From 21cb7cb7b73437904628f76530e4975e7fd1ad48 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Mon, 15 Apr 2013 15:49:17 -0400 Subject: [PATCH] OpenAL support via OpenTK. --- README | 3 + SDL2#.csproj | 47 + SDL2#.dll.config | 4 + opentk.LICENSE | 21 + src/MiniTK/Audio/AudioCapture.cs | 415 +++++ src/MiniTK/Audio/AudioContext.cs | 770 ++++++++ src/MiniTK/Audio/AudioContextException.cs | 44 + src/MiniTK/Audio/AudioDeviceEnumerator.cs | 218 +++ src/MiniTK/Audio/AudioDeviceErrorChecker.cs | 85 + src/MiniTK/Audio/AudioDeviceException.cs | 44 + src/MiniTK/Audio/AudioException.cs | 44 + src/MiniTK/Audio/AudioValueException.cs | 43 + src/MiniTK/Audio/OpenAL/AL/AL.cs | 1658 +++++++++++++++++ src/MiniTK/Audio/OpenAL/AL/ALEnums.cs | 431 +++++ .../Audio/OpenAL/AL/EffectsExtension.cs | 1293 +++++++++++++ .../Audio/OpenAL/AL/EffectsExtensionEnums.cs | 480 +++++ .../OpenAL/AL/EffectsExtensionPresets.cs | 374 ++++ src/MiniTK/Audio/OpenAL/AL/XRamExtension.cs | 208 +++ src/MiniTK/Audio/OpenAL/Alc/Alc.cs | 448 +++++ src/MiniTK/Audio/OpenAL/Alc/AlcEnums.cs | 135 ++ src/MiniTK/BlittableValueType.cs | 291 +++ src/MiniTK/ContextHandle.cs | 177 ++ src/MiniTK/Math/BezierCurve.cs | 261 +++ src/MiniTK/Math/BezierCurveCubic.cs | 163 ++ src/MiniTK/Math/BezierCurveQuadric.cs | 151 ++ src/MiniTK/Math/Box2.cs | 99 + src/MiniTK/Math/Functions.cs | 371 ++++ src/MiniTK/Math/Half.cs | 588 ++++++ src/MiniTK/Math/MathHelper.cs | 293 +++ src/MiniTK/Math/Matrix3d.cs | 828 ++++++++ src/MiniTK/Math/Matrix4.cs | 1229 ++++++++++++ src/MiniTK/Math/Matrix4d.cs | 1223 ++++++++++++ src/MiniTK/Math/Point.cs | 235 +++ src/MiniTK/Math/Quaternion.cs | 705 +++++++ src/MiniTK/Math/Quaterniond.cs | 1330 +++++++++++++ src/MiniTK/Math/Rectangle.cs | 323 ++++ src/MiniTK/Math/Size.cs | 222 +++ src/MiniTK/Math/Vector2.cs | 1107 +++++++++++ src/MiniTK/Math/Vector2d.cs | 1010 ++++++++++ src/MiniTK/Math/Vector2h.cs | 362 ++++ src/MiniTK/Math/Vector3.cs | 1387 ++++++++++++++ src/MiniTK/Math/Vector3d.cs | 1400 ++++++++++++++ src/MiniTK/Math/Vector3h.cs | 409 ++++ src/MiniTK/Math/Vector4.cs | 1220 ++++++++++++ src/MiniTK/Math/Vector4d.cs | 1238 ++++++++++++ src/MiniTK/Math/Vector4h.cs | 444 +++++ 46 files changed, 23831 insertions(+) create mode 100644 opentk.LICENSE create mode 100644 src/MiniTK/Audio/AudioCapture.cs create mode 100644 src/MiniTK/Audio/AudioContext.cs create mode 100644 src/MiniTK/Audio/AudioContextException.cs create mode 100644 src/MiniTK/Audio/AudioDeviceEnumerator.cs create mode 100644 src/MiniTK/Audio/AudioDeviceErrorChecker.cs create mode 100644 src/MiniTK/Audio/AudioDeviceException.cs create mode 100644 src/MiniTK/Audio/AudioException.cs create mode 100644 src/MiniTK/Audio/AudioValueException.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/AL.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/ALEnums.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/EffectsExtension.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/EffectsExtensionEnums.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/EffectsExtensionPresets.cs create mode 100644 src/MiniTK/Audio/OpenAL/AL/XRamExtension.cs create mode 100644 src/MiniTK/Audio/OpenAL/Alc/Alc.cs create mode 100644 src/MiniTK/Audio/OpenAL/Alc/AlcEnums.cs create mode 100644 src/MiniTK/BlittableValueType.cs create mode 100644 src/MiniTK/ContextHandle.cs create mode 100644 src/MiniTK/Math/BezierCurve.cs create mode 100644 src/MiniTK/Math/BezierCurveCubic.cs create mode 100644 src/MiniTK/Math/BezierCurveQuadric.cs create mode 100644 src/MiniTK/Math/Box2.cs create mode 100644 src/MiniTK/Math/Functions.cs create mode 100644 src/MiniTK/Math/Half.cs create mode 100644 src/MiniTK/Math/MathHelper.cs create mode 100644 src/MiniTK/Math/Matrix3d.cs create mode 100644 src/MiniTK/Math/Matrix4.cs create mode 100644 src/MiniTK/Math/Matrix4d.cs create mode 100644 src/MiniTK/Math/Point.cs create mode 100644 src/MiniTK/Math/Quaternion.cs create mode 100644 src/MiniTK/Math/Quaterniond.cs create mode 100644 src/MiniTK/Math/Rectangle.cs create mode 100644 src/MiniTK/Math/Size.cs create mode 100644 src/MiniTK/Math/Vector2.cs create mode 100644 src/MiniTK/Math/Vector2d.cs create mode 100644 src/MiniTK/Math/Vector2h.cs create mode 100644 src/MiniTK/Math/Vector3.cs create mode 100644 src/MiniTK/Math/Vector3d.cs create mode 100644 src/MiniTK/Math/Vector3h.cs create mode 100644 src/MiniTK/Math/Vector4.cs create mode 100644 src/MiniTK/Math/Vector4d.cs create mode 100644 src/MiniTK/Math/Vector4h.cs diff --git a/README b/README index 59e6998..c88d9da 100644 --- a/README +++ b/README @@ -6,6 +6,9 @@ License ------- SDL2 and SDL2# are released under the zlib license. See LICENSE for details. +SDL2# currently uses parts of OpenTK, which is released under the MIT license. +See opentk.LICENSE for details. + About SDL2 ---------- For more information about SDL2, visit the SDL wiki: diff --git a/SDL2#.csproj b/SDL2#.csproj index ce11098..665138c 100644 --- a/SDL2#.csproj +++ b/SDL2#.csproj @@ -38,6 +38,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -46,6 +88,7 @@ + @@ -56,4 +99,8 @@ + + + + diff --git a/SDL2#.dll.config b/SDL2#.dll.config index 6dfa40d..61d21e2 100644 --- a/SDL2#.dll.config +++ b/SDL2#.dll.config @@ -15,4 +15,8 @@ + + + + diff --git a/opentk.LICENSE b/opentk.LICENSE new file mode 100644 index 0000000..c848993 --- /dev/null +++ b/opentk.LICENSE @@ -0,0 +1,21 @@ +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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/src/MiniTK/Audio/AudioCapture.cs b/src/MiniTK/Audio/AudioCapture.cs new file mode 100644 index 0000000..d7af774 --- /dev/null +++ b/src/MiniTK/Audio/AudioCapture.cs @@ -0,0 +1,415 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using OpenTK.Audio.OpenAL; + +namespace OpenTK.Audio +{ + + /// + /// Provides methods to instantiate, use and destroy an audio device for recording. + /// Static methods are provided to list available devices known by the driver. + /// + public sealed class AudioCapture : IDisposable + { + #region Fields + + // This must stay private info so the end-user cannot call any Alc commands for the recording device. + IntPtr Handle; + + // Alc.CaptureStop should be called prior to device shutdown, this keeps track of Alc.CaptureStart/Stop calls. + bool _isrecording = false; + + ALFormat sample_format; + int sample_frequency; + + #endregion + + #region Constructors + + static AudioCapture() + { + if (AudioDeviceEnumerator.IsOpenALSupported) // forces enumeration + { + } + } + + /// + /// Opens the default device for audio recording. + /// Implicitly set parameters are: 22050Hz, 16Bit Mono, 4096 samples ringbuffer. + /// + public AudioCapture() + : this(AudioCapture.DefaultDevice, 22050, ALFormat.Mono16, 4096) + { + } + + /// Opens a device for audio recording. + /// The device name. + /// The frequency that the data should be captured at. + /// The requested capture buffer format. + /// The size of OpenAL's capture internal ring-buffer. This value expects number of samples, not bytes. + public AudioCapture(string deviceName, int frequency, ALFormat sampleFormat, int bufferSize) + { + if (!AudioDeviceEnumerator.IsOpenALSupported) + throw new DllNotFoundException("openal32.dll"); + if (frequency <= 0) + throw new ArgumentOutOfRangeException("frequency"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + + // Try to open specified device. If it fails, try to open default device. + device_name = deviceName; + Handle = Alc.CaptureOpenDevice(deviceName, frequency, sampleFormat, bufferSize); + + if (Handle == IntPtr.Zero) + { + Debug.WriteLine(ErrorMessage(deviceName, frequency, sampleFormat, bufferSize)); + device_name = "IntPtr.Zero"; + Handle = Alc.CaptureOpenDevice(null, frequency, sampleFormat, bufferSize); + } + + if (Handle == IntPtr.Zero) + { + Debug.WriteLine(ErrorMessage("IntPtr.Zero", frequency, sampleFormat, bufferSize)); + device_name = AudioDeviceEnumerator.DefaultRecordingDevice; + Handle = Alc.CaptureOpenDevice(AudioDeviceEnumerator.DefaultRecordingDevice, frequency, sampleFormat, bufferSize); + } + + if (Handle == IntPtr.Zero) + { + // Everything we tried failed. Capture may not be supported, bail out. + Debug.WriteLine(ErrorMessage(AudioDeviceEnumerator.DefaultRecordingDevice, frequency, sampleFormat, bufferSize)); + device_name = "None"; + + throw new AudioDeviceException("All attempts to open capture devices returned IntPtr.Zero. See debug log for verbose list."); + } + + // handle is not null, check for some Alc Error + CheckErrors(); + + SampleFormat = sampleFormat; + SampleFrequency = frequency; + } + + #endregion Constructor + + #region Public Members + + #region CurrentDevice + + private string device_name; + + /// + /// The name of the device associated with this instance. + /// + public string CurrentDevice + { + get + { + return device_name; + } + } + + #endregion + + #region AvailableDevices + + /// + /// Returns a list of strings containing all known recording devices. + /// + public static IList AvailableDevices + { + get + { + return AudioDeviceEnumerator.AvailableRecordingDevices; + } + } + + #endregion + + #region DefaultDevice + + /// + /// Returns the name of the device that will be used as recording default. + /// + public static string DefaultDevice + { + get + { + return AudioDeviceEnumerator.DefaultRecordingDevice; + } + } + + #endregion + + #region CheckErrors + + /// + /// Checks for ALC error conditions. + /// + /// Raised when an out of memory error is detected. + /// Raised when an invalid value is detected. + /// Raised when an invalid device is detected. + /// Raised when an invalid context is detected. + public void CheckErrors() + { + new AudioDeviceErrorChecker(Handle).Dispose(); + } + + #endregion + + #region CurrentError + + /// Returns the ALC error code for this device. + public AlcError CurrentError + { + get + { + return Alc.GetError(Handle); + } + } + + #endregion + + #region Start & Stop + + /// + /// Start recording samples. + /// The number of available samples can be obtained through the property. + /// The data can be queried with any method. + /// + public void Start() + { + Alc.CaptureStart(Handle); + _isrecording = true; + } + + /// Stop recording samples. This will not clear previously recorded samples. + public void Stop() + { + Alc.CaptureStop(Handle); + _isrecording = false; + } + + #endregion Start & Stop Capture + + #region AvailableSamples + + /// Returns the number of available samples for capture. + public int AvailableSamples + { + get + { + // TODO: Investigate inconsistency between documentation and actual usage. + // Doc claims the 3rd param is Number-of-Bytes, but it appears to be Number-of-Int32s + int result; + Alc.GetInteger(Handle, AlcGetInteger.CaptureSamples, 1, out result); + return result; + } + } + + #endregion Available samples property + + #region ReadSamples + + /// Fills the specified buffer with samples from the internal capture ring-buffer. This method does not block: it is an error to specify a sampleCount larger than AvailableSamples. + /// A pointer to a previously initialized and pinned array. + /// The number of samples to be written to the buffer. + public void ReadSamples(IntPtr buffer, int sampleCount) + { + Alc.CaptureSamples(Handle, buffer, sampleCount); + } + + /// Fills the specified buffer with samples from the internal capture ring-buffer. This method does not block: it is an error to specify a sampleCount larger than AvailableSamples. + /// The buffer to fill. + /// The number of samples to be written to the buffer. + /// Raised when buffer is null. + /// Raised when sampleCount is larger than the buffer. + public void ReadSamples(TBuffer[] buffer, int sampleCount) + where TBuffer : struct + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + + int buffer_size = BlittableValueType.Stride * buffer.Length; + // This is more of a heuristic than a 100% valid check. However, it will work + // correctly for 99.9% of all use cases. + // This should never produce a false positive, but a false negative might + // be produced with compressed sample formats (which are very rare). + // Still, this is better than no check at all. + if (sampleCount * GetSampleSize(SampleFormat) > buffer_size) + throw new ArgumentOutOfRangeException("sampleCount"); + + GCHandle buffer_ptr = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try { ReadSamples(buffer_ptr.AddrOfPinnedObject(), sampleCount); } + finally { buffer_ptr.Free(); } + } + + #endregion + + #region SampleFormat & SampleFrequency + + /// + /// Gets the OpenTK.Audio.ALFormat for this instance. + /// + public ALFormat SampleFormat + { + get { return sample_format; } + private set { sample_format = value; } + } + + /// + /// Gets the sampling rate for this instance. + /// + public int SampleFrequency + { + get { return sample_frequency; } + private set { sample_frequency = value; } + } + + #endregion + + #region IsRunning + + /// + /// Gets a value indicating whether this instance is currently capturing samples. + /// + public bool IsRunning + { + get { return _isrecording; } + } + + #endregion + + #endregion + + #region Private Members + + // Retrieves the sample size in bytes for various ALFormats. + // Compressed formats always return 1. + static int GetSampleSize(ALFormat format) + { + switch (format) + { + case ALFormat.Mono8: return 1; + case ALFormat.Mono16: return 2; + case ALFormat.Stereo8: return 2; + case ALFormat.Stereo16: return 4; + case ALFormat.MonoFloat32Ext: return 4; + case ALFormat.MonoDoubleExt: return 8; + case ALFormat.StereoFloat32Ext: return 8; + case ALFormat.StereoDoubleExt: return 16; + + case ALFormat.MultiQuad8Ext: return 4; + case ALFormat.MultiQuad16Ext: return 8; + case ALFormat.MultiQuad32Ext: return 16; + + case ALFormat.Multi51Chn8Ext: return 6; + case ALFormat.Multi51Chn16Ext: return 12; + case ALFormat.Multi51Chn32Ext: return 24; + + case ALFormat.Multi61Chn8Ext: return 7; + case ALFormat.Multi71Chn16Ext: return 14; + case ALFormat.Multi71Chn32Ext: return 28; + + case ALFormat.MultiRear8Ext: return 1; + case ALFormat.MultiRear16Ext: return 2; + case ALFormat.MultiRear32Ext: return 4; + + default: return 1; // Unknown sample size. + } + } + + // Converts an error code to an error string with additional information. + string ErrorMessage(string devicename, int frequency, ALFormat bufferformat, int buffersize) + { + string alcerrmsg; + AlcError alcerrcode = CurrentError; + switch (alcerrcode) + { + case AlcError.OutOfMemory: + alcerrmsg = alcerrcode.ToString() + ": The specified device is invalid, or can not capture audio."; + break; + case AlcError.InvalidValue: + alcerrmsg = alcerrcode.ToString() + ": One of the parameters has an invalid value."; + break; + default: + alcerrmsg = alcerrcode.ToString(); + break; + } + return "The handle returned by Alc.CaptureOpenDevice is null." + + "\nAlc Error: " + alcerrmsg + + "\nDevice Name: " + devicename + + "\nCapture frequency: " + frequency + + "\nBuffer format: " + bufferformat + + "\nBuffer Size: " + buffersize; + } + + #endregion + + #region IDisposable Members + + /// + /// Finalizes this instance. + /// + ~AudioCapture() + { + Dispose(); + } + + private bool IsDisposed; + + /// Closes the device and disposes the instance. + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!this.IsDisposed) + { + if (this.Handle != IntPtr.Zero) + { + if (this._isrecording) + this.Stop(); + + Alc.CaptureCloseDevice(this.Handle); + } + this.IsDisposed = true; + } + } + + #endregion Destructor + } +} diff --git a/src/MiniTK/Audio/AudioContext.cs b/src/MiniTK/Audio/AudioContext.cs new file mode 100644 index 0000000..9495d08 --- /dev/null +++ b/src/MiniTK/Audio/AudioContext.cs @@ -0,0 +1,770 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +using OpenTK.Audio.OpenAL; + +namespace OpenTK.Audio +{ + /// + /// Provides methods to instantiate, use and destroy an audio context for playback. + /// Static methods are provided to list available devices known by the driver. + /// + public sealed class AudioContext : IDisposable + { + #region --- Fields --- + + bool disposed; + bool is_processing, is_synchronized; + IntPtr device_handle; + ContextHandle context_handle; + bool context_exists; + + string device_name; + static object audio_context_lock = new object(); + static Dictionary available_contexts = new Dictionary(); + + #endregion + + #region --- Constructors --- + + #region static AudioContext() + + /// \internal + /// + /// Runs before the actual class constructor, to load available devices. + /// + static AudioContext() + { + if (AudioDeviceEnumerator.IsOpenALSupported) // forces enumeration + { } + } + + #endregion static AudioContext() + + #region public AudioContext() + + /// Constructs a new AudioContext, using the default audio device. + public AudioContext() + : this(null, 0, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { } + + #endregion + + #region public AudioContext(string device) + + /// + /// Constructs a new AudioContext instance. + /// + /// The device name that will host this instance. + public AudioContext(string device) : this(device, 0, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { } + + #endregion + + #region public AudioContext(string device, int freq) + + /// Constructs a new AudioContext, using the specified audio device and device parameters. + /// The name of the audio device to use. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// + /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices. + /// devices. + /// + public AudioContext(string device, int freq) : this(device, freq, 0, false, true, MaxAuxiliarySends.UseDriverDefault) { } + + #endregion + + #region public AudioContext(string device, int freq, int refresh) + + /// Constructs a new AudioContext, using the specified audio device and device parameters. + /// The name of the audio device to use. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// Refresh intervals, in units of Hz. Pass 0 for driver default. + /// + /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices. + /// devices. + /// + public AudioContext(string device, int freq, int refresh) + : this(device, freq, refresh, false, true, MaxAuxiliarySends.UseDriverDefault) { } + + #endregion + + #region public AudioContext(string device, int freq, int refresh, bool sync) + + /// Constructs a new AudioContext, using the specified audio device and device parameters. + /// The name of the audio device to use. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// Refresh intervals, in units of Hz. Pass 0 for driver default. + /// Flag, indicating a synchronous context. + /// + /// Use AudioContext.AvailableDevices to obtain a list of all available audio devices. + /// devices. + /// + public AudioContext(string device, int freq, int refresh, bool sync) + : this(AudioDeviceEnumerator.AvailablePlaybackDevices[0], freq, refresh, sync, true) { } + + #endregion + + #region public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx) + + /// Creates the audio context using the specified device and device parameters. + /// The device descriptor obtained through AudioContext.AvailableDevices. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// Refresh intervals, in units of Hz. Pass 0 for driver default. + /// Flag, indicating a synchronous context. + /// Indicates whether the EFX extension should be initialized, if present. + /// Occurs when the device string is invalid. + /// Occurs when a specified parameter is invalid. + /// + /// Occurs when the specified device is not available, or is in use by another program. + /// + /// + /// Occurs when an audio context could not be created with the specified parameters. + /// + /// + /// Occurs when an AudioContext already exists. + /// + /// For maximum compatibility, you are strongly recommended to use the default constructor. + /// Multiple AudioContexts are not supported at this point. + /// + /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well + /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends. + /// Values higher than supported will be clamped by the driver. + /// + /// + public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx) + { + CreateContext(device, freq, refresh, sync, enableEfx, MaxAuxiliarySends.UseDriverDefault); + } + + #endregion + + #region public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxMaxAuxSends) + + /// Creates the audio context using the specified device and device parameters. + /// The device descriptor obtained through AudioContext.AvailableDevices. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// Refresh intervals, in units of Hz. Pass 0 for driver default. + /// Flag, indicating a synchronous context. + /// Indicates whether the EFX extension should be initialized, if present. + /// Requires EFX enabled. The number of desired Auxiliary Sends per source. + /// Occurs when the device string is invalid. + /// Occurs when a specified parameter is invalid. + /// + /// Occurs when the specified device is not available, or is in use by another program. + /// + /// + /// Occurs when an audio context could not be created with the specified parameters. + /// + /// + /// Occurs when an AudioContext already exists. + /// + /// For maximum compatibility, you are strongly recommended to use the default constructor. + /// Multiple AudioContexts are not supported at this point. + /// + /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well + /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends. + /// Values higher than supported will be clamped by the driver. + /// + /// + public AudioContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxMaxAuxSends) + { + CreateContext(device, freq, refresh, sync, enableEfx, efxMaxAuxSends); + } + + #endregion + + #endregion --- Constructors --- + + #region --- Private Methods --- + + #region CreateContext + + /// May be passed at context construction time to indicate the number of desired auxiliary effect slot sends per source. + public enum MaxAuxiliarySends:int + { + /// Will chose a reliably working parameter. + UseDriverDefault = 0, + /// One send per source. + One = 1, + /// Two sends per source. + Two = 2, + /// Three sends per source. + Three = 3, + /// Four sends per source. + Four = 4, + } + + /// \internal + /// Creates the audio context using the specified device. + /// The device descriptor obtained through AudioContext.AvailableDevices, or null for the default device. + /// Frequency for mixing output buffer, in units of Hz. Pass 0 for driver default. + /// Refresh intervals, in units of Hz. Pass 0 for driver default. + /// Flag, indicating a synchronous context. + /// Indicates whether the EFX extension should be initialized, if present. + /// Requires EFX enabled. The number of desired Auxiliary Sends per source. + /// Occurs when a specified parameter is invalid. + /// + /// Occurs when the specified device is not available, or is in use by another program. + /// + /// + /// Occurs when an audio context could not be created with the specified parameters. + /// + /// + /// Occurs when an AudioContext already exists. + /// + /// For maximum compatibility, you are strongly recommended to use the default constructor. + /// Multiple AudioContexts are not supported at this point. + /// + /// The number of auxilliary EFX sends depends on the audio hardware and drivers. Most Realtek devices, as well + /// as the Creative SB Live!, support 1 auxilliary send. Creative's Audigy and X-Fi series support 4 sends. + /// Values higher than supported will be clamped by the driver. + /// + /// + void CreateContext(string device, int freq, int refresh, bool sync, bool enableEfx, MaxAuxiliarySends efxAuxiliarySends) + { + if (!AudioDeviceEnumerator.IsOpenALSupported) + throw new DllNotFoundException("openal32.dll"); + + if (AudioDeviceEnumerator.Version == AudioDeviceEnumerator.AlcVersion.Alc1_1 && AudioDeviceEnumerator.AvailablePlaybackDevices.Count == 0) // Alc 1.0 does not support device enumeration. + throw new NotSupportedException("No audio hardware is available."); + if (context_exists) throw new NotSupportedException("Multiple AudioContexts are not supported."); + if (freq < 0) throw new ArgumentOutOfRangeException("freq", freq, "Should be greater than zero."); + if (refresh < 0) throw new ArgumentOutOfRangeException("refresh", refresh, "Should be greater than zero."); + + + if (!String.IsNullOrEmpty(device)) + { + device_name = device; + device_handle = Alc.OpenDevice(device); // try to open device by name + } + if (device_handle == IntPtr.Zero) + { + device_name = "IntPtr.Zero (null string)"; + device_handle = Alc.OpenDevice(null); // try to open unnamed default device + } + if (device_handle == IntPtr.Zero) + { + device_name = AudioContext.DefaultDevice; + device_handle = Alc.OpenDevice(AudioContext.DefaultDevice); // try to open named default device + } + if (device_handle == IntPtr.Zero) + { + device_name = "None"; + throw new AudioDeviceException(String.Format("Audio device '{0}' does not exist or is tied up by another application.", + String.IsNullOrEmpty(device) ? "default" : device)); + } + + CheckErrors(); + + // Build the attribute list + List attributes = new List(); + + if (freq != 0) + { + attributes.Add((int)AlcContextAttributes.Frequency); + attributes.Add(freq); + } + + if (refresh != 0) + { + attributes.Add((int)AlcContextAttributes.Refresh); + attributes.Add(refresh); + } + + attributes.Add((int)AlcContextAttributes.Sync); + attributes.Add(sync ? 1 : 0); + + if (enableEfx && Alc.IsExtensionPresent(device_handle, "ALC_EXT_EFX")) + { + int num_slots; + switch (efxAuxiliarySends) + { + case MaxAuxiliarySends.One: + case MaxAuxiliarySends.Two: + case MaxAuxiliarySends.Three: + case MaxAuxiliarySends.Four: + num_slots = (int)efxAuxiliarySends; + break; + default: + case MaxAuxiliarySends.UseDriverDefault: + Alc.GetInteger(device_handle, AlcGetInteger.EfxMaxAuxiliarySends, 1, out num_slots); + break; + } + + attributes.Add((int)AlcContextAttributes.EfxMaxAuxiliarySends); + attributes.Add(num_slots); + } + attributes.Add(0); + + context_handle = Alc.CreateContext(device_handle, attributes.ToArray()); + + if (context_handle == ContextHandle.Zero) + { + Alc.CloseDevice(device_handle); + throw new AudioContextException("The audio context could not be created with the specified parameters."); + } + + CheckErrors(); + + // HACK: OpenAL SI on Linux/ALSA crashes on MakeCurrent. This hack avoids calling MakeCurrent when + // an old OpenAL version is detect - it may affect outdated OpenAL versions different than OpenAL SI, + // but it looks like a good compromise for now. + if (AudioDeviceEnumerator.AvailablePlaybackDevices.Count > 0) + MakeCurrent(); + + CheckErrors(); + + device_name = Alc.GetString(device_handle, AlcGetString.DeviceSpecifier); + + + lock (audio_context_lock) + { + available_contexts.Add(this.context_handle, this); + context_exists = true; + } + } + + #endregion --- Private Methods --- + + #region static void MakeCurrent(AudioContext context) + + /// \internal + /// Makes the specified AudioContext current in the calling thread. + /// The OpenTK.Audio.AudioContext to make current, or null. + /// + /// Occurs if this function is called after the AudioContext has been disposed. + /// + /// + /// Occurs when the AudioContext could not be made current. + /// + static void MakeCurrent(AudioContext context) + { + lock (audio_context_lock) + { + if (!Alc.MakeContextCurrent(context != null ? context.context_handle : ContextHandle.Zero)) + throw new AudioContextException(String.Format("ALC {0} error detected at {1}.", + Alc.GetError(context != null ? (IntPtr)context.context_handle : IntPtr.Zero).ToString(), + context != null ? context.ToString() : "null")); + } + } + + #endregion + + #region internal bool IsCurrent + + /// + /// Gets or sets a System.Boolean indicating whether the AudioContext + /// is current. + /// + /// + /// Only one AudioContext can be current in the application at any time, + /// regardless of the number of threads. + /// + internal bool IsCurrent + { + get + { + lock (audio_context_lock) + { + if (available_contexts.Count == 0) + return false; + else + { + return AudioContext.CurrentContext == this; + } + } + } + set + { + if (value) AudioContext.MakeCurrent(this); + else AudioContext.MakeCurrent(null); + } + } + + #endregion + + #region IntPtr Device + + IntPtr Device { get { return device_handle; } } + + #endregion + + #endregion + + #region --- Public Members --- + + #region CheckErrors + + /// + /// Checks for ALC error conditions. + /// + /// Raised when an out of memory error is detected. + /// Raised when an invalid value is detected. + /// Raised when an invalid device is detected. + /// Raised when an invalid context is detected. + public void CheckErrors() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + new AudioDeviceErrorChecker(device_handle).Dispose(); + } + + #endregion + + #region CurrentError + + /// + /// Returns the ALC error code for this instance. + /// + public AlcError CurrentError + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + return Alc.GetError(device_handle); + } + } + + #endregion + + #region MakeCurrent + + /// Makes the AudioContext current in the calling thread. + /// + /// Occurs if this function is called after the AudioContext has been disposed. + /// + /// + /// Occurs when the AudioContext could not be made current. + /// + /// + /// Only one AudioContext can be current in the application at any time, + /// regardless of the number of threads. + /// + public void MakeCurrent() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + AudioContext.MakeCurrent(this); + } + + #endregion + + #region IsProcessing + + /// + /// Gets a System.Boolean indicating whether the AudioContext is + /// currently processing audio events. + /// + /// + /// + public bool IsProcessing + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + return is_processing; + } + private set { is_processing = value; } + } + + #endregion + + #region IsSynchronized + + /// + /// Gets a System.Boolean indicating whether the AudioContext is + /// synchronized. + /// + /// + public bool IsSynchronized + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + return is_synchronized; + } + private set { is_synchronized = value; } + } + + #endregion + + #region public void Process + + /// + /// Processes queued audio events. + /// + /// + /// + /// If AudioContext.IsSynchronized is true, this function will resume + /// the internal audio processing thread. If AudioContext.IsSynchronized is false, + /// you will need to call this function multiple times per second to process + /// audio events. + /// + /// + /// In some implementations this function may have no effect. + /// + /// + /// Occurs when this function is called after the AudioContext had been disposed. + /// + /// + /// + public void Process() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + Alc.ProcessContext(this.context_handle); + IsProcessing = true; + } + + #endregion + + #region public void Suspend + + /// + /// Suspends processing of audio events. + /// + /// + /// + /// To avoid audio artifacts when calling this function, set audio gain to zero before + /// suspending an AudioContext. + /// + /// + /// In some implementations, it can be faster to suspend processing before changing + /// AudioContext state. + /// + /// + /// In some implementations this function may have no effect. + /// + /// + /// Occurs when this function is called after the AudioContext had been disposed. + /// + /// + /// + public void Suspend() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + Alc.SuspendContext(this.context_handle); + IsProcessing = false; + } + + #endregion + + #region public bool SupportsExtension(string extension) + + /// + /// Checks whether the specified OpenAL extension is supported. + /// + /// The name of the extension to check (e.g. "ALC_EXT_EFX"). + /// true if the extension is supported; false otherwise. + public bool SupportsExtension(string extension) + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + return Alc.IsExtensionPresent(this.Device, extension); + } + + #endregion + + #region CurrentDevice + + /// + /// Gets a System.String with the name of the device used in this context. + /// + public string CurrentDevice + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().FullName); + + return device_name; + } + } + + #endregion + + #endregion --- Public Members --- + + #region --- Static Members --- + + #region public static AudioContext CurrentContext + + /// + /// Gets the OpenTK.Audio.AudioContext which is current in the application. + /// + /// + /// Only one AudioContext can be current in the application at any time, + /// regardless of the number of threads. + /// + public static AudioContext CurrentContext + { + get + { + lock (audio_context_lock) + { + if (available_contexts.Count == 0) + return null; + else + { + AudioContext context; + AudioContext.available_contexts.TryGetValue( + (ContextHandle)Alc.GetCurrentContext(), + out context); + return context; + } + } + } + } + + #endregion + + #region AvailableDevices + + /// + /// Returns a list of strings containing all known playback devices. + /// + public static IList AvailableDevices + { + get + { + return AudioDeviceEnumerator.AvailablePlaybackDevices; + } + } + #endregion public static IList AvailablePlaybackDevices + + #region DefaultDevice + + /// + /// Returns the name of the device that will be used as playback default. + /// + public static string DefaultDevice + { + get + { + return AudioDeviceEnumerator.DefaultPlaybackDevice; + } + } + + #endregion + + #endregion + + #region --- IDisposable Members --- + + /// + /// Disposes of the AudioContext, cleaning up all resources consumed by it. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (this.IsCurrent) + this.IsCurrent = false; + + if (context_handle != ContextHandle.Zero) + { + available_contexts.Remove(context_handle); + Alc.DestroyContext(context_handle); + } + + if (device_handle != IntPtr.Zero) + Alc.CloseDevice(device_handle); + + if (manual) + { + } + disposed = true; + } + } + + /// + /// Finalizes this instance. + /// + ~AudioContext() + { + this.Dispose(false); + } + + #endregion + + #region --- Overrides --- + + /// + /// Calculates the hash code for this instance. + /// + /// + public override int GetHashCode() + { + return base.GetHashCode(); + } + + /// + /// Compares this instance with another. + /// + /// The instance to compare to. + /// True, if obj refers to this instance; false otherwise. + public override bool Equals(object obj) + { + return base.Equals(obj); + } + + /// + /// Returns a that desrcibes this instance. + /// + /// A that desrcibes this instance. + public override string ToString() + { + return String.Format("{0} (handle: {1}, device: {2})", + this.device_name, this.context_handle, this.device_handle); + } + + #endregion + } +} diff --git a/src/MiniTK/Audio/AudioContextException.cs b/src/MiniTK/Audio/AudioContextException.cs new file mode 100644 index 0000000..af0b90a --- /dev/null +++ b/src/MiniTK/Audio/AudioContextException.cs @@ -0,0 +1,44 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Audio +{ + /// Represents exceptions related to an OpenTK.Audio.AudioContext. + public class AudioContextException : AudioException + { + /// Constructs a new AudioContextException. + public AudioContextException() : base() { } + /// Constructs a new AudioContextException with the specified error message. + /// The error message of the AudioContextException. + public AudioContextException(string message) : base(message) { } + } +} diff --git a/src/MiniTK/Audio/AudioDeviceEnumerator.cs b/src/MiniTK/Audio/AudioDeviceEnumerator.cs new file mode 100644 index 0000000..6b3f741 --- /dev/null +++ b/src/MiniTK/Audio/AudioDeviceEnumerator.cs @@ -0,0 +1,218 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; + +using OpenTK.Audio.OpenAL; + +namespace OpenTK.Audio +{ + internal static class AudioDeviceEnumerator + { + #region All device strings + + private static readonly List available_playback_devices = new List(); + private static readonly List available_recording_devices = new List(); + + internal static IList AvailablePlaybackDevices + { + get + { + return available_playback_devices.AsReadOnly(); + } + } + internal static IList AvailableRecordingDevices + { + get + { + return available_recording_devices.AsReadOnly(); + } + } + + #endregion All device strings + + #region Default device strings + + private static string default_playback_device; + internal static string DefaultPlaybackDevice + { + get + { + return default_playback_device; + } + } + + private static string default_recording_device; + internal static string DefaultRecordingDevice + { + get + { + return default_recording_device; + } + } + + #endregion Default device strings + + #region Is OpenAL supported? + + private static bool openal_supported = true; + internal static bool IsOpenALSupported + { + get + { + return openal_supported; + } + } + + #endregion Is OpenAL supported? + + #region Alc Version number + + internal enum AlcVersion + { + Alc1_0, + Alc1_1 + } + + private static AlcVersion version; + internal static AlcVersion Version + { + get + { + return version; + } + } + + #endregion Alc Version number + + #region Constructors + + // Loads all available audio devices into the available_*_devices lists. + static AudioDeviceEnumerator() + { + IntPtr dummy_device = IntPtr.Zero; + ContextHandle dummy_context = ContextHandle.Zero; + + try + { + Debug.WriteLine("Enumerating audio devices."); + Debug.Indent(); + + // need a dummy context for correct results + dummy_device = Alc.OpenDevice(null); + dummy_context = Alc.CreateContext(dummy_device, (int[])null); + bool dummy_success = Alc.MakeContextCurrent(dummy_context); + AlcError dummy_error = Alc.GetError(dummy_device); + if (!dummy_success || dummy_error != AlcError.NoError) + { + throw new AudioContextException("Failed to create dummy Context. Device (" + dummy_device.ToString() + + ") Context (" + dummy_context.Handle.ToString() + + ") MakeContextCurrent " + (dummy_success ? "succeeded" : "failed") + + ", Alc Error (" + dummy_error.ToString() + ") " + Alc.GetString(IntPtr.Zero, (AlcGetString)dummy_error)); + } + + // Get a list of all known playback devices, using best extension available + if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATION_EXT")) + { + version = AlcVersion.Alc1_1; + if (Alc.IsExtensionPresent(IntPtr.Zero, "ALC_ENUMERATE_ALL_EXT")) + { + available_playback_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.AllDevicesSpecifier)); + default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultAllDevicesSpecifier); + } + else + { + available_playback_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.DeviceSpecifier)); + default_playback_device = Alc.GetString(IntPtr.Zero, AlcGetString.DefaultDeviceSpecifier); + } + } + else + { + version = AlcVersion.Alc1_0; + Debug.Print("Device enumeration extension not available. Failed to enumerate playback devices."); + } + AlcError playback_err = Alc.GetError(dummy_device); + if (playback_err != AlcError.NoError) + throw new AudioContextException("Alc Error occured when querying available playback devices. " + playback_err.ToString()); + + // Get a list of all known recording devices, at least ALC_ENUMERATION_EXT is needed too + if (version == AlcVersion.Alc1_1 && Alc.IsExtensionPresent(IntPtr.Zero, "ALC_EXT_CAPTURE")) + { + available_recording_devices.AddRange(Alc.GetString(IntPtr.Zero, AlcGetStringList.CaptureDeviceSpecifier)); + default_recording_device = Alc.GetString(IntPtr.Zero, AlcGetString.CaptureDefaultDeviceSpecifier); + } + else + { + Debug.Print("Capture extension not available. Failed to enumerate recording devices."); + } + AlcError record_err = Alc.GetError(dummy_device); + if (record_err != AlcError.NoError) + throw new AudioContextException("Alc Error occured when querying available recording devices. " + record_err.ToString()); + +#if DEBUG + Debug.WriteLine("Found playback devices:"); + foreach (string s in available_playback_devices) + Debug.WriteLine(s); + + Debug.WriteLine("Default playback device: " + default_playback_device); + + Debug.WriteLine("Found recording devices:"); + foreach (string s in available_recording_devices) + Debug.WriteLine(s); + + Debug.WriteLine("Default recording device: " + default_recording_device); +#endif + } + catch (DllNotFoundException e) + { + Trace.WriteLine(e.ToString()); + openal_supported = false; + } + catch (AudioContextException ace) + { + Trace.WriteLine(ace.ToString()); + openal_supported = false; + } + finally + { + Debug.Unindent(); + + // clean up the dummy context + Alc.MakeContextCurrent(ContextHandle.Zero); + if (dummy_context != ContextHandle.Zero && dummy_context.Handle != IntPtr.Zero) + Alc.DestroyContext(dummy_context); + if (dummy_device != IntPtr.Zero) + Alc.CloseDevice(dummy_device); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/MiniTK/Audio/AudioDeviceErrorChecker.cs b/src/MiniTK/Audio/AudioDeviceErrorChecker.cs new file mode 100644 index 0000000..939751c --- /dev/null +++ b/src/MiniTK/Audio/AudioDeviceErrorChecker.cs @@ -0,0 +1,85 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +using OpenTK.Audio.OpenAL; + +namespace OpenTK.Audio +{ + struct AudioDeviceErrorChecker : IDisposable + { + #region Fields + + readonly IntPtr Device; + static readonly string ErrorString = "Device {0} reported {1}."; + + #endregion + + #region Constructors + + public AudioDeviceErrorChecker(IntPtr device) + { + if (device == IntPtr.Zero) + throw new AudioDeviceException(); + + Device = device; + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + AlcError err = Alc.GetError(Device); + switch (err) + { + case AlcError.OutOfMemory: + throw new OutOfMemoryException(String.Format(ErrorString, Device, err)); + + case AlcError.InvalidValue: + throw new AudioValueException(String.Format(ErrorString, Device, err)); + + case AlcError.InvalidDevice: + throw new AudioDeviceException(String.Format(ErrorString, Device, err)); + + case AlcError.InvalidContext: + throw new AudioContextException(String.Format(ErrorString, Device, err)); + + case AlcError.NoError: + default: + // everything went fine, do nothing + break; + } + } + + #endregion + } +} diff --git a/src/MiniTK/Audio/AudioDeviceException.cs b/src/MiniTK/Audio/AudioDeviceException.cs new file mode 100644 index 0000000..40c6431 --- /dev/null +++ b/src/MiniTK/Audio/AudioDeviceException.cs @@ -0,0 +1,44 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Audio +{ + /// Represents exceptions related to an OpenTK.Audio device. + public class AudioDeviceException : AudioException + { + /// Constructs a new AudioDeviceException. + public AudioDeviceException() : base() { } + /// Constructs a new AudioDeviceException with the specified error message. + /// The error message of the AudioDeviceException. + public AudioDeviceException(string message) : base(message) { } + } +} diff --git a/src/MiniTK/Audio/AudioException.cs b/src/MiniTK/Audio/AudioException.cs new file mode 100644 index 0000000..6fc7766 --- /dev/null +++ b/src/MiniTK/Audio/AudioException.cs @@ -0,0 +1,44 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Audio +{ + /// Represents exceptions related to the OpenTK.Audio subsystem. + public class AudioException : Exception + { + /// Constructs a new AudioException. + public AudioException() : base() { } + /// Constructs a new AudioException with the specified error message. + /// The error message of the AudioException. + public AudioException(string message) : base(message) { } + } +} diff --git a/src/MiniTK/Audio/AudioValueException.cs b/src/MiniTK/Audio/AudioValueException.cs new file mode 100644 index 0000000..cfda06a --- /dev/null +++ b/src/MiniTK/Audio/AudioValueException.cs @@ -0,0 +1,43 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Audio +{ + /// Represents exceptions related to invalid values. + public class AudioValueException : AudioException + { + /// Constructs a new instance. + public AudioValueException() : base() { } + /// Constructs a new instance with the specified error message. + /// The error message of the AudioContextException. + public AudioValueException(string message) : base(message) { } + } +} diff --git a/src/MiniTK/Audio/OpenAL/AL/AL.cs b/src/MiniTK/Audio/OpenAL/AL/AL.cs new file mode 100644 index 0000000..b8cc1e6 --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/AL.cs @@ -0,0 +1,1658 @@ +#region --- OpenTK.OpenAL License --- +/* AlFunctions.cs + * C header: \OpenAL 1.1 SDK\include\Al.h + * Spec: http://www.openal.org/openal_webstf/specs/OpenAL11Specification.pdf + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Security; + +using OpenTK; + +// flibit Added This!!! +#pragma warning disable 3021 + +/* Type Mapping +// 8-bit boolean +typedef char ALboolean; + * bool +// character +typedef char ALchar; + * byte +// signed 8-bit 2's complement integer +typedef char ALbyte; + * byte + +// unsigned 8-bit integer +typedef unsigned char ALubyte; + * byte + +// signed 16-bit 2's complement integer +typedef short ALshort; + * short + +// unsigned 16-bit integer +typedef unsigned short ALushort; + * ushort + +// unsigned 32-bit integer +typedef unsigned int ALuint; + * uint + +// signed 32-bit 2's complement integer +typedef int ALint; + * int +// non-negative 32-bit binary integer size +typedef int ALsizei; + * int +// enumerated 32-bit value +typedef int ALenum; + * int + +// 32-bit IEEE754 floating-point +typedef float ALfloat; + * float + +// 64-bit IEEE754 floating-point +typedef double ALdouble; + * double + +// void type (for opaque pointers only) +typedef void ALvoid; + * void +*/ + +namespace OpenTK.Audio.OpenAL +{ + /// + /// Provides access to the OpenAL 1.1 flat API. + /// + public static partial class AL + { + + #region Constants + + internal const string Lib = "openal32.dll"; + private const CallingConvention Style = CallingConvention.Cdecl; + + #endregion Constants + + #region Renderer State management + + /// This function enables a feature of the OpenAL driver. There are no capabilities defined in OpenAL 1.1 to be used with this function, but it may be used by an extension. + /// The name of a capability to enable. + [DllImport(AL.Lib, EntryPoint = "alEnable", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Enable(ALCapability capability); + //AL_API void AL_APIENTRY alEnable( ALenum capability ); + + /// This function disables a feature of the OpenAL driver. + /// The name of a capability to disable. + [DllImport(AL.Lib, EntryPoint = "alDisable", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Disable(ALCapability capability); + // AL_API void AL_APIENTRY alDisable( ALenum capability ); + + /// This function returns a boolean indicating if a specific feature is enabled in the OpenAL driver. + /// The name of a capability to enable. + /// True if enabled, False if disabled. + [DllImport(AL.Lib, EntryPoint = "alIsEnabled", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern bool IsEnabled(ALCapability capability); + // AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ); + + #endregion Renderer State management + + #region State retrieval + + [DllImport(AL.Lib, EntryPoint = "alGetString", ExactSpelling = true, CallingConvention = AL.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + private static extern IntPtr GetStringPrivate(ALGetString param); // accepts the enums AlError, AlContextString + // AL_API const ALchar* AL_APIENTRY alGetString( ALenum param ); + + /// This function retrieves an OpenAL string property. + /// The property to be returned: Vendor, Version, Renderer and Extensions + /// Returns a pointer to a null-terminated string. + public static string Get(ALGetString param) + { + return Marshal.PtrToStringAnsi(GetStringPrivate(param)); + } + + /// This function retrieves an OpenAL string property. + /// The human-readable errorstring to be returned. + /// Returns a pointer to a null-terminated string. + public static string GetErrorString(ALError param) + { + return Marshal.PtrToStringAnsi(GetStringPrivate((ALGetString)param)); + } + + /* no functions return more than 1 result .. + // AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* buffer ); + // AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* buffer ); + // AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* buffer ); + // AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* buffer ); + */ + + /* disabled due to no token using it + /// This function returns a boolean OpenAL state. + /// the state to be queried: AL_DOPPLER_FACTOR, AL_SPEED_OF_SOUND, AL_DISTANCE_MODEL + /// The boolean state described by param will be returned. + [DllImport( AL.Lib, EntryPoint = "alGetBoolean", ExactSpelling = true, CallingConvention = AL.Style ), SuppressUnmanagedCodeSecurity( )] + public static extern bool Get( ALGetBoolean param ); + // AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param ); + */ + + /// This function returns an integer OpenAL state. + /// the state to be queried: DistanceModel. + /// The integer state described by param will be returned. + [DllImport(AL.Lib, EntryPoint = "alGetInteger", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern int Get(ALGetInteger param); + // AL_API ALint AL_APIENTRY alGetInteger( ALenum param ); + + /// This function returns a floating-point OpenAL state. + /// the state to be queried: DopplerFactor, SpeedOfSound. + /// The floating-point state described by param will be returned. + [DllImport(AL.Lib, EntryPoint = "alGetFloat", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern float Get(ALGetFloat param); + // AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param ); + + /* disabled due to no token using it + /// This function returns a double-precision floating-point OpenAL state. + /// the state to be queried: AL_DOPPLER_FACTOR, AL_SPEED_OF_SOUND, AL_DISTANCE_MODEL + /// The double value described by param will be returned. + [DllImport( AL.Lib, EntryPoint = "alGetDouble", ExactSpelling = true, CallingConvention = AL.Style ), SuppressUnmanagedCodeSecurity( )] + public static extern double Get( ALGetDouble param ); + // AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param ); + */ + + /// Error support. Obtain the most recent error generated in the AL state machine. When an error is detected by AL, a flag is set and the error code is recorded. Further errors, if they occur, do not affect this recorded code. When alGetError is called, the code is returned and the flag is cleared, so that a further error will again record its code. + /// The first error that occured. can be used with AL.GetString. Returns an Alenum representing the error state. When an OpenAL error occurs, the error state is set and will not be changed until the error state is retrieved using alGetError. Whenever alGetError is called, the error state is cleared and the last state (the current state when the call was made) is returned. To isolate error detection to a specific portion of code, alGetError should be called before the isolated section to clear the current error state. + [DllImport(AL.Lib, EntryPoint = "alGetError", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern ALError GetError(); + // AL_API ALenum AL_APIENTRY alGetError( void ); + + #endregion State retrieval + + #region Extension support. + + ///This function tests if a specific Extension is available for the OpenAL driver. + /// A string naming the desired extension. Example: "EAX-RAM" + /// Returns True if the Extension is available or False if not available. + [DllImport(AL.Lib, EntryPoint = "alIsExtensionPresent", ExactSpelling = true, CallingConvention = AL.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern bool IsExtensionPresent([In] string extname); + // AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname ); + + /// This function returns the address of an OpenAL extension function. Handle with care. + /// A string containing the function name. + /// The return value is a pointer to the specified function. The return value will be IntPtr.Zero if the function is not found. + [DllImport(AL.Lib, EntryPoint = "alGetProcAddress", ExactSpelling = true, CallingConvention = AL.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern IntPtr GetProcAddress([In] string fname); + // AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname ); + + /// This function returns the enumeration value of an OpenAL token, described by a string. + /// A string describing an OpenAL token. Example "AL_DISTANCE_MODEL" + /// Returns the actual ALenum described by a string. Returns 0 if the string doesn’t describe a valid OpenAL token. + [DllImport(AL.Lib, EntryPoint = "alGetEnumValue", ExactSpelling = true, CallingConvention = AL.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern int GetEnumValue([In] string ename); + // AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename ); + + #endregion Extension support. + + /* Listener + * Listener represents the location and orientation of the + * 'user' in 3D-space. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors) + */ + + #region Set Listener parameters + + /// This function sets a floating-point property for the listener. + /// The name of the attribute to be set: ALListenerf.Gain + /// The float value to set the attribute to. + [DllImport(AL.Lib, EntryPoint = "alListenerf", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Listener(ALListenerf param, float value); + // AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value ); + + /// This function sets a floating-point property for the listener. + /// The name of the attribute to set: ALListener3f.Position, ALListener3f.Velocity + /// The value to set the attribute to. + /// The value to set the attribute to. + /// The value to set the attribute to. + [DllImport(AL.Lib, EntryPoint = "alListener3f", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Listener(ALListener3f param, float value1, float value2, float value3); + // AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + + /// This function sets a Math.Vector3 property for the listener. + /// The name of the attribute to set: ALListener3f.Position, ALListener3f.Velocity + /// The Math.Vector3 to set the attribute to. + public static void Listener(ALListener3f param, ref Vector3 values) + { + Listener(param, values.X, values.Y, values.Z); + } + + [DllImport(AL.Lib, EntryPoint = "alListenerfv", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe private static extern void ListenerPrivate(ALListenerfv param, float* values); + // AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ); + + /// This function sets a floating-point vector property of the listener. + /// The name of the attribute to be set: ALListener3f.Position, ALListener3f.Velocity, ALListenerfv.Orientation + /// Pointer to floating-point vector values. + public static void Listener(ALListenerfv param, ref float[] values) + { + unsafe + { + fixed (float* ptr = &values[0]) + { + ListenerPrivate(param, ptr); + } + } + } + + /// This function sets two Math.Vector3 properties of the listener. + /// The name of the attribute to be set: ALListenerfv.Orientation + /// A Math.Vector3 for the At-Vector. + /// A Math.Vector3 for the Up-Vector. + public static void Listener(ALListenerfv param, ref Vector3 at, ref Vector3 up) + { + float[] temp = new float[6]; + + temp[0] = at.X; + temp[1] = at.Y; + temp[2] = at.Z; + + temp[3] = up.X; + temp[4] = up.Y; + temp[5] = up.Z; + + unsafe + { + fixed (float* ptr = &temp[0]) + { + ListenerPrivate(param, ptr); + } + } + } + + // Not used by any Enums + // AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value ); + // AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ); + // AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values ); + + #endregion Set Listener parameters + + #region Get Listener parameters + + /// This function retrieves a floating-point property of the listener. + /// the name of the attribute to be retrieved: ALListenerf.Gain + /// a pointer to the floating-point value being retrieved. + [DllImport(AL.Lib, EntryPoint = "alGetListenerf", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetListener(ALListenerf param, [Out] out float value); + // AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value ); + + /// This function retrieves a set of three floating-point values from a property of the listener. + /// The name of the attribute to be retrieved: ALListener3f.Position, ALListener3f.Velocity + /// The first floating-point value being retrieved. + /// The second floating-point value being retrieved. + /// The third floating-point value being retrieved. + [DllImport(AL.Lib, EntryPoint = "alGetListener3f", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetListener(ALListener3f param, [Out] out float value1, [Out] out float value2, [Out] out float value3); + // AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); + + /// This function retrieves a Math.Vector3 from a property of the listener. + /// The name of the attribute to be retrieved: ALListener3f.Position, ALListener3f.Velocity + /// A Math.Vector3 to hold the three floats being retrieved. + public static void GetListener(ALListener3f param, out Vector3 values) + { + GetListener(param, out values.X, out values.Y, out values.Z); + } + + /// This function retrieves a floating-point vector property of the listener. You must pin it manually. + /// the name of the attribute to be retrieved: ALListener3f.Position, ALListener3f.Velocity, ALListenerfv.Orientation + /// A pointer to the floating-point vector value being retrieved. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alGetListenerfv", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe public static extern void GetListener(ALListenerfv param, float* values); + // AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values ); + + /// This function retrieves two Math.Vector3 properties of the listener. + /// the name of the attribute to be retrieved: ALListenerfv.Orientation + /// A Math.Vector3 for the At-Vector. + /// A Math.Vector3 for the Up-Vector. + public static void GetListener(ALListenerfv param, out Vector3 at, out Vector3 up) + { + float[] pinned = new float[6]; // should lose scope when the function exits + unsafe + { + fixed (float* ptr = &pinned[0]) + { + GetListener(param, ptr); + + at.X = pinned[0]; + at.Y = pinned[1]; + at.Z = pinned[2]; + + up.X = pinned[3]; + up.Y = pinned[4]; + up.Z = pinned[5]; + } + } + } + + // Not used by any Enum: + // AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value ); + // AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); + // AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values ); + + #endregion Get Listener parameters + + /* Source + * Sources represent individual sound objects in 3D-space. + * Sources take the PCM buffer provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial arrangement etc. + * + * Properties include: - + * + + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Direction AL_DIRECTION ALfloat[3] + + * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE) + * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE) + * + * Reference Distance AL_REFERENCE_DISTANCE ALfloat + * Max Distance AL_MAX_DISTANCE ALfloat + * RollOff Factor AL_ROLLOFF_FACTOR ALfloat + * Pitch AL_PITCH ALfloat + * Gain AL_GAIN ALfloat + * Min Gain AL_MIN_GAIN ALfloat + * Max Gain AL_MAX_GAIN ALfloat + * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat + * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat + * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat + * + * MS Offset AL_MSEC_OFFSET ALint or ALfloat + * Byte Offset AL_BYTE_OFFSET ALint or ALfloat + * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat + * Attached Buffer AL_BUFFER ALint + * + * State (Query only) AL_SOURCE_STATE ALint + * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint + * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint + */ + + #region Create Source objects + + #region GenSources() + + [DllImport(AL.Lib, EntryPoint = "alGenSources", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe private static extern void GenSourcesPrivate(int n, [Out] uint* sources); + // AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* Sources ); + + /// This function generates one or more sources. References to sources are uint values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// The number of sources to be generated. + /// Pointer to an array of uint values which will store the names of the new sources. + [CLSCompliant(false)] + public static void GenSources(int n, out uint sources) + { + unsafe + { + fixed (uint* sources_ptr = &sources) + { + GenSourcesPrivate(n, sources_ptr); + } + } + } + + /// This function generates one or more sources. References to sources are int values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// The number of sources to be generated. + /// Pointer to an array of int values which will store the names of the new sources. + public static void GenSources(int n, out int sources) + { + unsafe + { + fixed (int* sources_ptr = &sources) + { + GenSourcesPrivate(n, (uint*)sources_ptr); + } + } + } + + /// This function generates one or more sources. References to sources are int values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// Pointer to an array of int values which will store the names of the new sources. + public static void GenSources(int[] sources) + { + uint[] temp = new uint[sources.Length]; + GenSources(temp.Length, out temp[0]); + for (int i = 0; i < temp.Length; i++) + { + sources[i] = (int)temp[i]; + } + } + + /// This function generates one or more sources. References to sources are int values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// The number of sources to be generated. + /// Pointer to an array of int values which will store the names of the new sources. + public static int[] GenSources(int n) + { + uint[] temp = new uint[n]; + GenSources(temp.Length, out temp[0]); + int[] sources = new int[n]; + for (int i = 0; i < temp.Length; i++) + { + sources[i] = (int)temp[i]; + } + return sources; + } + + /// This function generates one source only. References to sources are int values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// Pointer to an int value which will store the name of the new source. + public static int GenSource() + { + int temp; + GenSources(1, out temp); + return (int)temp; + } + + /// This function generates one source only. References to sources are uint values, which are used wherever a source reference is needed (in calls such as AL.DeleteSources and AL.Source with parameter ALSourcei). + /// Pointer to an uint value which will store the name of the new source. + [CLSCompliant(false)] + public static void GenSource(out uint source) + { + GenSources(1, out source); + } + + #endregion GenSources() + + #region DeleteSources() + + /// This function deletes one or more sources. + /// The number of sources to be deleted. + /// Pointer to an array of source names identifying the sources to be deleted. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alDeleteSources", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe public static extern void DeleteSources(int n, [In] uint* sources); // Delete Source objects + // AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* Sources ); + + /// This function deletes one or more sources. + /// The number of sources to be deleted. + /// Reference to a single source, or an array of source names identifying the sources to be deleted. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alDeleteSources", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void DeleteSources(int n, ref uint sources); + + /// This function deletes one or more sources. + /// The number of sources to be deleted. + /// Reference to a single source, or an array of source names identifying the sources to be deleted. + [DllImport(AL.Lib, EntryPoint = "alDeleteSources", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void DeleteSources(int n, ref int sources); + + /// This function deletes one or more sources. + /// An array of source names identifying the sources to be deleted. + [CLSCompliant(false)] + public static void DeleteSources(uint[] sources) + { + if (sources == null) throw new ArgumentNullException(); + if (sources.Length == 0) throw new ArgumentOutOfRangeException(); + DeleteBuffers(sources.Length, ref sources[0]); + } + + /// This function deletes one or more sources. + /// An array of source names identifying the sources to be deleted. + public static void DeleteSources(int[] sources) + { + if (sources == null) throw new ArgumentNullException(); + if (sources.Length == 0) throw new ArgumentOutOfRangeException(); + DeleteBuffers(sources.Length, ref sources[0]); + } + + /// This function deletes one source only. + /// Pointer to a source name identifying the source to be deleted. + [CLSCompliant(false)] + public static void DeleteSource(ref uint source) + { + DeleteSources(1, ref source); + } + + /// This function deletes one source only. + /// Pointer to a source name identifying the source to be deleted. + public static void DeleteSource(int source) + { + DeleteSources(1, ref source); + } + + #endregion DeleteSources() + + #region IsSource() + + /// This function tests if a source name is valid, returning True if valid and False if not. + /// A source name to be tested for validity + /// Success. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alIsSource", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern bool IsSource(uint sid); + // AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ); + + /// This function tests if a source name is valid, returning True if valid and False if not. + /// A source name to be tested for validity + /// Success. + public static bool IsSource(int sid) + { + return IsSource((uint)sid); + } + + #endregion IsSource() + + #endregion Create Source objects + + #region Set Source parameters + + #region Sourcef + + /// This function sets a floating-point property of a source. + /// Source name whose attribute is being set + /// The name of the attribute to set: ALSourcef.Pitch, Gain, MinGain, MaxGain, MaxDistance, RolloffFactor, ConeOuterGain, ConeInnerAngle, ConeOuterAngle, ReferenceDistance, EfxAirAbsorptionFactor, EfxRoomRolloffFactor, EfxConeOuterGainHighFrequency. + /// The value to set the attribute to. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcef", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Source(uint sid, ALSourcef param, float value); + // AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); + + /// This function sets a floating-point property of a source. + /// Source name whose attribute is being set + /// The name of the attribute to set: ALSourcef.Pitch, Gain, MinGain, MaxGain, MaxDistance, RolloffFactor, ConeOuterGain, ConeInnerAngle, ConeOuterAngle, ReferenceDistance, EfxAirAbsorptionFactor, EfxRoomRolloffFactor, EfxConeOuterGainHighFrequency. + /// The value to set the attribute to. + public static void Source(int sid, ALSourcef param, float value) + { + Source((uint)sid, param, value); + } + + #endregion Sourcef + + #region Source3f + + /// This function sets a source property requiring three floating-point values. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSource3f.Position, Velocity, Direction. + /// The three ALfloat values which the attribute will be set to. + /// The three ALfloat values which the attribute will be set to. + /// The three ALfloat values which the attribute will be set to. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSource3f", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Source(uint sid, ALSource3f param, float value1, float value2, float value3); + // AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + + /// This function sets a source property requiring three floating-point values. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSource3f.Position, Velocity, Direction. + /// The three ALfloat values which the attribute will be set to. + /// The three ALfloat values which the attribute will be set to. + /// The three ALfloat values which the attribute will be set to. + public static void Source(int sid, ALSource3f param, float value1, float value2, float value3) + { + Source((uint)sid, param, value1, value2, value3); + } + + /// This function sets a source property requiring three floating-point values. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSource3f.Position, Velocity, Direction. + /// A Math.Vector3 which the attribute will be set to. + [CLSCompliant(false)] + public static void Source(uint sid, ALSource3f param, ref Vector3 values) + { + Source(sid, param, values.X, values.Y, values.Z); + } + + /// This function sets a source property requiring three floating-point values. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSource3f.Position, Velocity, Direction. + /// A Math.Vector3 which the attribute will be set to. + public static void Source(int sid, ALSource3f param, ref Vector3 values) + { + Source((uint)sid, param, values.X, values.Y, values.Z); + } + + #endregion Source3f + + #region Sourcei + + /// This function sets an integer property of a source. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSourcei.SourceRelative, ConeInnerAngle, ConeOuterAngle, Looping, Buffer, SourceState. + /// The value to set the attribute to. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcei", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Source(uint sid, ALSourcei param, int value); + // AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); + + /// This function sets an integer property of a source. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSourcei.SourceRelative, ConeInnerAngle, ConeOuterAngle, Looping, Buffer, SourceState. + /// The value to set the attribute to. + public static void Source(int sid, ALSourcei param, int value) + { + Source((uint)sid, param, value); + } + + /// This function sets an bool property of a source. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSourceb.SourceRelative, Looping. + /// The value to set the attribute to. + [CLSCompliant(false)] + public static void Source(uint sid, ALSourceb param, bool value) + { + Source(sid, (ALSourcei)param, (value) ? 1 : 0); + } + + /// This function sets an bool property of a source. + /// Source name whose attribute is being set. + /// The name of the attribute to set: ALSourceb.SourceRelative, Looping. + /// The value to set the attribute to. + public static void Source(int sid, ALSourceb param, bool value) + { + Source((uint)sid, (ALSourcei)param, (value) ? 1 : 0); + } + + /// (Helper) Binds a Buffer to a Source handle. + /// Source name to attach the Buffer to. + /// Buffer name which is attached to the Source. + [CLSCompliant(false)] + public static void BindBufferToSource(uint source, uint buffer) + { + Source(source, ALSourcei.Buffer, (int)buffer); + } + + /// (Helper) Binds a Buffer to a Source handle. + /// Source name to attach the Buffer to. + /// Buffer name which is attached to the Source. + public static void BindBufferToSource(int source, int buffer) + { + Source((uint)source, ALSourcei.Buffer, buffer); + } + + #endregion Sourcei + + #region Source3i + + /// This function sets 3 integer properties of a source. This property is used to establish connections between Sources and Auxiliary Effect Slots. + /// Source name whose attribute is being set. + /// The name of the attribute to set: EfxAuxiliarySendFilter + /// The value to set the attribute to. (EFX Extension) The destination Auxiliary Effect Slot ID + /// The value to set the attribute to. (EFX Extension) The Auxiliary Send number. + ///The value to set the attribute to. (EFX Extension) optional Filter ID. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSource3i", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void Source(uint sid, ALSource3i param, int value1, int value2, int value3); + // AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); + + /// This function sets 3 integer properties of a source. This property is used to establish connections between Sources and Auxiliary Effect Slots. + /// Source name whose attribute is being set. + /// The name of the attribute to set: EfxAuxiliarySendFilter + /// The value to set the attribute to. (EFX Extension) The destination Auxiliary Effect Slot ID + /// The value to set the attribute to. (EFX Extension) The Auxiliary Send number. + ///The value to set the attribute to. (EFX Extension) optional Filter ID. + public static void Source(int sid, ALSource3i param, int value1, int value2, int value3) + { + Source((uint)sid, param, value1, value2, value3); + } + + #endregion Source3i + + // Not used by any Enum: + // AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); + // AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ); + + #endregion Set Source parameters + + #region Get Source parameters + + #region GetSourcef + + /// This function retrieves a floating-point property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to set: ALSourcef.Pitch, Gain, MinGain, MaxGain, MaxDistance, RolloffFactor, ConeOuterGain, ConeInnerAngle, ConeOuterAngle, ReferenceDistance, EfxAirAbsorptionFactor, EfxRoomRolloffFactor, EfxConeOuterGainHighFrequency. + /// A pointer to the floating-point value being retrieved + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alGetSourcef", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetSource(uint sid, ALSourcef param, [Out] out float value); + // AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ); + + /// This function retrieves a floating-point property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to set: ALSourcef.Pitch, Gain, MinGain, MaxGain, MaxDistance, RolloffFactor, ConeOuterGain, ConeInnerAngle, ConeOuterAngle, ReferenceDistance, EfxAirAbsorptionFactor, EfxRoomRolloffFactor, EfxConeOuterGainHighFrequency. + /// A pointer to the floating-point value being retrieved + public static void GetSource(int sid, ALSourcef param, out float value) + { + GetSource((uint)sid, param, out value); + } + + #endregion GetSourcef + + #region GetSource3f + + /// This function retrieves three floating-point values representing a property of a source. + /// Source name whose attribute is being retrieved. + /// the name of the attribute being retrieved: ALSource3f.Position, Velocity, Direction. + /// Pointer to the value to retrieve. + /// Pointer to the value to retrieve. + /// Pointer to the value to retrieve. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alGetSource3f", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetSource(uint sid, ALSource3f param, [Out] out float value1, [Out] out float value2, [Out] out float value3); + // AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + + /// This function retrieves three floating-point values representing a property of a source. + /// Source name whose attribute is being retrieved. + /// the name of the attribute being retrieved: ALSource3f.Position, Velocity, Direction. + /// Pointer to the value to retrieve. + /// Pointer to the value to retrieve. + /// Pointer to the value to retrieve. + public static void GetSource(int sid, ALSource3f param, out float value1, out float value2, out float value3) + { + GetSource((uint)sid, param, out value1, out value2, out value3); + } + + /// This function retrieves three floating-point values representing a property of a source. + /// Source name whose attribute is being retrieved. + /// the name of the attribute being retrieved: ALSource3f.Position, Velocity, Direction. + /// A Math.Vector3 to retrieve the values to. + [CLSCompliant(false)] + public static void GetSource(uint sid, ALSource3f param, out Vector3 values) + { + GetSource(sid, param, out values.X, out values.Y, out values.Z); + } + + /// This function retrieves three floating-point values representing a property of a source. + /// Source name whose attribute is being retrieved. + /// the name of the attribute being retrieved: ALSource3f.Position, Velocity, Direction. + /// A Math.Vector3 to retrieve the values to. + public static void GetSource(int sid, ALSource3f param, out Vector3 values) + { + GetSource((uint)sid, param, out values.X, out values.Y, out values.Z); + } + + #endregion GetSource3f + + #region GetSourcei + + /// This function retrieves an integer property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to retrieve: ALSourcei.SourceRelative, Buffer, SourceState, BuffersQueued, BuffersProcessed. + /// A pointer to the integer value being retrieved. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alGetSourcei", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetSource(uint sid, ALGetSourcei param, [Out] out int value); + // AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ); + + /// This function retrieves an integer property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to retrieve: ALSourcei.SourceRelative, Buffer, SourceState, BuffersQueued, BuffersProcessed. + /// A pointer to the integer value being retrieved. + public static void GetSource(int sid, ALGetSourcei param, out int value) + { + GetSource((uint)sid, param, out value); + } + + /// This function retrieves a bool property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to get: ALSourceb.SourceRelative, Looping. + /// A pointer to the bool value being retrieved. + [CLSCompliant(false)] + public static void GetSource(uint sid, ALSourceb param, out bool value) + { + int result; + GetSource(sid, (ALGetSourcei)param, out result); + value = result != 0; + } + + /// This function retrieves a bool property of a source. + /// Source name whose attribute is being retrieved. + /// The name of the attribute to get: ALSourceb.SourceRelative, Looping. + /// A pointer to the bool value being retrieved. + public static void GetSource(int sid, ALSourceb param, out bool value) + { + int result; + GetSource((uint)sid, (ALGetSourcei)param, out result); + value = result != 0; + } + + #endregion GetSourcei + + // Not used by any Enum: + // AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + // AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ); + // AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ); + + #endregion Get Source parameters + + #region Source vector based playback calls + + #region SourcePlay + + /// This function plays a set of sources. The playing sources will have their state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The number of sources to be played. + /// A pointer to an array of sources to be played. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcePlayv"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourcePlay(int ns, [In] uint* sids); + // AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ); + + /// This function plays a set of sources. The playing sources will have their state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The number of sources to be played. + /// A pointer to an array of sources to be played. + [CLSCompliant(false)] + public static void SourcePlay(int ns, uint[] sids) + { + unsafe + { + fixed (uint* ptr = sids) + { + SourcePlay(ns, ptr); + } + } + } + + /// This function plays a set of sources. The playing sources will have their state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The number of sources to be played. + /// A pointer to an array of sources to be played. + public static void SourcePlay(int ns, int[] sids) + { + uint[] temp = new uint[ns]; + for (int i = 0; i < ns; i++) + { + temp[i] = (uint)sids[i]; + } + SourcePlay(ns, temp); + } + + /// This function plays a set of sources. The playing sources will have their state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The number of sources to be played. + /// A pointer to an array of sources to be played. + [CLSCompliant(false)] + public static void SourcePlay(int ns, ref uint sids) + { + unsafe + { + fixed (uint* ptr = &sids) + { + SourcePlay(ns, ptr); + } + } + } + + #endregion SourcePlay + + #region SourceStop + + /// This function stops a set of sources. The stopped sources will have their state changed to ALSourceState.Stopped. + /// The number of sources to stop. + /// A pointer to an array of sources to be stopped. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceStopv"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourceStop(int ns, [In] uint* sids); + // AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ); + + /// This function stops a set of sources. The stopped sources will have their state changed to ALSourceState.Stopped. + /// The number of sources to stop. + /// A pointer to an array of sources to be stopped. + [CLSCompliant(false)] + public static void SourceStop(int ns, uint[] sids) + { + unsafe + { + fixed (uint* ptr = sids) + { + SourceStop(ns, ptr); + } + } + } + + /// This function stops a set of sources. The stopped sources will have their state changed to ALSourceState.Stopped. + /// The number of sources to stop. + /// A pointer to an array of sources to be stopped. + public static void SourceStop(int ns, int[] sids) + { + uint[] temp = new uint[ns]; + for (int i = 0; i < ns; i++) + { + temp[i] = (uint)sids[i]; + } + SourceStop(ns, temp); + } + + /// This function stops a set of sources. The stopped sources will have their state changed to ALSourceState.Stopped. + /// The number of sources to stop. + /// A pointer to an array of sources to be stopped. + [CLSCompliant(false)] + public static void SourceStop(int ns, ref uint sids) + { + unsafe + { + fixed (uint* ptr = &sids) + { + SourceStop(ns, ptr); + } + } + } + + #endregion SourceStop + + #region SourceRewind + + /// This function stops a set of sources and sets all their states to ALSourceState.Initial. + /// The number of sources to be rewound. + /// A pointer to an array of sources to be rewound. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceRewindv"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourceRewind(int ns, [In] uint* sids); + // AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ); + + /// This function stops a set of sources and sets all their states to ALSourceState.Initial. + /// The number of sources to be rewound. + /// A pointer to an array of sources to be rewound. + [CLSCompliant(false)] + public static void SourceRewind(int ns, uint[] sids) + { + unsafe + { + fixed (uint* ptr = sids) + { + SourceRewind(ns, ptr); + } + } + } + + /// This function stops a set of sources and sets all their states to ALSourceState.Initial. + /// The number of sources to be rewound. + /// A pointer to an array of sources to be rewound. + public static void SourceRewind(int ns, int[] sids) + { + uint[] temp = new uint[ns]; + for (int i = 0; i < ns; i++) + { + temp[i] = (uint)sids[i]; + } + SourceRewind(ns, temp); + } + + /// This function stops a set of sources and sets all their states to ALSourceState.Initial. + /// The number of sources to be rewound. + /// A pointer to an array of sources to be rewound. + [CLSCompliant(false)] + public static void SourceRewind(int ns, ref uint sids) + { + unsafe + { + fixed (uint* ptr = &sids) + { + SourceRewind(ns, ptr); + } + } + } + + #endregion SourceRewind + + #region SourcePause + + /// This function pauses a set of sources. The paused sources will have their state changed to ALSourceState.Paused. + /// The number of sources to be paused. + /// A pointer to an array of sources to be paused. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcePausev"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourcePause(int ns, [In] uint* sids); + // AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ); + + /// This function pauses a set of sources. The paused sources will have their state changed to ALSourceState.Paused. + /// The number of sources to be paused. + /// A pointer to an array of sources to be paused. + [CLSCompliant(false)] + public static void SourcePause(int ns, uint[] sids) + { + unsafe + { + fixed (uint* ptr = sids) + { + SourcePause(ns, ptr); + } + } + } + /// This function pauses a set of sources. The paused sources will have their state changed to ALSourceState.Paused. + /// The number of sources to be paused. + /// A pointer to an array of sources to be paused. + public static void SourcePause(int ns, int[] sids) + { + uint[] temp = new uint[ns]; + for (int i = 0; i < ns; i++) + { + temp[i] = (uint)sids[i]; + } + SourcePause(ns, temp); + } + + /// This function pauses a set of sources. The paused sources will have their state changed to ALSourceState.Paused. + /// The number of sources to be paused. + /// A pointer to an array of sources to be paused. + [CLSCompliant(false)] + public static void SourcePause(int ns, ref uint sids) + { + unsafe + { + fixed (uint* ptr = &sids) + { + SourcePause(ns, ptr); + } + } + } + + #endregion SourcePause + + #endregion Source vector based playback calls + + #region Source based playback calls + + #region SourcePlay + + /// This function plays, replays or resumes a source. The playing source will have it's state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The name of the source to be played. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcePlay", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void SourcePlay(uint sid); + // AL_API void AL_APIENTRY alSourcePlay( ALuint sid ); + + /// This function plays, replays or resumes a source. The playing source will have it's state changed to ALSourceState.Playing. When called on a source which is already playing, the source will restart at the beginning. When the attached buffer(s) are done playing, the source will progress to the ALSourceState.Stopped state. + /// The name of the source to be played. + public static void SourcePlay(int sid) + { + SourcePlay((uint)sid); + } + + #endregion SourcePlay + + #region SourceStop + + /// This function stops a source. The stopped source will have it's state changed to ALSourceState.Stopped. + /// The name of the source to be stopped. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceStop", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void SourceStop(uint sid); + // AL_API void AL_APIENTRY alSourceStop( ALuint sid ); + + /// This function stops a source. The stopped source will have it's state changed to ALSourceState.Stopped. + /// The name of the source to be stopped. + public static void SourceStop(int sid) + { + SourceStop((uint)sid); + } + + #endregion SourceStop + + #region SourceRewind + + /// This function stops the source and sets its state to ALSourceState.Initial. + /// The name of the source to be rewound. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceRewind", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void SourceRewind(uint sid); + // AL_API void AL_APIENTRY alSourceRewind( ALuint sid ); + + /// This function stops the source and sets its state to ALSourceState.Initial. + /// The name of the source to be rewound. + public static void SourceRewind(int sid) + { + SourceRewind((uint)sid); + } + + #endregion SourceRewind + + #region SourcePause + + /// This function pauses a source. The paused source will have its state changed to ALSourceState.Paused. + /// The name of the source to be paused. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourcePause", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void SourcePause(uint sid); + // AL_API void AL_APIENTRY alSourcePause( ALuint sid ); + + /// This function pauses a source. The paused source will have its state changed to ALSourceState.Paused. + /// The name of the source to be paused. + public static void SourcePause(int sid) + { + SourcePause((uint)sid); + } + + #endregion SourcePause + + #endregion Source based playback calls + + #region Source Queuing + + #region SourceQueueBuffers + + /// This function queues a set of buffers on a source. All buffers attached to a source will be played in sequence, and the number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed. When first created, a source will be of type ALSourceType.Undetermined. A successful AL.SourceQueueBuffers call will change the source type to ALSourceType.Streaming. + /// The name of the source to queue buffers onto. + /// The number of buffers to be queued. + /// A pointer to an array of buffer names to be queued. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceQueueBuffers"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourceQueueBuffers(uint sid, int numEntries, [In] uint* bids); + // AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ); + + /// This function queues a set of buffers on a source. All buffers attached to a source will be played in sequence, and the number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed. When first created, a source will be of type ALSourceType.Undetermined. A successful AL.SourceQueueBuffers call will change the source type to ALSourceType.Streaming. + /// The name of the source to queue buffers onto. + /// The number of buffers to be queued. + /// A pointer to an array of buffer names to be queued. + [CLSCompliant(false)] + public static void SourceQueueBuffers(uint sid, int numEntries, uint[] bids) + { + unsafe + { + fixed (uint* ptr = bids) + { + SourceQueueBuffers(sid, numEntries, ptr); + } + } + } + + /// This function queues a set of buffers on a source. All buffers attached to a source will be played in sequence, and the number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed. When first created, a source will be of type ALSourceType.Undetermined. A successful AL.SourceQueueBuffers call will change the source type to ALSourceType.Streaming. + /// The name of the source to queue buffers onto. + /// The number of buffers to be queued. + /// A pointer to an array of buffer names to be queued. + public static void SourceQueueBuffers(int sid, int numEntries, int[] bids) + { + uint[] temp = new uint[numEntries]; + for (int i = 0; i < numEntries; i++) + { + temp[i] = (uint)bids[i]; + } + SourceQueueBuffers((uint)sid, numEntries, temp); + } + + /// This function queues a set of buffers on a source. All buffers attached to a source will be played in sequence, and the number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed. When first created, a source will be of type ALSourceType.Undetermined. A successful AL.SourceQueueBuffers call will change the source type to ALSourceType.Streaming. + /// The name of the source to queue buffers onto. + /// The number of buffers to be queued. + /// A pointer to an array of buffer names to be queued. + [CLSCompliant(false)] + public static void SourceQueueBuffers(uint sid, int numEntries, ref uint bids) + { + unsafe + { + fixed (uint* ptr = &bids) + { + SourceQueueBuffers(sid, numEntries, ptr); + } + } + } + + /// This function queues a set of buffers on a source. All buffers attached to a source will be played in sequence, and the number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed. When first created, a source will be of type ALSourceType.Undetermined. A successful AL.SourceQueueBuffers call will change the source type to ALSourceType.Streaming. + /// The name of the source to queue buffers onto. + /// The name of the buffer to be queued. + public static void SourceQueueBuffer(int source, int buffer) + { + unsafe { AL.SourceQueueBuffers((uint)source, 1, (uint*)&buffer); } + } + + #endregion SourceQueueBuffers + + #region SourceUnqueueBuffers + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + /// A pointer to an array of buffer names that were removed. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alSourceUnqueueBuffers"), SuppressUnmanagedCodeSecurity] + unsafe public static extern void SourceUnqueueBuffers(uint sid, int numEntries, [In] uint* bids); + // AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + /// A pointer to an array of buffer names that were removed. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alSourceUnqueueBuffers"), SuppressUnmanagedCodeSecurity] + public static extern void SourceUnqueueBuffers(uint sid, int numEntries, [Out] uint[] bids); + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + /// A pointer to an array of buffer names that were removed. + [DllImport(AL.Lib, EntryPoint = "alSourceUnqueueBuffers"), SuppressUnmanagedCodeSecurity] + public static extern void SourceUnqueueBuffers(int sid, int numEntries, [Out] int[] bids); + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + /// A pointer to an array of buffer names that were removed. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alSourceUnqueueBuffers"), SuppressUnmanagedCodeSecurity] + public static extern void SourceUnqueueBuffers(uint sid, int numEntries, ref uint bids); + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + /// A pointer to an array of buffer names that were removed. + [DllImport(AL.Lib, EntryPoint = "alSourceUnqueueBuffers"), SuppressUnmanagedCodeSecurity] + public static extern void SourceUnqueueBuffers(int sid, int numEntries, ref int bids); + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + public static int SourceUnqueueBuffer(int sid) + { + uint buf; + unsafe { SourceUnqueueBuffers((uint)sid, 1, &buf); } + return (int)buf; + } + + /// This function unqueues a set of buffers attached to a source. The number of processed buffers can be detected using AL.GetSource with parameter ALGetSourcei.BuffersProcessed, which is the maximum number of buffers that can be unqueued using this call. The unqueue operation will only take place if all n buffers can be removed from the queue. + /// The name of the source to unqueue buffers from. + /// The number of buffers to be unqueued. + public static int[] SourceUnqueueBuffers(int sid, int numEntries) + { + if (numEntries <= 0) throw new ArgumentOutOfRangeException("numEntries", "Must be greater than zero."); + int[] buf = new int[numEntries]; + SourceUnqueueBuffers(sid, numEntries, buf); + return buf; + } + + #endregion SourceUnqueueBuffers + + #endregion Source Queuing + + /* + * Buffer + * Buffer objects are storage space for sample buffer. + * Buffers are referred to by Sources. One Buffer can be used + * by multiple Sources. + * + * Properties include: - + * + * Frequency (Query only) AL_FREQUENCY ALint + * Size (Query only) AL_SIZE ALint + * Bits (Query only) AL_BITS ALint + * Channels (Query only) AL_CHANNELS ALint + */ + + #region Buffer objects + + #region GenBuffers + + /// This function generates one or more buffers, which contain audio buffer (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// The number of buffers to be generated. + /// Pointer to an array of uint values which will store the names of the new buffers. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alGenBuffers", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity] + unsafe public static extern void GenBuffers(int n, [Out] uint* buffers); + // AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* Buffers ); + + /// This function generates one or more buffers, which contain audio buffer (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// The number of buffers to be generated. + /// Pointer to an array of uint values which will store the names of the new buffers. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alGenBuffers", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity] + unsafe public static extern void GenBuffers(int n, [Out] int* buffers); + + /// This function generates one or more buffers, which contain audio buffer (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// The number of buffers to be generated. + /// Pointer to an array of uint values which will store the names of the new buffers. + [CLSCompliant(false)] + public static void GenBuffers(int n, out uint buffers) + { + unsafe + { + fixed (uint* pbuffers = &buffers) + { + GenBuffers(n, pbuffers); + } + } + } + + /// This function generates one or more buffers, which contain audio buffer (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// The number of buffers to be generated. + /// Pointer to an array of uint values which will store the names of the new buffers. + public static void GenBuffers(int n, out int buffers) + { + unsafe + { + fixed (int* pbuffers = &buffers) + { + GenBuffers(n, pbuffers); + } + } + } + + /// This function generates one or more buffers, which contain audio data (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// The number of buffers to be generated. + /// Pointer to an array of uint values which will store the names of the new buffers. + public static int[] GenBuffers(int n) + { + int[] buffers = new int[n]; + GenBuffers(buffers.Length, out buffers[0]); + return buffers; + } + + /// This function generates one buffer only, which contain audio data (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// Pointer to an uint value which will store the name of the new buffer. + public static int GenBuffer() + { + int temp; + GenBuffers(1, out temp); + return (int)temp; + } + + /// This function generates one buffer only, which contain audio data (see AL.BufferData). References to buffers are uint values, which are used wherever a buffer reference is needed (in calls such as AL.DeleteBuffers, AL.Source with parameter ALSourcei, AL.SourceQueueBuffers, and AL.SourceUnqueueBuffers). + /// Pointer to an uint value which will store the names of the new buffer. + [CLSCompliant(false)] + public static void GenBuffer(out uint buffer) + { + GenBuffers(1, out buffer); + } + + #endregion GenBuffers + + #region DeleteBuffers + + /// This function deletes one or more buffers, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// The number of buffers to be deleted. + /// Pointer to an array of buffer names identifying the buffers to be deleted. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alDeleteBuffers", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe public static extern void DeleteBuffers(int n, [In] uint* buffers); + // AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* Buffers ); + + /// This function deletes one or more buffers, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// The number of buffers to be deleted. + /// Pointer to an array of buffer names identifying the buffers to be deleted. + [CLSCompliant(false)] + [DllImport(AL.Lib, EntryPoint = "alDeleteBuffers", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + unsafe public static extern void DeleteBuffers(int n, [In] int* buffers); + + /// This function deletes one or more buffers, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// The number of buffers to be deleted. + /// Pointer to an array of buffer names identifying the buffers to be deleted. + [CLSCompliant(false)] + public static void DeleteBuffers(int n, [In] ref uint buffers) + { + unsafe + { + fixed (uint* pbuffers = &buffers) + { + DeleteBuffers(n, pbuffers); + } + } + } + + /// This function deletes one or more buffers, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// The number of buffers to be deleted. + /// Pointer to an array of buffer names identifying the buffers to be deleted. + public static void DeleteBuffers(int n, [In] ref int buffers) + { + unsafe + { + fixed (int* pbuffers = &buffers) + { + DeleteBuffers(n, pbuffers); + } + } + } + + /// This function deletes one buffer only, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// Pointer to a buffer name identifying the buffer to be deleted. + [CLSCompliant(false)] + public static void DeleteBuffers(uint[] buffers) + { + if (buffers == null) throw new ArgumentNullException(); + if (buffers.Length == 0) throw new ArgumentOutOfRangeException(); + DeleteBuffers(buffers.Length, ref buffers[0]); + } + + /// This function deletes one or more buffers, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// Pointer to an array of buffer names identifying the buffers to be deleted. + public static void DeleteBuffers(int[] buffers) + { + if (buffers == null) throw new ArgumentNullException(); + if (buffers.Length == 0) throw new ArgumentOutOfRangeException(); + DeleteBuffers(buffers.Length, ref buffers[0]); + } + + /// This function deletes one buffer only, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// Pointer to a buffer name identifying the buffer to be deleted. + [CLSCompliant(false)] + public static void DeleteBuffer(ref uint buffer) + { + DeleteBuffers(1, ref buffer); + } + + /// This function deletes one buffer only, freeing the resources used by the buffer. Buffers which are attached to a source can not be deleted. See AL.Source (ALSourcei) and AL.SourceUnqueueBuffers for information on how to detach a buffer from a source. + /// Pointer to a buffer name identifying the buffer to be deleted. + public static void DeleteBuffer(int buffer) + { + DeleteBuffers(1, ref buffer); + } + + #endregion DeleteBuffers + + #region IsBuffer + + /// This function tests if a buffer name is valid, returning True if valid, False if not. + /// A buffer Handle previously allocated with . + /// Success. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alIsBuffer", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern bool IsBuffer(uint bid); + // AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid ); + + /// This function tests if a buffer name is valid, returning True if valid, False if not. + /// A buffer Handle previously allocated with . + /// Success. + public static bool IsBuffer(int bid) + { + uint temp = (uint)bid; + return IsBuffer(temp); + } + + #endregion IsBuffer + + #region BufferData + + /// This function fills a buffer with audio buffer. All the pre-defined formats are PCM buffer, but this function may be used by extensions to load other buffer types as well. + /// buffer Handle/Name to be filled with buffer. + /// Format type from among the following: ALFormat.Mono8, ALFormat.Mono16, ALFormat.Stereo8, ALFormat.Stereo16. + /// Pointer to a pinned audio buffer. + /// The size of the audio buffer in bytes. + /// The frequency of the audio buffer. + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alBufferData", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void BufferData(uint bid, ALFormat format, IntPtr buffer, int size, int freq); + // AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* buffer, ALsizei size, ALsizei freq ); + + /// This function fills a buffer with audio buffer. All the pre-defined formats are PCM buffer, but this function may be used by extensions to load other buffer types as well. + /// buffer Handle/Name to be filled with buffer. + /// Format type from among the following: ALFormat.Mono8, ALFormat.Mono16, ALFormat.Stereo8, ALFormat.Stereo16. + /// Pointer to a pinned audio buffer. + /// The size of the audio buffer in bytes. + /// The frequency of the audio buffer. + public static void BufferData(int bid, ALFormat format, IntPtr buffer, int size, int freq) + { + BufferData((uint)bid, format, buffer, size, freq); + } + + /// This function fills a buffer with audio buffer. All the pre-defined formats are PCM buffer, but this function may be used by extensions to load other buffer types as well. + /// buffer Handle/Name to be filled with buffer. + /// Format type from among the following: ALFormat.Mono8, ALFormat.Mono16, ALFormat.Stereo8, ALFormat.Stereo16. + /// The audio buffer. + /// The size of the audio buffer in bytes. + /// The frequency of the audio buffer. + public static void BufferData(int bid, ALFormat format, TBuffer[] buffer, int size, int freq) + where TBuffer : struct + { + if (!BlittableValueType.Check(buffer)) + throw new ArgumentException("buffer"); + + GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try { BufferData(bid, format, handle.AddrOfPinnedObject(), size, freq); } + finally { handle.Free(); } + } + + #endregion BufferData + + #endregion Buffer objects + + #region Set Buffer parameters (currently parameters can only be read) + + /* + Remarks (from Manual) + * There are no relevant buffer properties defined in OpenAL 1.1 which can be affected by this call, + * but this function may be used by OpenAL extensions. + + // AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ); + // AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ); + // AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value ); + // AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); + // AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ); + // AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + */ + + /* + [DllImport( Al.Lib, EntryPoint = "alBuffer3f", ExactSpelling = true, CallingConvention = Al.Style ), SuppressUnmanagedCodeSecurity( )] + public static extern void Buffer3f( uint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + + public static void Bufferv3( uint bid, Alenum param, ref Vector3 values ) + { + Buffer3f( bid, param, values.X, values.Y, values.Z ); + }*/ + + #endregion Set Buffer parameters + + #region Get Buffer parameters + + #region GetBufferi + + /// This function retrieves an integer property of a buffer. + /// Buffer name whose attribute is being retrieved + /// The name of the attribute to be retrieved: ALGetBufferi.Frequency, Bits, Channels, Size, and the currently hidden AL_DATA (dangerous). + /// A pointer to an int to hold the retrieved buffer + [CLSCompliant(false), DllImport(AL.Lib, EntryPoint = "alGetBufferi", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void GetBuffer(uint bid, ALGetBufferi param, [Out] out int value); + // AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ); + + /// This function retrieves an integer property of a buffer. + /// Buffer name whose attribute is being retrieved + /// The name of the attribute to be retrieved: ALGetBufferi.Frequency, Bits, Channels, Size, and the currently hidden AL_DATA (dangerous). + /// A pointer to an int to hold the retrieved buffer + public static void GetBuffer(int bid, ALGetBufferi param, out int value) + { + GetBuffer((uint)bid, param, out value); + } + + #endregion GetBufferi + + // AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ); + // AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + // AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ); + // AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + // AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ); + + #endregion Get Buffer parameters + + #region Global Parameters + + /// AL.DopplerFactor is a simple scaling of source and listener velocities to exaggerate or deemphasize the Doppler (pitch) shift resulting from the calculation. + /// A negative value will result in an error, the command is then ignored. The default value is 1f. The current setting can be queried using AL.Get with parameter ALGetFloat.SpeedOfSound. + [DllImport(AL.Lib, EntryPoint = "alDopplerFactor", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void DopplerFactor(float value); + // AL_API void AL_APIENTRY alDopplerFactor( ALfloat value ); + + /// This function is deprecated and should not be used. + /// The default is 1.0f. + [DllImport(AL.Lib, EntryPoint = "alDopplerVelocity", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void DopplerVelocity(float value); + // AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value ); + + /// AL.SpeedOfSound allows the application to change the reference (propagation) speed used in the Doppler calculation. The source and listener velocities should be expressed in the same units as the speed of sound. + /// A negative or zero value will result in an error, and the command is ignored. Default: 343.3f (appropriate for velocity units of meters and air as the propagation medium). The current setting can be queried using AL.Get with parameter ALGetFloat.SpeedOfSound. + [DllImport(AL.Lib, EntryPoint = "alSpeedOfSound", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void SpeedOfSound(float value); + // AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value ); + + /// This function selects the OpenAL distance model – ALDistanceModel.InverseDistance, ALDistanceModel.InverseDistanceClamped, ALDistanceModel.LinearDistance, ALDistanceModel.LinearDistanceClamped, ALDistanceModel.ExponentDistance, ALDistanceModel.ExponentDistanceClamped, or ALDistanceModel.None. The default distance model in OpenAL is ALDistanceModel.InverseDistanceClamped. + /// + /// The ALDistanceModel .InverseDistance model works according to the following formula: + /// gain = ALSourcef.ReferenceDistance / (ALSourcef.ReferenceDistance + ALSourcef.RolloffFactor * (distance – ALSourcef.ReferenceDistance)); + /// + /// The ALDistanceModel .InverseDistanceClamped model works according to the following formula: + /// distance = max(distance,ALSourcef.ReferenceDistance); + /// distance = min(distance,ALSourcef.MaxDistance); + /// gain = ALSourcef.ReferenceDistance / (ALSourcef.ReferenceDistance + ALSourcef.RolloffFactor * (distance – ALSourcef.ReferenceDistance)); + /// + /// The ALDistanceModel.LinearDistance model works according to the following formula: + /// distance = min(distance, ALSourcef.MaxDistance) // avoid negative gain + /// gain = (1 – ALSourcef.RolloffFactor * (distance – ALSourcef.ReferenceDistance) / (ALSourcef.MaxDistance – ALSourcef.ReferenceDistance)) + /// + /// The ALDistanceModel.LinearDistanceClamped model works according to the following formula: + /// distance = max(distance, ALSourcef.ReferenceDistance) + /// distance = min(distance, ALSourcef.MaxDistance) + /// gain = (1 – ALSourcef.RolloffFactor * (distance – ALSourcef.ReferenceDistance) / (ALSourcef.MaxDistance – ALSourcef.ReferenceDistance)) + /// + /// The ALDistanceModel.ExponentDistance model works according to the following formula: + /// gain = (distance / ALSourcef.ReferenceDistance) ^ (- ALSourcef.RolloffFactor) + /// + /// The ALDistanceModel.ExponentDistanceClamped model works according to the following formula: + /// distance = max(distance, ALSourcef.ReferenceDistance) + /// distance = min(distance, ALSourcef.MaxDistance) + /// gain = (distance / ALSourcef.ReferenceDistance) ^ (- ALSourcef.RolloffFactor) + /// + /// The ALDistanceModel.None model works according to the following formula: + /// gain = 1f; + /// + /// + [DllImport(AL.Lib, EntryPoint = "alDistanceModel", ExactSpelling = true, CallingConvention = AL.Style), SuppressUnmanagedCodeSecurity()] + public static extern void DistanceModel(ALDistanceModel distancemodel); + // AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel ); + + #endregion Global Parameters + + #region Helpers + + /// (Helper) Returns Source state information. + /// The source to be queried. + /// state information from OpenAL. + [CLSCompliant(false)] + public static ALSourceState GetSourceState(uint sid) + { + int temp; + AL.GetSource(sid, ALGetSourcei.SourceState, out temp); + return (ALSourceState)temp; + } + + /// (Helper) Returns Source state information. + /// The source to be queried. + /// state information from OpenAL. + public static ALSourceState GetSourceState(int sid) + { + int temp; + AL.GetSource(sid, ALGetSourcei.SourceState, out temp); + return (ALSourceState)temp; + } + + /// (Helper) Returns Source type information. + /// The source to be queried. + /// type information from OpenAL. + [CLSCompliant(false)] + public static ALSourceType GetSourceType(uint sid) + { + int temp; + AL.GetSource(sid, ALGetSourcei.SourceType, out temp); + return (ALSourceType)temp; + } + + /// (Helper) Returns Source type information. + /// The source to be queried. + /// type information from OpenAL. + public static ALSourceType GetSourceType(int sid) + { + int temp; + AL.GetSource(sid, ALGetSourcei.SourceType, out temp); + return (ALSourceType)temp; + } + + /// + /// Returns the of the current context. + /// + /// The of the current context. + public static ALDistanceModel GetDistanceModel() + { + return (ALDistanceModel)AL.Get(ALGetInteger.DistanceModel); + } + + #endregion Helpers + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Audio/OpenAL/AL/ALEnums.cs b/src/MiniTK/Audio/OpenAL/AL/ALEnums.cs new file mode 100644 index 0000000..e6c90be --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/ALEnums.cs @@ -0,0 +1,431 @@ +#region --- OpenTK.OpenAL License --- +/* AlTokens.cs + * C header: \OpenAL 1.1 SDK\include\Al.h + * Spec: http://www.openal.org/openal_webstf/specs/OpenAL11Specification.pdf + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; + +namespace OpenTK.Audio.OpenAL +{ + + ///A list of valid Enable/Disable/IsEnabled parameters + public enum ALCapability : int + { + ///Currently no state toggles exist for vanilla OpenAL and no Extension uses it. + Invalid = -1, + } + + ///A list of valid 32-bit Float Listener/GetListener parameters + public enum ALListenerf : int + { + ///Indicate the gain (Volume amplification) applied. Type: float Range: [0.0f - ? ] A value of 1.0 means un-attenuated/unchanged. Each division by 2 equals an attenuation of -6dB. Each multiplicaton with 2 equals an amplification of +6dB. A value of 0.0f is interpreted as zero volume and the channel is effectively disabled. + Gain = 0x100A, + + ///(EFX Extension) This setting is critical if Air Absorption effects are enabled because the amount of Air Absorption applied is directly related to the real-world distance between the Source and the Listener. centimeters 0.01f meters 1.0f kilometers 1000.0f Range [float.MinValue .. float.MaxValue] Default: 1.0f + EfxMetersPerUnit = 0x20004, + } + + ///A list of valid Math.Vector3 Listener/GetListener parameters + public enum ALListener3f : int + { + ///Specify the current location in three dimensional space. OpenAL, like OpenGL, uses a right handed coordinate system, where in a frontal default view X (thumb) points right, Y points up (index finger), and Z points towards the viewer/camera (middle finger). To switch from a left handed coordinate system, flip the sign on the Z coordinate. Listener position is always in the world coordinate system. + Position = 0x1004, + + ///Specify the current velocity in three dimensional space. + Velocity = 0x1006, + } + + ///A list of valid float[] Listener/GetListener parameters + public enum ALListenerfv : int + { + ///Indicate Listener orientation. Expects two Vector3, At followed by Up. + Orientation = 0x100F, + } + + ///A list of valid 32-bit Float Source/GetSource parameters + public enum ALSourcef : int + { + ///Source specific reference distance. Type: float Range: [0.0f - float.PositiveInfinity] At 0.0f, no distance attenuation occurs. Type: float Default: 1.0f. + ReferenceDistance = 0x1020, + + ///Indicate distance above which Sources are not attenuated using the inverse clamped distance model. Default: float.PositiveInfinity Type: float Range: [0.0f - float.PositiveInfinity] + MaxDistance = 0x1023, + + ///Source specific rolloff factor. Type: float Range: [0.0f - float.PositiveInfinity] + RolloffFactor = 0x1021, + + ///Specify the pitch to be applied, either at Source, or on mixer results, at Listener. Range: [0.5f - 2.0f] Default: 1.0f + Pitch = 0x1003, + + ///Indicate the gain (volume amplification) applied. Type: float. Range: [0.0f - ? ] A value of 1.0 means un-attenuated/unchanged. Each division by 2 equals an attenuation of -6dB. Each multiplicaton with 2 equals an amplification of +6dB. A value of 0.0f is meaningless with respect to a logarithmic scale; it is interpreted as zero volume - the channel is effectively disabled. + Gain = 0x100A, + + ///Indicate minimum Source attenuation. Type: float Range: [0.0f - 1.0f] (Logarthmic) + MinGain = 0x100D, + + ///Indicate maximum Source attenuation. Type: float Range: [0.0f - 1.0f] (Logarthmic) + MaxGain = 0x100E, + + ///Directional Source, inner cone angle, in degrees. Range: [0-360] Default: 360 + ConeInnerAngle = 0x1001, + + ///Directional Source, outer cone angle, in degrees. Range: [0-360] Default: 360 + ConeOuterAngle = 0x1002, + + ///Directional Source, outer cone gain. Default: 0.0f Range: [0.0f - 1.0] (Logarithmic) + ConeOuterGain = 0x1022, + + /// The playback position, expressed in seconds. + SecOffset = 0x1024, // AL_EXT_OFFSET extension. + + ///(EFX Extension) This property is a multiplier on the amount of Air Absorption applied to the Source. The AL_AIR_ABSORPTION_FACTOR is multiplied by an internal Air Absorption Gain HF value of 0.994 (-0.05dB) per meter which represents normal atmospheric humidity and temperature. Range [0.0f .. 10.0f] Default: 0.0f + EfxAirAbsorptionFactor = 0x20007, + + ///(EFX Extension) This property is defined the same way as the Reverb Room Rolloff property: it is one of two methods available in the Effect Extension to attenuate the reflected sound (early reflections and reverberation) according to source-listener distance. Range [0.0f .. 10.0f] Default: 0.0f + EfxRoomRolloffFactor = 0x20008, + + ///(EFX Extension) A directed Source points in a specified direction. The Source sounds at full volume when the listener is directly in front of the source; it is attenuated as the listener circles the Source away from the front. Range [0.0f .. 1.0f] Default: 1.0f + EfxConeOuterGainHighFrequency = 0x20009, + + } + + ///A list of valid Math.Vector3 Source/GetSource parameters + public enum ALSource3f : int + { + ///Specify the current location in three dimensional space. OpenAL, like OpenGL, uses a right handed coordinate system, where in a frontal default view X (thumb) points right, Y points up (index finger), and Z points towards the viewer/camera (middle finger). To switch from a left handed coordinate system, flip the sign on the Z coordinate. Listener position is always in the world coordinate system. + Position = 0x1004, + + ///Specify the current velocity in three dimensional space. + Velocity = 0x1006, + + ///Specify the current direction vector. + Direction = 0x1005, + } + + ///A list of valid 8-bit boolean Source/GetSource parameters + public enum ALSourceb : int + { + ///Indicate that the Source has relative coordinates. Type: bool Range: [True, False] + SourceRelative = 0x202, + + ///Indicate whether the Source is looping. Type: bool Range: [True, False] Default: False. + Looping = 0x1007, + + ///(EFX Extension) If this Source property is set to True, this Source’s direct-path is automatically filtered according to the orientation of the source relative to the listener and the setting of the Source property Sourcef.ConeOuterGainHF. Type: bool Range [False, True] Default: True + EfxDirectFilterGainHighFrequencyAuto = 0x2000A, + + ///(EFX Extension) If this Source property is set to True, the intensity of this Source’s reflected sound is automatically attenuated according to source-listener distance and source directivity (as determined by the cone parameters). If it is False, the reflected sound is not attenuated according to distance and directivity. Type: bool Range [False, True] Default: True + EfxAuxiliarySendFilterGainAuto = 0x2000B, + + ///(EFX Extension) If this Source property is AL_TRUE (its default value), the intensity of this Source’s reflected sound at high frequencies will be automatically attenuated according to the high-frequency source directivity as set by the Sourcef.ConeOuterGainHF property. If this property is AL_FALSE, the Source’s reflected sound is not filtered at all according to the Source’s directivity. Type: bool Range [False, True] Default: True + EfxAuxiliarySendFilterGainHighFrequencyAuto = 0x2000C, + } + + ///A list of valid Int32 Source parameters + public enum ALSourcei : int + { + ///The playback position, expressed in bytes. + ByteOffset = 0x1026, // AL_EXT_OFFSET extension. + + ///The playback position, expressed in samples. + SampleOffset = 0x1025, // AL_EXT_OFFSET extension. + + ///Indicate the Buffer to provide sound samples. Type: uint Range: any valid Buffer Handle. + Buffer = 0x1009, + + ///Source type (Static, Streaming or undetermined). Use enum AlSourceType for comparison + SourceType = 0x1027, + + ///(EFX Extension) This Source property is used to apply filtering on the direct-path (dry signal) of a Source. + EfxDirectFilter = 0x20005, + } + + ///A list of valid 3x Int32 Source/GetSource parameters + public enum ALSource3i : int + { + ///(EFX Extension) This Source property is used to establish connections between Sources and Auxiliary Effect Slots. For a Source to feed an Effect that has been loaded into an Auxiliary Effect Slot the application must configure one of the Source’s auxiliary sends. This process involves setting 3 variables – the destination Auxiliary Effect Slot ID, the Auxiliary Send number, and an optional Filter ID. Type: uint Range: any valid Filter Handle. + EfxAuxiliarySendFilter = 0x20006, + } + + ///A list of valid Int32 GetSource parameters + public enum ALGetSourcei : int + { + ///The playback position, expressed in bytes. AL_EXT_OFFSET Extension. + ByteOffset = 0x1026, + + ///The playback position, expressed in samples. AL_EXT_OFFSET Extension. + SampleOffset = 0x1025, + + ///Indicate the Buffer to provide sound samples. Type: uint Range: any valid Buffer Handle. + Buffer = 0x1009, + + /// The state of the source (Stopped, Playing, etc.) Use the enum AlSourceState for comparison. + SourceState = 0x1010, + + /// The number of buffers queued on this source. + BuffersQueued = 0x1015, + + /// The number of buffers in the queue that have been processed. + BuffersProcessed = 0x1016, + + ///Source type (Static, Streaming or undetermined). Use enum AlSourceType for comparison. + SourceType = 0x1027, + } + + /* + public enum ALDeprecated : int + { + ///Deprecated. Specify the channel mask. (Creative) Type: uint Range: [0 - 255] + ChannelMask = 0x3000, + } + */ + + ///Source state information, can be retrieved by AL.Source() with ALSourcei.SourceState. + public enum ALSourceState : int + { + ///Default State when loaded, can be manually set with AL.SourceRewind(). + Initial = 0x1011, + + ///The source is currently playing. + Playing = 0x1012, + + ///The source has paused playback. + Paused = 0x1013, + + ///The source is not playing. + Stopped = 0x1014, + } + + ///Source type information, can be retrieved by AL.Source() with ALSourcei.SourceType. + public enum ALSourceType : int + { + ///Source is Static if a Buffer has been attached using AL.Source with the parameter Sourcei.Buffer. + Static = 0x1028, + + ///Source is Streaming if one or more Buffers have been attached using AL.SourceQueueBuffers + Streaming = 0x1029, + + ///Source is undetermined when it has a null Buffer attached + Undetermined = 0x1030, + } + + ///Sound samples: Format specifier. + public enum ALFormat : int + { + ///1 Channel, 8 bits per sample. + Mono8 = 0x1100, + + ///1 Channel, 16 bits per sample. + Mono16 = 0x1101, + + ///2 Channels, 8 bits per sample each. + Stereo8 = 0x1102, + + ///2 Channels, 16 bits per sample each. + Stereo16 = 0x1103, + + /// 1 Channel, A-law encoded data. Requires Extension: AL_EXT_ALAW + MonoALawExt = 0x10016, + + /// 2 Channels, A-law encoded data. Requires Extension: AL_EXT_ALAW + StereoALawExt = 0x10017, + + /// 1 Channel, µ-law encoded data. Requires Extension: AL_EXT_MULAW + MonoMuLawExt = 0x10014, + + /// 2 Channels, µ-law encoded data. Requires Extension: AL_EXT_MULAW + StereoMuLawExt = 0x10015, + + /// Ogg Vorbis encoded data. Requires Extension: AL_EXT_vorbis + VorbisExt = 0x10003, + + /// MP3 encoded data. Requires Extension: AL_EXT_mp3 + Mp3Ext = 0x10020, + + /// 1 Channel, IMA4 ADPCM encoded data. Requires Extension: AL_EXT_IMA4 + MonoIma4Ext = 0x1300, + + /// 2 Channels, IMA4 ADPCM encoded data. Requires Extension: AL_EXT_IMA4 + StereoIma4Ext = 0x1301, + + /// 1 Channel, single-precision floating-point data. Requires Extension: AL_EXT_float32 + MonoFloat32Ext = 0x10010, + + /// 2 Channels, single-precision floating-point data. Requires Extension: AL_EXT_float32 + StereoFloat32Ext = 0x10011, + + /// 1 Channel, double-precision floating-point data. Requires Extension: AL_EXT_double + MonoDoubleExt = 0x10012, + + /// 2 Channels, double-precision floating-point data. Requires Extension: AL_EXT_double + StereoDoubleExt = 0x10013, + + /// Multichannel 5.1, 16-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi51Chn16Ext = 0x120B, + + /// Multichannel 5.1, 32-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi51Chn32Ext = 0x120C, + + /// Multichannel 5.1, 8-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi51Chn8Ext = 0x120A, + + /// Multichannel 6.1, 16-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi61Chn16Ext = 0x120E, + + /// Multichannel 6.1, 32-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi61Chn32Ext = 0x120F, + + /// Multichannel 6.1, 8-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi61Chn8Ext = 0x120D, + + /// Multichannel 7.1, 16-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi71Chn16Ext = 0x1211, + + /// Multichannel 7.1, 32-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi71Chn32Ext = 0x1212, + + /// Multichannel 7.1, 8-bit data. Requires Extension: AL_EXT_MCFORMATS + Multi71Chn8Ext = 0x1210, + + /// Multichannel 4.0, 16-bit data. Requires Extension: AL_EXT_MCFORMATS + MultiQuad16Ext = 0x1205, + + /// Multichannel 4.0, 32-bit data. Requires Extension: AL_EXT_MCFORMATS + MultiQuad32Ext = 0x1206, + + /// Multichannel 4.0, 8-bit data. Requires Extension: AL_EXT_MCFORMATS + MultiQuad8Ext = 0x1204, + + /// 1 Channel rear speaker, 16-bit data. See Quadrophonic setups. Requires Extension: AL_EXT_MCFORMATS + MultiRear16Ext = 0x1208, + + /// 1 Channel rear speaker, 32-bit data. See Quadrophonic setups. Requires Extension: AL_EXT_MCFORMATS + MultiRear32Ext = 0x1209, + + /// 1 Channel rear speaker, 8-bit data. See Quadrophonic setups. Requires Extension: AL_EXT_MCFORMATS + MultiRear8Ext = 0x1207, + } + + ///A list of valid Int32 GetBuffer parameters + public enum ALGetBufferi : int + { + ///Sound sample's frequency, in units of hertz [Hz]. This is the number of samples per second. Half of the sample frequency marks the maximum significant frequency component. + Frequency = 0x2001, + + /// Bit depth of the buffer. Should be 8 or 16. + Bits = 0x2002, + + /// Number of channels in buffer. > 1 is valid, but buffer won’t be positioned when played. 1 for Mono, 2 for Stereo. + Channels = 0x2003, + + /// size of the Buffer in bytes. + Size = 0x2004, + + // Deprecated: From Manual, not in header: AL_DATA ( i, iv ) original location where buffer was copied from generally useless, as was probably freed after buffer creation + } + + ///Buffer state. Not supported for public use (yet). + public enum ALBufferState : int + { + ///Buffer state. Not supported for public use (yet). + Unused = 0x2010, + + ///Buffer state. Not supported for public use (yet). + Pending = 0x2011, + + ///Buffer state. Not supported for public use (yet). + Processed = 0x2012, + } + + /// Returned by AL.GetError + public enum ALError : int + { + ///No OpenAL Error. + NoError = 0, + + ///Invalid Name paramater passed to OpenAL call. + InvalidName = 0xA001, + + ///Invalid parameter passed to OpenAL call. + IllegalEnum = 0xA002, + ///Invalid parameter passed to OpenAL call. + InvalidEnum = 0xA002, + + ///Invalid OpenAL enum parameter value. + InvalidValue = 0xA003, + + ///Illegal OpenAL call. + IllegalCommand = 0xA004, + ///Illegal OpenAL call. + InvalidOperation = 0xA004, + + ///No OpenAL memory left. + OutOfMemory = 0xA005, + } + + ///A list of valid string AL.Get() parameters + public enum ALGetString : int + { + /// Gets the Vendor name. + Vendor = 0xB001, + + /// Gets the driver version. + Version = 0xB002, + + /// Gets the renderer mode. + Renderer = 0xB003, + + /// Gets a list of all available Extensions, separated with spaces. + Extensions = 0xB004, + } + + ///A list of valid 32-bit Float AL.Get() parameters + public enum ALGetFloat : int + { + ///Doppler scale. Default 1.0f + DopplerFactor = 0xC000, + + ///Tweaks speed of propagation. This functionality is deprecated. + DopplerVelocity = 0xC001, + + ///Speed of Sound in units per second. Default: 343.3f + SpeedOfSound = 0xC003, + } + + ///A list of valid Int32 AL.Get() parameters + public enum ALGetInteger : int + { + ///See enum ALDistanceModel. + DistanceModel = 0xD000, + } + + /// Used by AL.DistanceModel(), the distance model can be retrieved by AL.Get() with ALGetInteger.DistanceModel + public enum ALDistanceModel : int + { + ///Bypasses all distance attenuation calculation for all Sources. + None = 0, + + ///InverseDistance is equivalent to the IASIG I3DL2 model with the exception that ALSourcef.ReferenceDistance does not imply any clamping. + InverseDistance = 0xD001, + + ///InverseDistanceClamped is the IASIG I3DL2 model, with ALSourcef.ReferenceDistance indicating both the reference distance and the distance below which gain will be clamped. + InverseDistanceClamped = 0xD002, + + ///AL_EXT_LINEAR_DISTANCE extension. + LinearDistance = 0xD003, + + ///AL_EXT_LINEAR_DISTANCE extension. + LinearDistanceClamped = 0xD004, + + ///AL_EXT_EXPONENT_DISTANCE extension. + ExponentDistance = 0xD005, + + ///AL_EXT_EXPONENT_DISTANCE extension. + ExponentDistanceClamped = 0xD006, + } + +} diff --git a/src/MiniTK/Audio/OpenAL/AL/EffectsExtension.cs b/src/MiniTK/Audio/OpenAL/AL/EffectsExtension.cs new file mode 100644 index 0000000..c69249b --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/EffectsExtension.cs @@ -0,0 +1,1293 @@ +#region --- OpenTK.OpenAL License --- +/* EfxFunctions.cs + * C headers: \OpenAL 1.1 SDK\include\ "efx.h", "efx-creative.h", "Efx-Util.h" + * Spec: Effects Extension Guide.pdf (bundled with OpenAL SDK) + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK.Audio.OpenAL +{ + /// + /// Provides access to the OpenAL effects extension. + /// + public partial class EffectsExtension + { + #region Helpers + + #region BindEffect + + /// (Helper) Selects the Effect type used by this Effect handle. + /// Effect id returned from a successful call to GenEffects. + /// Effect type. + [CLSCompliant(false)] + public void BindEffect(uint eid, EfxEffectType type) + { + Imported_alEffecti(eid, EfxEffecti.EffectType, (int)type); + } + + /// (Helper) Selects the Effect type used by this Effect handle. + /// Effect id returned from a successful call to GenEffects. + /// Effect type. + + public void BindEffect(int eid, EfxEffectType type) + { + Imported_alEffecti((uint)eid, EfxEffecti.EffectType, (int)type); + } + + #endregion BindEffect + + #region BindFilterToSource + + /// (Helper) reroutes the output of a Source through a Filter. + /// A valid Source handle. + /// A valid Filter handle. + [CLSCompliant(false)] + public void BindFilterToSource(uint source, uint filter) + { + AL.Source(source, ALSourcei.EfxDirectFilter, (int)filter); + } + + /// (Helper) reroutes the output of a Source through a Filter. + /// A valid Source handle. + /// A valid Filter handle. + + public void BindFilterToSource(int source, int filter) + { + AL.Source((uint)source, ALSourcei.EfxDirectFilter, (int)filter); + } + + #endregion BindFilterToSource + + #region BindEffectToAuxiliarySlot + + /// (Helper) Attaches an Effect to an Auxiliary Effect Slot. + /// The slot handle to attach the Effect to. + /// The Effect handle that is being attached. + [CLSCompliant(false)] + public void BindEffectToAuxiliarySlot(uint auxiliaryeffectslot, uint effect) + { + AuxiliaryEffectSlot(auxiliaryeffectslot, EfxAuxiliaryi.EffectslotEffect, (int)effect); + } + + /// (Helper) Attaches an Effect to an Auxiliary Effect Slot. + /// The slot handle to attach the Effect to. + /// The Effect handle that is being attached. + + public void BindEffectToAuxiliarySlot(int auxiliaryeffectslot, int effect) + { + AuxiliaryEffectSlot((uint)auxiliaryeffectslot, EfxAuxiliaryi.EffectslotEffect, (int)effect); + } + + #endregion BindEffectToAuxiliarySlot + + #region BindSourceToAuxiliarySlot + + /// (Helper) Reroutes a Source's output into an Auxiliary Effect Slot. + /// The Source handle who's output is forwarded. + /// The Auxiliary Effect Slot handle that receives input from the Source. + /// Every Source has only a limited number of slots it can feed buffer to. The number must stay below AlcContextAttributes.EfxMaxAuxiliarySends + /// Filter handle to be attached between Source ouput and Auxiliary Slot input. Use 0 or EfxFilterType.FilterNull for no filter. + [CLSCompliant(false)] + public void BindSourceToAuxiliarySlot(uint source, uint slot, int slotnumber, uint filter) + { + AL.Source(source, ALSource3i.EfxAuxiliarySendFilter, (int)slot, (int)slotnumber, (int)filter); + } + + /// (Helper) Reroutes a Source's output into an Auxiliary Effect Slot. + /// The Source handle who's output is forwarded. + /// The Auxiliary Effect Slot handle that receives input from the Source. + /// Every Source has only a limited number of slots it can feed buffer to. The number must stay below AlcContextAttributes.EfxMaxAuxiliarySends + /// Filter handle to be attached between Source ouput and Auxiliary Slot input. Use 0 or EfxFilterType.FilterNull for no filter. + + public void BindSourceToAuxiliarySlot(int source, int slot, int slotnumber, int filter) + { + AL.Source((uint)source, ALSource3i.EfxAuxiliarySendFilter, (int)slot, (int)slotnumber, (int)filter); + } + + #endregion BindSourceToAuxiliarySlot + + #endregion Helpers + + #region Effect Object + + #region alGenEffects + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGenEffects(int n, [Out] uint* effects); + // typedef void (__cdecl *LPALGENEFFECTS)( ALsizei n, ALuint* effects ); + + //[CLSCompliant(false)] + private Delegate_alGenEffects Imported_alGenEffects; + + /// The GenEffects function is used to create one or more Effect objects. An Effect object stores an effect type and a set of parameter values to control that Effect. In order to use an Effect it must be attached to an Auxiliary Effect Slot object + /// After creation an Effect has no type (EfxEffectType.Null), so before it can be used to store a set of parameters, the application must specify what type of effect should be stored in the object, using Effect() with EfxEffecti. + /// Number of Effects to be created. + /// Pointer addressing sufficient memory to store n Effect object identifiers. + [CLSCompliant(false)] + public void GenEffects(int n, out uint effects) + { + unsafe + { + fixed (uint* ptr = &effects) + { + Imported_alGenEffects(n, ptr); + effects = *ptr; + } + } + } + + /// The GenEffects function is used to create one or more Effect objects. An Effect object stores an effect type and a set of parameter values to control that Effect. In order to use an Effect it must be attached to an Auxiliary Effect Slot object + /// After creation an Effect has no type (EfxEffectType.Null), so before it can be used to store a set of parameters, the application must specify what type of effect should be stored in the object, using Effect() with EfxEffecti. + /// Number of Effects to be created. + /// Pointer addressing sufficient memory to store n Effect object identifiers. + public void GenEffects(int n, out int effects) + { + unsafe + { + fixed (int* ptr = &effects) + { + Imported_alGenEffects(n, (uint*)ptr); + effects = *ptr; + } + } + } + + /// Generates one or more effect objects. + /// Number of Effect object identifiers to generate. + /// + /// The GenEffects function is used to create one or more Effect objects. An Effect object stores an effect type and a set of parameter values to control that Effect. In order to use an Effect it must be attached to an Auxiliary Effect Slot object. + /// After creation an Effect has no type (EfxEffectType.Null), so before it can be used to store a set of parameters, the application must specify what type of effect should be stored in the object, using Effect() with EfxEffecti. + /// + public int[] GenEffects(int n) + { + if (n <= 0) throw new ArgumentOutOfRangeException("n", "Must be higher than 0."); + int[] effects = new int[n]; + GenEffects(n, out effects[0]); + return effects; + } + + /// Generates a single effect object. + /// A handle to the generated effect object. + /// + /// The GenEffects function is used to create one or more Effect objects. An Effect object stores an effect type and a set of parameter values to control that Effect. In order to use an Effect it must be attached to an Auxiliary Effect Slot object. + /// After creation an Effect has no type (EfxEffectType.Null), so before it can be used to store a set of parameters, the application must specify what type of effect should be stored in the object, using Effect() with EfxEffecti. + /// + public int GenEffect() + { + int temp; + GenEffects(1, out temp); + return temp; + } + + /// Generates a single effect object. + /// A handle to the generated effect object. + [CLSCompliant(false)] + public void GenEffect(out uint effect) + { + unsafe + { + fixed (uint* ptr = &effect) + { + Imported_alGenEffects(1, ptr); + effect = *ptr; + } + } + + } + + #endregion alGenEffects + + #region alDeleteEffects + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alDeleteEffects(int n, [In] uint* effects); + // typedef void (__cdecl *LPALDELETEEFFECTS)( ALsizei n, ALuint* effects ); + + //[CLSCompliant(false)] + private Delegate_alDeleteEffects Imported_alDeleteEffects; + + /// The DeleteEffects function is used to delete and free resources for Effect objects previously created with GenEffects. + /// Number of Effects to be deleted. + /// Pointer to n Effect object identifiers. + [CLSCompliant(false)] + public void DeleteEffects(int n, ref uint effects) + { + unsafe + { + fixed (uint* ptr = &effects) + { + Imported_alDeleteEffects(n, ptr); + } + } + } + + /// The DeleteEffects function is used to delete and free resources for Effect objects previously created with GenEffects. + /// Number of Effects to be deleted. + /// Pointer to n Effect object identifiers. + public void DeleteEffects(int n, ref int effects) + { + unsafe + { + fixed (int* ptr = &effects) + { + Imported_alDeleteEffects(n, (uint*)ptr); + } + } + } + + /// The DeleteEffects function is used to delete and free resources for Effect objects previously created with GenEffects. + /// Pointer to n Effect object identifiers. + public void DeleteEffects(int[] effects) + { + if (effects == null) throw new ArgumentNullException("effects"); + DeleteEffects(effects.Length, ref effects[0]); + } + + /// The DeleteEffects function is used to delete and free resources for Effect objects previously created with GenEffects. + /// Pointer to n Effect object identifiers. + [CLSCompliant(false)] + public void DeleteEffects(uint[] effects) + { + if (effects == null) throw new ArgumentNullException("effects"); + DeleteEffects(effects.Length, ref effects[0]); + } + + /// This function deletes one Effect only. + /// Pointer to an effect name/handle identifying the Effect Object to be deleted. + public void DeleteEffect(int effect) + { + DeleteEffects(1, ref effect); + } + + /// This function deletes one Effect only. + /// Pointer to an effect name/handle identifying the Effect Object to be deleted. + [CLSCompliant(false)] + public void DeleteEffect(ref uint effect) + { + unsafe + { + fixed (uint* ptr = &effect) + { + Imported_alDeleteEffects(1, ptr); + } + } + } + + #endregion alDeleteEffects + + #region alIsEffect + + //[CLSCompliant(false)] + private delegate bool Delegate_alIsEffect(uint eid); + // typedef ALboolean (__cdecl *LPALISEFFECT)( ALuint eid ); + + //[CLSCompliant(false)] + private Delegate_alIsEffect Imported_alIsEffect; + + /// The IsEffect function is used to determine if an object identifier is a valid Effect object. + /// Effect identifier to validate. + /// True if the identifier is a valid Effect, False otherwise. + [CLSCompliant(false)] + public bool IsEffect(uint eid) + { + return Imported_alIsEffect(eid); + } + + /// The IsEffect function is used to determine if an object identifier is a valid Effect object. + /// Effect identifier to validate. + /// True if the identifier is a valid Effect, False otherwise. + + public bool IsEffect(int eid) + { + return Imported_alIsEffect((uint)eid); + } + + #endregion alIsEffect + + #region alEffecti + + //[CLSCompliant(false)] + private delegate void Delegate_alEffecti(uint eid, EfxEffecti param, int value); + // typedef void (__cdecl *LPALEFFECTI)( ALuint eid, ALenum param, ALint value); + + //[CLSCompliant(false)] + private Delegate_alEffecti Imported_alEffecti; + + /// This function is used to set integer properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Integer value. + [CLSCompliant(false)] + public void Effect(uint eid, EfxEffecti param, int value) + { + Imported_alEffecti(eid, param, value); + } + + /// This function is used to set integer properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Integer value. + + public void Effect(int eid, EfxEffecti param, int value) + { + Imported_alEffecti((uint)eid, param, value); + } + + #endregion alEffecti + + #region alEffectf + + //[CLSCompliant(false)] + private delegate void Delegate_alEffectf(uint eid, EfxEffectf param, float value); + // typedef void (__cdecl *LPALEFFECTF)( ALuint eid, ALenum param, ALfloat value); + + //[CLSCompliant(false)] + private Delegate_alEffectf Imported_alEffectf; + + /// This function is used to set floating-point properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Floating-point value. + [CLSCompliant(false)] + public void Effect(uint eid, EfxEffectf param, float value) + { + Imported_alEffectf(eid, param, value); + } + + /// This function is used to set floating-point properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Floating-point value. + + public void Effect(int eid, EfxEffectf param, float value) + { + Imported_alEffectf((uint)eid, param, value); + } + + #endregion alEffectf + + #region alEffectfv + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alEffectfv(uint eid, EfxEffect3f param, [In] float* values); + // typedef void (__cdecl *LPALEFFECTFV)( ALuint eid, ALenum param, ALfloat* values ); + + //[CLSCompliant(false)] + private Delegate_alEffectfv Imported_alEffectfv; + + /// This function is used to set 3 floating-point properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Pointer to Math.Vector3. + [CLSCompliant(false)] + public void Effect(uint eid, EfxEffect3f param, ref Vector3 values) + { + unsafe + { + fixed (float* ptr = &values.X) + { + Imported_alEffectfv(eid, param, ptr); + } + } + } + + /// This function is used to set 3 floating-point properties on Effect objects. + /// Effect object identifier. + /// Effect property to set. + /// Pointer to Math.Vector3. + + public void Effect(int eid, EfxEffect3f param, ref Vector3 values) + { + Effect((uint)eid, param, ref values); + } + + #endregion alEffectfv + + #region alGetEffecti + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetEffecti(uint eid, EfxEffecti pname, [Out] int* value); + // typedef void (__cdecl *LPALGETEFFECTI)( ALuint eid, ALenum pname, ALint* value ); + + //[CLSCompliant(false)] + private Delegate_alGetEffecti Imported_alGetEffecti; + + /// This function is used to retrieve integer properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// Address where integer value will be stored. + [CLSCompliant(false)] + public void GetEffect(uint eid, EfxEffecti pname, out int value) + { + unsafe + { + fixed (int* ptr = &value) + { + Imported_alGetEffecti(eid, pname, ptr); + } + } + } + + /// This function is used to retrieve integer properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// Address where integer value will be stored. + + public void GetEffect(int eid, EfxEffecti pname, out int value) + { + GetEffect((uint)eid, pname, out value); + } + + #endregion alGetEffecti + + #region alGetEffectf + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetEffectf(uint eid, EfxEffectf pname, [Out]float* value); + // typedef void (__cdecl *LPALGETEFFECTF)( ALuint eid, ALenum pname, ALfloat* value ); + + //[CLSCompliant(false)] + private Delegate_alGetEffectf Imported_alGetEffectf; + + /// This function is used to retrieve floating-point properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// Address where floating-point value will be stored. + [CLSCompliant(false)] + public void GetEffect(uint eid, EfxEffectf pname, out float value) + { + unsafe + { + fixed (float* ptr = &value) + { + Imported_alGetEffectf(eid, pname, ptr); + } + } + } + + /// This function is used to retrieve floating-point properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// Address where floating-point value will be stored. + + public void GetEffect(int eid, EfxEffectf pname, out float value) + { + GetEffect((uint)eid, pname, out value); + } + + #endregion alGetEffectf + + #region alGetEffectfv + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetEffectfv(uint eid, EfxEffect3f param, [Out] float* values); + // typedef void (__cdecl *LPALGETEFFECTFV)( ALuint eid, ALenum pname, ALfloat* values ); + + //[CLSCompliant(false)] + private Delegate_alGetEffectfv Imported_alGetEffectfv; + + /// This function is used to retrieve 3 floating-point properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// A Math.Vector3 to hold the values. + [CLSCompliant(false)] + public void GetEffect(uint eid, EfxEffect3f param, out Vector3 values) + { + unsafe + { + fixed (float* ptr = &values.X) + { + Imported_alGetEffectfv(eid, param, ptr); + values.X = ptr[0]; + values.Y = ptr[1]; + values.Z = ptr[2]; + } + } + } + + /// This function is used to retrieve 3 floating-point properties from Effect objects. + /// Effect object identifier. + /// Effect property to retrieve. + /// A Math.Vector3 to hold the values. + + public void GetEffect(int eid, EfxEffect3f param, out Vector3 values) + { + GetEffect((uint)eid, param, out values); + } + + #endregion alGetEffectfv + + // Not used: + // typedef void (__cdecl *LPALEFFECTIV)( ALuint eid, ALenum param, ALint* values ); + // typedef void (__cdecl *LPALGETEFFECTIV)( ALuint eid, ALenum pname, ALint* values ); + + #endregion Effect Object + + #region Filter Object + + #region alGenFilters + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGenFilters(int n, [Out] uint* filters); + // typedef void (__cdecl *LPALGENFILTERS)( ALsizei n, ALuint* filters ); + + //[CLSCompliant(false)] + private Delegate_alGenFilters Imported_alGenFilters; + + /// The GenFilters function is used to create one or more Filter objects. A Filter object stores a filter type and a set of parameter values to control that Filter. Filter objects can be attached to Sources as Direct Filters or Auxiliary Send Filters. + /// After creation a Filter has no type (EfxFilterType.Null), so before it can be used to store a set of parameters, the application must specify what type of filter should be stored in the object, using Filter() with EfxFilteri. + /// Number of Filters to be created. + /// Pointer addressing sufficient memory to store n Filter object identifiers. + [CLSCompliant(false)] + public void GenFilters(int n, out uint filters) + { + unsafe + { + fixed (uint* ptr = &filters) + { + Imported_alGenFilters(n, ptr); + filters = *ptr; + } + } + } + + /// The GenFilters function is used to create one or more Filter objects. A Filter object stores a filter type and a set of parameter values to control that Filter. Filter objects can be attached to Sources as Direct Filters or Auxiliary Send Filters. + /// After creation a Filter has no type (EfxFilterType.Null), so before it can be used to store a set of parameters, the application must specify what type of filter should be stored in the object, using Filter() with EfxFilteri. + /// Number of Filters to be created. + /// Pointer addressing sufficient memory to store n Filter object identifiers. + public void GenFilters(int n, out int filters) + { + unsafe + { + fixed (int* ptr = &filters) + { + Imported_alGenFilters(n, (uint*)ptr); + filters = *ptr; + } + } + } + + + /// The GenFilters function is used to create one or more Filter objects. A Filter object stores a filter type and a set of parameter values to control that Filter. Filter objects can be attached to Sources as Direct Filters or Auxiliary Send Filters. + /// After creation a Filter has no type (EfxFilterType.Null), so before it can be used to store a set of parameters, the application must specify what type of filter should be stored in the object, using Filter() with EfxFilteri. + /// Number of Filters to be created. + /// Pointer addressing sufficient memory to store n Filter object identifiers. + public int[] GenFilters(int n) + { + + if (n <= 0) throw new ArgumentOutOfRangeException("n", "Must be higher than 0."); + int[] filters = new int[n]; + GenFilters(filters.Length, out filters[0]); + return filters; + } + + /// This function generates only one Filter. + /// Storage Int32 for the new filter name/handle. + public int GenFilter() + { + int filter; + GenFilters(1, out filter); + return filter; + } + + /// This function generates only one Filter. + /// Storage UInt32 for the new filter name/handle. + [CLSCompliant(false)] + unsafe public void GenFilter(out uint filter) + { + unsafe + { + fixed (uint* ptr = &filter) + { + Imported_alGenFilters(1, ptr); + filter = *ptr; + } + } + } + + #endregion alGenFilters + + #region alDeleteFilters + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alDeleteFilters(int n, [In] uint* filters); + // typedef void (__cdecl *LPALDELETEFILTERS)( ALsizei n, ALuint* filters ); + + //[CLSCompliant(false)] + private Delegate_alDeleteFilters Imported_alDeleteFilters; + + /// The DeleteFilters function is used to delete and free resources for Filter objects previously created with GenFilters. + /// Number of Filters to be deleted. + /// Pointer to n Filter object identifiers. + [CLSCompliant(false)] + public void DeleteFilters(int n, ref uint filters) + { + unsafe + { + fixed (uint* ptr = &filters) + { + Imported_alDeleteFilters(n, ptr); + } + } + } + + /// The DeleteFilters function is used to delete and free resources for Filter objects previously created with GenFilters. + /// Number of Filters to be deleted. + /// Pointer to n Filter object identifiers. + public void DeleteFilters(int n, ref int filters) + { + unsafe + { + fixed (int* ptr = &filters) + { + Imported_alDeleteFilters(n, (uint*)ptr); + } + } + } + + /// This function deletes one Filter only. + /// Pointer to an filter name/handle identifying the Filter Object to be deleted. + [CLSCompliant(false)] + public void DeleteFilters(uint[] filters) + { + if (filters == null) throw new ArgumentNullException("filters"); + DeleteFilters(filters.Length, ref filters[0]); + } + + /// This function deletes one Filter only. + /// Pointer to an filter name/handle identifying the Filter Object to be deleted. + public void DeleteFilters(int[] filters) + { + if (filters == null) throw new ArgumentNullException("filters"); + DeleteFilters(filters.Length, ref filters[0]); + } + + /// This function deletes one Filter only. + /// Pointer to an filter name/handle identifying the Filter Object to be deleted. + public void DeleteFilter(int filter) + { + DeleteFilters(1, ref filter); + } + + /// This function deletes one Filter only. + /// Pointer to an filter name/handle identifying the Filter Object to be deleted. + [CLSCompliant(false)] + public void DeleteFilter(ref uint filter) + { + unsafe + { + fixed (uint* ptr = &filter) + { + Imported_alDeleteFilters(1, ptr); + } + } + } + + #endregion alDeleteFilters + + #region alIsFilter + + //[CLSCompliant(false)] + private delegate bool Delegate_alIsFilter(uint fid); + // typedef ALboolean (__cdecl *LPALISFILTER)( ALuint fid ); + + //[CLSCompliant(false)] + private Delegate_alIsFilter Imported_alIsFilter; + + /// The IsFilter function is used to determine if an object identifier is a valid Filter object. + /// Effect identifier to validate. + /// True if the identifier is a valid Filter, False otherwise. + [CLSCompliant(false)] + public bool IsFilter(uint fid) + { + return Imported_alIsFilter(fid); + } + + /// The IsFilter function is used to determine if an object identifier is a valid Filter object. + /// Effect identifier to validate. + /// True if the identifier is a valid Filter, False otherwise. + + public bool IsFilter(int fid) + { + return Imported_alIsFilter((uint)fid); + } + + #endregion alIsFilter + + #region alFilteri + + //[CLSCompliant(false)] + private delegate void Delegate_alFilteri(uint fid, EfxFilteri param, int value); + // typedef void (__cdecl *LPALFILTERI)( ALuint fid, ALenum param, ALint value ); + + //[CLSCompliant(false)] + private Delegate_alFilteri Imported_alFilteri; + + /// This function is used to set integer properties on Filter objects. + /// Filter object identifier. + /// Effect property to set. + /// Integer value. + [CLSCompliant(false)] + public void Filter(uint fid, EfxFilteri param, int value) + { + Imported_alFilteri(fid, param, value); + } + + /// This function is used to set integer properties on Filter objects. + /// Filter object identifier. + /// Effect property to set. + /// Integer value. + + public void Filter(int fid, EfxFilteri param, int value) + { + Imported_alFilteri((uint)fid, param, value); + } + + #endregion alFilteri + + #region alFilterf + + //[CLSCompliant(false)] + private delegate void Delegate_alFilterf(uint fid, EfxFilterf param, float value); + // typedef void (__cdecl *LPALFILTERF)( ALuint fid, ALenum param, ALfloat value); + + //[CLSCompliant(false)] + private Delegate_alFilterf Imported_alFilterf; + + /// This function is used to set floating-point properties on Filter objects. + /// Filter object identifier. + /// Effect property to set. + /// Floating-point value. + [CLSCompliant(false)] + public void Filter(uint fid, EfxFilterf param, float value) + { + Imported_alFilterf(fid, param, value); + } + + /// This function is used to set floating-point properties on Filter objects. + /// Filter object identifier. + /// Effect property to set. + /// Floating-point value. + + public void Filter(int fid, EfxFilterf param, float value) + { + Imported_alFilterf((uint)fid, param, value); + } + + #endregion alFilterf + + #region alGetFilteri + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetFilteri(uint fid, EfxFilteri pname, [Out] int* value); + // typedef void (__cdecl *LPALGETFILTERI)( ALuint fid, ALenum pname, ALint* value ); + + //[CLSCompliant(false)] + private Delegate_alGetFilteri Imported_alGetFilteri; + + /// This function is used to retrieve integer properties from Filter objects. + /// Filter object identifier. + /// Effect property to retrieve. + /// Address where integer value will be stored. + [CLSCompliant(false)] + public void GetFilter(uint fid, EfxFilteri pname, out int value) + { + unsafe + { + fixed (int* ptr = &value) + { + Imported_alGetFilteri(fid, pname, ptr); + } + } + } + + /// This function is used to retrieve integer properties from Filter objects. + /// Filter object identifier. + /// Effect property to retrieve. + /// Address where integer value will be stored. + + public void GetFilter(int fid, EfxFilteri pname, out int value) + { + GetFilter((uint)fid, pname, out value); + } + + #endregion alGetFilteri + + #region alGetFilterf + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetFilterf(uint fid, EfxFilterf pname, [Out] float* value); + // typedef void (__cdecl *LPALGETFILTERF)( ALuint fid, ALenum pname, ALfloat* value ); + + //[CLSCompliant(false)] + private Delegate_alGetFilterf Imported_alGetFilterf; + + /// This function is used to retrieve floating-point properties from Filter objects. + /// Filter object identifier. + /// Effect property to retrieve. + /// Address where floating-point value will be stored. + [CLSCompliant(false)] + public void GetFilter(uint fid, EfxFilterf pname, out float value) + { + unsafe + { + fixed (float* ptr = &value) + { + Imported_alGetFilterf(fid, pname, ptr); + } + } + } + + /// This function is used to retrieve floating-point properties from Filter objects. + /// Filter object identifier. + /// Effect property to retrieve. + /// Address where floating-point value will be stored. + + public void GetFilter(int fid, EfxFilterf pname, out float value) + { + GetFilter((uint)fid, pname, out value); + } + + #endregion alGetFilterf + + // Not used: + // typedef void (__cdecl *LPALFILTERIV)( ALuint fid, ALenum param, ALint* values ); + // typedef void (__cdecl *LPALFILTERFV)( ALuint fid, ALenum param, ALfloat* values ); + // typedef void (__cdecl *LPALGETFILTERIV)( ALuint fid, ALenum pname, ALint* values ); + // typedef void (__cdecl *LPALGETFILTERFV)( ALuint fid, ALenum pname, ALfloat* values ); + + #endregion Filter Object + + #region Auxiliary Effect Slot Object + + #region alGenAuxiliaryEffectSlots + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGenAuxiliaryEffectSlots(int n, [Out] uint* slots); + // typedef void (__cdecl *LPALGENAUXILIARYEFFECTSLOTS)( ALsizei n, ALuint* slots ); + + //[CLSCompliant(false)] + private Delegate_alGenAuxiliaryEffectSlots Imported_alGenAuxiliaryEffectSlots; + + /// The GenAuxiliaryEffectSlots function is used to create one or more Auxiliary Effect Slots. The number of slots that can be created will be dependant upon the Open AL device used. + /// An application should check the OpenAL error state after making this call to determine if the Effect Slot was successfully created. If the function call fails then none of the requested Effect Slots are created. A good strategy for creating any OpenAL object is to use a for-loop and generate one object each loop iteration and then check for an error condition. If an error is set then the loop can be broken and the application can determine if sufficient resources are available. + /// Number of Auxiliary Effect Slots to be created. + /// Pointer addressing sufficient memory to store n Effect Slot object identifiers. + [CLSCompliant(false)] + public void GenAuxiliaryEffectSlots(int n, out uint slots) + { + unsafe + { + fixed (uint* ptr = &slots) + { + Imported_alGenAuxiliaryEffectSlots(n, ptr); + slots = *ptr; + } + } + } + + /// The GenAuxiliaryEffectSlots function is used to create one or more Auxiliary Effect Slots. The number of slots that can be created will be dependant upon the Open AL device used. + /// An application should check the OpenAL error state after making this call to determine if the Effect Slot was successfully created. If the function call fails then none of the requested Effect Slots are created. A good strategy for creating any OpenAL object is to use a for-loop and generate one object each loop iteration and then check for an error condition. If an error is set then the loop can be broken and the application can determine if sufficient resources are available. + /// Number of Auxiliary Effect Slots to be created. + /// Pointer addressing sufficient memory to store n Effect Slot object identifiers. + public void GenAuxiliaryEffectSlots(int n, out int slots) + { + unsafe + { + fixed (int* ptr = &slots) + { + Imported_alGenAuxiliaryEffectSlots(n, (uint*)ptr); + slots = *ptr; + } + } + } + + /// The GenAuxiliaryEffectSlots function is used to create one or more Auxiliary Effect Slots. The number of slots that can be created will be dependant upon the Open AL device used. + /// An application should check the OpenAL error state after making this call to determine if the Effect Slot was successfully created. If the function call fails then none of the requested Effect Slots are created. A good strategy for creating any OpenAL object is to use a for-loop and generate one object each loop iteration and then check for an error condition. If an error is set then the loop can be broken and the application can determine if sufficient resources are available. + /// Number of Auxiliary Effect Slots to be created. + /// Pointer addressing sufficient memory to store n Effect Slot object identifiers. + public int[] GenAuxiliaryEffectSlots(int n) + { + if (n <= 0) throw new ArgumentOutOfRangeException("n", "Must be higher than 0."); + int[] slots = new int[n]; + GenAuxiliaryEffectSlots(slots.Length, out slots[0]); + return slots; + } + + /// This function generates only one Auxiliary Effect Slot. + /// Storage Int32 for the new auxiliary effect slot name/handle. + public int GenAuxiliaryEffectSlot() + { + int temp; + GenAuxiliaryEffectSlots(1, out temp); + return temp; + } + + /// This function generates only one Auxiliary Effect Slot. + /// Storage UInt32 for the new auxiliary effect slot name/handle. + [CLSCompliant(false)] + public void GenAuxiliaryEffectSlot(out uint slot) + { + unsafe + { + fixed (uint* ptr = &slot) + { + Imported_alGenAuxiliaryEffectSlots(1, ptr); + slot = *ptr; + } + } + } + + #endregion alGenAuxiliaryEffectSlots + + #region DeleteAuxiliaryEffectSlots + + unsafe private delegate void Delegate_alDeleteAuxiliaryEffectSlots(int n, [In] uint* slots); + // typedef void (__cdecl *LPALDELETEAUXILIARYEFFECTSLOTS)( ALsizei n, ALuint* slots ); + + private Delegate_alDeleteAuxiliaryEffectSlots Imported_alDeleteAuxiliaryEffectSlots; + + /// The DeleteAuxiliaryEffectSlots function is used to delete and free resources for Auxiliary Effect Slots previously created with GenAuxiliaryEffectSlots. + /// Number of Auxiliary Effect Slots to be deleted. + /// Pointer to n Effect Slot object identifiers. + [CLSCompliant(false)] + public void DeleteAuxiliaryEffectSlots(int n, ref uint slots) + { + unsafe + { + fixed (uint* ptr = &slots) + { + Imported_alDeleteAuxiliaryEffectSlots(n, ptr); + } + } + } + + /// The DeleteAuxiliaryEffectSlots function is used to delete and free resources for Auxiliary Effect Slots previously created with GenAuxiliaryEffectSlots. + /// Number of Auxiliary Effect Slots to be deleted. + /// Pointer to n Effect Slot object identifiers. + public void DeleteAuxiliaryEffectSlots(int n, ref int slots) + { + unsafe + { + fixed (int* ptr = &slots) + { + Imported_alDeleteAuxiliaryEffectSlots(n, (uint*)ptr); + } + } + } + + /// The DeleteAuxiliaryEffectSlots function is used to delete and free resources for Auxiliary Effect Slots previously created with GenAuxiliaryEffectSlots. + /// Pointer to n Effect Slot object identifiers. + public void DeleteAuxiliaryEffectSlots(int[] slots) + { + if (slots == null) throw new ArgumentNullException("slots"); + DeleteAuxiliaryEffectSlots(slots.Length, ref slots[0]); + } + + /// This function deletes one AuxiliaryEffectSlot only. + /// Pointer to an auxiliary effect slot name/handle identifying the Auxiliary Effect Slot Object to be deleted. + [CLSCompliant(false)] + public void DeleteAuxiliaryEffectSlots(uint[] slots) + { + if (slots == null) throw new ArgumentNullException("slots"); + DeleteAuxiliaryEffectSlots(slots.Length, ref slots[0]); + } + + /// This function deletes one AuxiliaryEffectSlot only. + /// Pointer to an auxiliary effect slot name/handle identifying the Auxiliary Effect Slot Object to be deleted. + public void DeleteAuxiliaryEffectSlot(int slot) + { + DeleteAuxiliaryEffectSlots(1, ref slot); + } + + /// This function deletes one AuxiliaryEffectSlot only. + /// Pointer to an auxiliary effect slot name/handle identifying the Auxiliary Effect Slot Object to be deleted. + [CLSCompliant(false)] + public void DeleteAuxiliaryEffectSlot(ref uint slot) + { + unsafe + { + fixed (uint* ptr = &slot) + { + Imported_alDeleteAuxiliaryEffectSlots(1, ptr); + } + } + } + + #endregion alDeleteAuxiliaryEffectSlots + + #region alIsAuxiliaryEffectSlot + + //[CLSCompliant(false)] + private delegate bool Delegate_alIsAuxiliaryEffectSlot(uint slot); + // typedef ALboolean (__cdecl *LPALISAUXILIARYEFFECTSLOT)( ALuint slot ); + + //[CLSCompliant(false)] + private Delegate_alIsAuxiliaryEffectSlot Imported_alIsAuxiliaryEffectSlot; + + /// The IsAuxiliaryEffectSlot function is used to determine if an object identifier is a valid Auxiliary Effect Slot object. + /// Effect Slot object identifier to validate. + /// True if the identifier is a valid Auxiliary Effect Slot, False otherwise. + [CLSCompliant(false)] + public bool IsAuxiliaryEffectSlot(uint slot) + { + return Imported_alIsAuxiliaryEffectSlot(slot); + } + + /// The IsAuxiliaryEffectSlot function is used to determine if an object identifier is a valid Auxiliary Effect Slot object. + /// Effect Slot object identifier to validate. + /// True if the identifier is a valid Auxiliary Effect Slot, False otherwise. + + public bool IsAuxiliaryEffectSlot(int slot) + { + return Imported_alIsAuxiliaryEffectSlot((uint)slot); + } + + #endregion alIsAuxiliaryEffectSlot + + #region alAuxiliaryEffectSloti + + //[CLSCompliant(false)] + private delegate void Delegate_alAuxiliaryEffectSloti(uint asid, EfxAuxiliaryi param, int value); + // typedef void (__cdecl *LPALAUXILIARYEFFECTSLOTI)( ALuint asid, ALenum param, ALint value ); + + //[CLSCompliant(false)] + private Delegate_alAuxiliaryEffectSloti Imported_alAuxiliaryEffectSloti; + + /// This function is used to set integer properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to set. + /// Integer value. + [CLSCompliant(false)] + public void AuxiliaryEffectSlot(uint asid, EfxAuxiliaryi param, int value) + { + Imported_alAuxiliaryEffectSloti(asid, param, value); + } + + /// This function is used to set integer properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to set. + /// Integer value. + + public void AuxiliaryEffectSlot(int asid, EfxAuxiliaryi param, int value) + { + Imported_alAuxiliaryEffectSloti((uint)asid, param, value); + } + + #endregion alAuxiliaryEffectSloti + + #region alAuxiliaryEffectSlotf + + //[CLSCompliant(false)] + private delegate void Delegate_alAuxiliaryEffectSlotf(uint asid, EfxAuxiliaryf param, float value); + // typedef void (__cdecl *LPALAUXILIARYEFFECTSLOTF)( ALuint asid, ALenum param, ALfloat value ); + + //[CLSCompliant(false)] + private Delegate_alAuxiliaryEffectSlotf Imported_alAuxiliaryEffectSlotf; + + /// This function is used to set floating-point properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to set. + /// Floating-point value. + [CLSCompliant(false)] + public void AuxiliaryEffectSlot(uint asid, EfxAuxiliaryf param, float value) + { + Imported_alAuxiliaryEffectSlotf(asid, param, value); + } + + /// This function is used to set floating-point properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to set. + /// Floating-point value. + + public void AuxiliaryEffectSlot(int asid, EfxAuxiliaryf param, float value) + { + Imported_alAuxiliaryEffectSlotf((uint)asid, param, value); + } + + #endregion alAuxiliaryEffectSlotf + + #region alGetAuxiliaryEffectSloti + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetAuxiliaryEffectSloti(uint asid, EfxAuxiliaryi pname, [Out] int* value); + // typedef void (__cdecl *LPALGETAUXILIARYEFFECTSLOTI)( ALuint asid, ALenum pname, ALint* value ); + + //[CLSCompliant(false)] + private Delegate_alGetAuxiliaryEffectSloti Imported_alGetAuxiliaryEffectSloti; + + /// This function is used to retrieve integer properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to retrieve. + /// Address where integer value will be stored. + [CLSCompliant(false)] + public void GetAuxiliaryEffectSlot(uint asid, EfxAuxiliaryi pname, out int value) + { + unsafe + { + fixed (int* ptr = &value) + { + Imported_alGetAuxiliaryEffectSloti(asid, pname, ptr); + } + } + } + + /// This function is used to retrieve integer properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to retrieve. + /// Address where integer value will be stored. + + public void GetAuxiliaryEffectSlot(int asid, EfxAuxiliaryi pname, out int value) + { + GetAuxiliaryEffectSlot((uint)asid, pname, out value); + } + + #endregion alGetAuxiliaryEffectSloti + + #region alGetAuxiliaryEffectSlotf + + //[CLSCompliant(false)] + unsafe private delegate void Delegate_alGetAuxiliaryEffectSlotf(uint asid, EfxAuxiliaryf pname, [Out] float* value); + // typedef void (__cdecl *LPALGETAUXILIARYEFFECTSLOTF)( ALuint asid, ALenum pname, ALfloat* value ); + + //[CLSCompliant(false)] + private Delegate_alGetAuxiliaryEffectSlotf Imported_alGetAuxiliaryEffectSlotf; + + /// This function is used to retrieve floating properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to retrieve. + /// Address where floating-point value will be stored. + [CLSCompliant(false)] + public void GetAuxiliaryEffectSlot(uint asid, EfxAuxiliaryf pname, out float value) + { + unsafe + { + fixed (float* ptr = &value) + { + Imported_alGetAuxiliaryEffectSlotf(asid, pname, ptr); + } + } + } + + /// This function is used to retrieve floating properties on Auxiliary Effect Slot objects. + /// Auxiliary Effect Slot object identifier. + /// Auxiliary Effect Slot property to retrieve. + /// Address where floating-point value will be stored. + + public void GetAuxiliaryEffectSlot(int asid, EfxAuxiliaryf pname, out float value) + { + GetAuxiliaryEffectSlot((uint)asid, pname, out value); + } + + #endregion alGetAuxiliaryEffectSlotf + + // Not used: + // typedef void (__cdecl *LPALAUXILIARYEFFECTSLOTIV)( ALuint asid, ALenum param, ALint* values ); + // typedef void (__cdecl *LPALAUXILIARYEFFECTSLOTFV)( ALuint asid, ALenum param, ALfloat* values ); + // typedef void (__cdecl *LPALGETAUXILIARYEFFECTSLOTIV)( ALuint asid, ALenum pname, ALint* values ); + // typedef void (__cdecl *LPALGETAUXILIARYEFFECTSLOTFV)( ALuint asid, ALenum pname, ALfloat* values ); + + #endregion Auxiliary Effect Slot Object + + #region Constructor / Extension Loading + + private bool _valid; + + /// Returns True if the EFX Extension has been found and could be initialized. + public bool IsInitialized + { + get + { + return _valid; + } + } + + /// + /// Constructs a new EffectsExtension instance. + /// + public EffectsExtension() + { + _valid = false; + + if (AudioContext.CurrentContext == null) + throw new InvalidOperationException("AL.LoadAll() needs a current AudioContext."); + + if (!AudioContext.CurrentContext.SupportsExtension("ALC_EXT_EFX")) + { + Debug.Print("EFX Extension (ALC_EXT_EFX) is not supported(AudioContext: {0}).", AudioContext.CurrentContext.ToString()); + return; + } + // Console.WriteLine("ALC_EXT_EFX found. Efx can be used."); + + try + { + Imported_alGenEffects = (Delegate_alGenEffects)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGenEffects"), typeof(Delegate_alGenEffects)); + Imported_alDeleteEffects = (Delegate_alDeleteEffects)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alDeleteEffects"), typeof(Delegate_alDeleteEffects)); + Imported_alIsEffect = (Delegate_alIsEffect)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alIsEffect"), typeof(Delegate_alIsEffect)); + Imported_alEffecti = (Delegate_alEffecti)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alEffecti"), typeof(Delegate_alEffecti)); + Imported_alEffectf = (Delegate_alEffectf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alEffectf"), typeof(Delegate_alEffectf)); + Imported_alEffectfv = (Delegate_alEffectfv)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alEffectfv"), typeof(Delegate_alEffectfv)); + Imported_alGetEffecti = (Delegate_alGetEffecti)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetEffecti"), typeof(Delegate_alGetEffecti)); + Imported_alGetEffectf = (Delegate_alGetEffectf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetEffectf"), typeof(Delegate_alGetEffectf)); + Imported_alGetEffectfv = (Delegate_alGetEffectfv)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetEffectfv"), typeof(Delegate_alGetEffectfv)); + } + catch (Exception e) + { + Debug.WriteLine("Failed to marshal Effect functions. " + e.ToString()); + return; + } + // Console.WriteLine("Effect functions appear to be ok."); + + try + { + Imported_alGenFilters = (Delegate_alGenFilters)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGenFilters"), typeof(Delegate_alGenFilters)); + Imported_alDeleteFilters = (Delegate_alDeleteFilters)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alDeleteFilters"), typeof(Delegate_alDeleteFilters)); + Imported_alIsFilter = (Delegate_alIsFilter)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alIsFilter"), typeof(Delegate_alIsFilter)); + Imported_alFilteri = (Delegate_alFilteri)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alFilteri"), typeof(Delegate_alFilteri)); + Imported_alFilterf = (Delegate_alFilterf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alFilterf"), typeof(Delegate_alFilterf)); + Imported_alGetFilteri = (Delegate_alGetFilteri)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetFilteri"), typeof(Delegate_alGetFilteri)); + Imported_alGetFilterf = (Delegate_alGetFilterf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetFilterf"), typeof(Delegate_alGetFilterf)); + } + catch (Exception e) + { + Debug.WriteLine("Failed to marshal Filter functions. " + e.ToString()); + return; + } + // Console.WriteLine("Filter functions appear to be ok."); + + try + { + Imported_alGenAuxiliaryEffectSlots = (Delegate_alGenAuxiliaryEffectSlots)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGenAuxiliaryEffectSlots"), typeof(Delegate_alGenAuxiliaryEffectSlots)); + Imported_alDeleteAuxiliaryEffectSlots = (Delegate_alDeleteAuxiliaryEffectSlots)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alDeleteAuxiliaryEffectSlots"), typeof(Delegate_alDeleteAuxiliaryEffectSlots)); + Imported_alIsAuxiliaryEffectSlot = (Delegate_alIsAuxiliaryEffectSlot)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alIsAuxiliaryEffectSlot"), typeof(Delegate_alIsAuxiliaryEffectSlot)); + Imported_alAuxiliaryEffectSloti = (Delegate_alAuxiliaryEffectSloti)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alAuxiliaryEffectSloti"), typeof(Delegate_alAuxiliaryEffectSloti)); + Imported_alAuxiliaryEffectSlotf = (Delegate_alAuxiliaryEffectSlotf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alAuxiliaryEffectSlotf"), typeof(Delegate_alAuxiliaryEffectSlotf)); + Imported_alGetAuxiliaryEffectSloti = (Delegate_alGetAuxiliaryEffectSloti)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetAuxiliaryEffectSloti"), typeof(Delegate_alGetAuxiliaryEffectSloti)); + Imported_alGetAuxiliaryEffectSlotf = (Delegate_alGetAuxiliaryEffectSlotf)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("alGetAuxiliaryEffectSlotf"), typeof(Delegate_alGetAuxiliaryEffectSlotf)); + } + catch (Exception e) + { + Debug.WriteLine("Failed to marshal AuxiliaryEffectSlot functions. " + e.ToString()); + return; + } + // Console.WriteLine("Auxiliary Effect Slot functions appear to be ok."); + + // didn't return so far, everything went fine. + _valid = true; + } + + #endregion Constructor / Extension Loading + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionEnums.cs b/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionEnums.cs new file mode 100644 index 0000000..313f213 --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionEnums.cs @@ -0,0 +1,480 @@ +#region --- OpenTK.OpenAL License --- +/* EfxTokens.cs + * C headers: \OpenAL 1.1 SDK\include\ "efx.h", "efx-creative.h", "Efx-Util.h" + * Spec: Effects Extension Guide.pdf (bundled with OpenAL SDK) + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; + +namespace OpenTK.Audio.OpenAL +{ + #region Effect + + ///A list of valid 32-bit Float Effect/GetEffect parameters + public enum EfxEffectf : int + { + ///Reverb Modal Density controls the coloration of the late reverb. Lowering the value adds more coloration to the late reverb. Range [0.0f .. 1.0f] Default: 1.0f + ReverbDensity = 0x0001, + ///The Reverb Diffusion property controls the echo density in the reverberation decay. The default 1.0f provides the highest density. Reducing diffusion gives the reverberation a more "grainy" character that is especially noticeable with percussive sound sources. If you set a diffusion value of 0.0f, the later reverberation sounds like a succession of distinct echoes. Range [0.0f .. 1.0f] Default: 1.0f + ReverbDiffusion = 0x0002, + ///The Reverb Gain property is the master volume control for the reflected sound - both early reflections and reverberation - that the reverb effect adds to all sound sources. Ranges from 1.0 (0db) (the maximum amount) to 0.0 (-100db) (no reflected sound at all) are accepted. Units: Linear gain Range [0.0f .. 1.0f] Default: 0.32f + ReverbGain = 0x0003, + ///The Reverb Gain HF property further tweaks reflected sound by attenuating it at high frequencies. It controls a low-pass filter that applies globally to the reflected sound of all sound sources feeding the particular instance of the reverb effect. Ranges from 1.0f (0db) (no filter) to 0.0f (-100db) (virtually no reflected sound) are accepted. Units: Linear gain Range [0.0f .. 1.0f] Default: 0.89f + ReverbGainHF = 0x0004, + ///The Decay Time property sets the reverberation decay time. It ranges from 0.1f (typically a small room with very dead surfaces) to 20.0 (typically a large room with very live surfaces). Unit: Seconds Range [0.1f .. 20.0f] Default: 1.49f + ReverbDecayTime = 0x0005, + ///The Decay HF Ratio property sets the spectral quality of the Decay Time parameter. It is the ratio of high-frequency decay time relative to the time set by Decay Time.. Unit: linear multiplier Range [0.1f .. 2.0f] Default: 0.83f + ReverbDecayHFRatio = 0x0006, + ///The Reflections Gain property controls the overall amount of initial reflections relative to the Gain property. The value of Reflections Gain ranges from a maximum of 3.16f (+10 dB) to a minimum of 0.0f (-100 dB) (no initial reflections at all), and is corrected by the value of the Gain property. Unit: Linear gain Range [0.0f .. 3.16f] Default: 0.05f + ReverbReflectionsGain = 0x0007, + ///The Reflections Delay property is the amount of delay between the arrival time of the direct path from the source to the first reflection from the source. It ranges from 0 to 300 milliseconds. Unit: Seconds Range [0.0f .. 0.3f] Default: 0.007f + ReverbReflectionsDelay = 0x0008, + ///The Late Reverb Gain property controls the overall amount of later reverberation relative to the Gain property. The value of Late Reverb Gain ranges from a maximum of 10.0f (+20 dB) to a minimum of 0.0f (-100 dB) (no late reverberation at all). Unit: Linear gain Range [0.0f .. 10.0f] Default: 1.26f + ReverbLateReverbGain = 0x0009, + ///The Late Reverb Delay property defines the begin time of the late reverberation relative to the time of the initial reflection (the first of the early reflections). It ranges from 0 to 100 milliseconds. Unit: Seconds Range [0.0f .. 0.1f] Default: 0.011f + ReverbLateReverbDelay = 0x000A, + ///The Air Absorption Gain HF property controls the distance-dependent attenuation at high frequencies caused by the propagation medium and applies to reflected sound only. Unit: Linear gain per meter Range [0.892f .. 1.0f] Default: 0.994f + ReverbAirAbsorptionGainHF = 0x000B, + ///The Room Rolloff Factor property is one of two methods available to attenuate the reflected sound (containing both reflections and reverberation) according to source-listener distance. It's defined the same way as OpenAL's Rolloff Factor, but operates on reverb sound instead of direct-path sound. Unit: Linear multiplier Range [0.0f .. 10.0f] Default: 0.0f + ReverbRoomRolloffFactor = 0x000C, + + ///This property sets the modulation rate of the low-frequency oscillator that controls the delay time of the delayed signals. Unit: Hz Range [0.0f .. 10.0f] Default: 1.1f + ChorusRate = 0x0003, + ///This property controls the amount by which the delay time is modulated by the low-frequency oscillator. Range [0.0f .. 1.0f] Default: 0.1f + ChorusDepth = 0x0004, + ///This property controls the amount of processed signal that is fed back to the input of the chorus effect. Negative values will reverse the phase of the feedback signal. At full magnitude the identical sample will repeat endlessly. Range [-1.0f .. +1.0f] Default: +0.25f + ChorusFeedback = 0x0005, + ///This property controls the average amount of time the sample is delayed before it is played back, and with feedback, the amount of time between iterations of the sample. Larger values lower the pitch. Unit: Seconds Range [0.0f .. 0.016f] Default: 0.016f + ChorusDelay = 0x0006, + + ///This property controls the shape of the distortion. The higher the value for Edge, the "dirtier" and "fuzzier" the effect. Range [0.0f .. 1.0f] Default: 0.2f + DistortionEdge = 0x0001, + ///This property allows you to attenuate the distorted sound. Range [0.01f .. 1.0f] Default: 0.05f + DistortionGain = 0x0002, + ///Input signals can have a low pass filter applied, to limit the amount of high frequency signal feeding into the distortion effect. Unit: Hz Range [80.0f .. 24000.0f] Default: 8000.0f + DistortionLowpassCutoff = 0x0003, + ///This property controls the frequency at which the post-distortion attenuation (Distortion Gain) is active. Unit: Hz Range [80.0f .. 24000.0f] Default: 3600.0f + DistortionEQCenter = 0x0004, + ///This property controls the bandwidth of the post-distortion attenuation. Unit: Hz Range [80.0f .. 24000.0f] Default: 3600.0f + DistortionEQBandwidth = 0x0005, + + ///This property controls the delay between the original sound and the first "tap", or echo instance. Subsequently, the value for Echo Delay is used to determine the time delay between each "second tap" and the next "first tap". Unit: Seconds Range [0.0f .. 0.207f] Default: 0.1f + EchoDelay = 0x0001, + ///This property controls the delay between the "first tap" and the "second tap". Subsequently, the value for Echo LR Delay is used to determine the time delay between each "first tap" and the next "second tap". Unit: Seconds Range [0.0f .. 0.404f] Default: 0.1f + EchoLRDelay = 0x0002, + ///This property controls the amount of high frequency damping applied to each echo. As the sound is subsequently fed back for further echoes, damping results in an echo which progressively gets softer in tone as well as intensity. Range [0.0f .. 0.99f] Default: 0.5f + EchoDamping = 0x0003, + ///This property controls the amount of feedback the output signal fed back into the input. Use this parameter to create "cascading" echoes. At full magnitude, the identical sample will repeat endlessly. Below full magnitude, the sample will repeat and fade. Range [0.0f .. 1.0f] Default: 0.5f + EchoFeedback = 0x0004, + ///This property controls how hard panned the individual echoes are. With a value of 1.0f, the first "tap" will be panned hard left, and the second "tap" hard right. –1.0f gives the opposite result and values near to 0.0f result in less emphasized panning. Range [-1.0f .. +1.0f] Default: -1.0f + EchoSpread = 0x0005, + + ///The number of times per second the low-frequency oscillator controlling the amount of delay repeats. Range [0.0f .. 10.0f] Default: 0.27f + FlangerRate = 0x0003, + ///The ratio by which the delay time is modulated by the low-frequency oscillator. Range [0.0f .. 1.0f] Default: 1.0f + FlangerDepth = 0x0004, + ///This is the amount of the output signal level fed back into the effect's input. A negative value will reverse the phase of the feedback signal. Range [-1.0f .. +1.0f] Default: -0.5f + FlangerFeedback = 0x0005, + ///The average amount of time the sample is delayed before it is played back. When used with the Feedback property it's the amount of time between iterations of the sample. Unit: Seconds Range [0.0f .. 0.004f] Default: 0.002f + FlangerDelay = 0x0006, + + ///This is the carrier frequency. For carrier frequencies below the audible range, the single sideband modulator may produce phaser effects, spatial effects or a slight pitch-shift. As the carrier frequency increases, the timbre of the sound is affected. Unit: Hz Range [0.0f .. 24000.0f] Default: 0.0f + FrequencyShifterFrequency = 0x0001, + + ///This controls the frequency of the low-frequency oscillator used to morph between the two phoneme filters. Unit: Hz Range [0.0f .. 10.0f] Default: 1.41f + VocalMorpherRate = 0x0006, + + ///This is the frequency of the carrier signal. If the carrier signal is slowly varying (less than 20 Hz), the result is a slow amplitude variation effect (tremolo). Unit: Hz Range [0.0f .. 8000.0f] Default: 440.0f + RingModulatorFrequency = 0x0001, + ///This controls the cutoff frequency at which the input signal is high-pass filtered before being ring modulated. Unit: Hz Range [0.0f .. 24000.0f] Default: 800.0f + RingModulatorHighpassCutoff = 0x0002, + + ///This property controls the time the filtering effect takes to sweep from minimum to maximum center frequency when it is triggered by input signal. Unit: Seconds Range [0.0001f .. 1.0f] Default: 0.06f + AutowahAttackTime = 0x0001, + ///This property controls the time the filtering effect takes to sweep from maximum back to base center frequency, when the input signal ends. Unit: Seconds Range [0.0001f .. 1.0f] Default: 0.06f + AutowahReleaseTime = 0x0002, + ///This property controls the resonant peak, sometimes known as emphasis or Q, of the auto-wah band-pass filter. Range [2.0f .. 1000.0f] Default: 1000.0f + AutowahResonance = 0x0003, + ///This property controls the input signal level at which the band-pass filter will be fully opened. Range [0.00003f .. 31621.0f] Default: 11.22f + AutowahPeakGain = 0x0004, + + ///This property controls amount of cut or boost on the low frequency range. Range [0.126f .. 7.943f] Default: 1.0f + EqualizerLowGain = 0x0001, + ///This property controls the low frequency below which signal will be cut off. Unit: Hz Range [50.0f .. 800.0f] Default: 200.0f + EqualizerLowCutoff = 0x0002, + ///This property allows you to cut/boost signal on the "mid1" range. Range [0.126f .. 7.943f] Default: 1.0f + EqualizerMid1Gain = 0x0003, + ///This property sets the center frequency for the "mid1" range. Unit: Hz Range [200.0f .. 3000.0f] Default: 500.0f + EqualizerMid1Center = 0x0004, + ///This property controls the width of the "mid1" range. Range [0.01f .. 1.0f] Default: 1.0f + EqualizerMid1Width = 0x0005, + ///This property allows you to cut/boost signal on the "mid2" range. Range [0.126f .. 7.943f] Default: 1.0f + EqualizerMid2Gain = 0x0006, + ///This property sets the center frequency for the "mid2" range. Unit: Hz Range [1000.0f .. 8000.0f] Default: 3000.0f + EqualizerMid2Center = 0x0007, + ///This property controls the width of the "mid2" range. Range [0.01f .. 1.0f] Default: 1.0f + EqualizerMid2Width = 0x0008, + ///This property allows to cut/boost the signal at high frequencies. Range [0.126f .. 7.943f] Default: 1.0f + EqualizerHighGain = 0x0009, + ///This property controls the high frequency above which signal will be cut off. Unit: Hz Range [4000.0f .. 16000.0f] Default: 6000.0f + EqualizerHighCutoff = 0x000A, + + ///Reverb Modal Density controls the coloration of the late reverb. Range [0.0f .. 1.0f] Default: 1.0f + EaxReverbDensity = 0x0001, + ///The Reverb Diffusion property controls the echo density in the reverberation decay. Range [0.0f .. 1.0f] Default: 1.0f + EaxReverbDiffusion = 0x0002, + ///Reverb Gain controls the level of the reverberant sound in an environment. A high level of reverb is characteristic of rooms with highly reflective walls and/or small dimensions. Unit: Linear gain Range [0.0f .. 1.0f] Default: 0.32f + EaxReverbGain = 0x0003, + ///Gain HF is used to attenuate the high frequency content of all the reflected sound in an environment. You can use this property to give a room specific spectral characteristic. Unit: Linear gain Range [0.0f .. 1.0f] Default: 0.89f + EaxReverbGainHF = 0x0004, + ///Gain LF is the low frequency counterpart to Gain HF. Use this to reduce or boost the low frequency content in an environment. Unit: Linear gain Range [0.0f .. 1.0f] Default: 1.0f + EaxReverbGainLF = 0x0005, + ///The Decay Time property sets the reverberation decay time. It ranges from 0.1f (typically a small room with very dead surfaces) to 20.0f (typically a large room with very live surfaces). Unit: Seconds Range [0.1f .. 20.0f] Default: 1.49f + EaxReverbDecayTime = 0x0006, + ///Decay HF Ratio scales the decay time of high frequencies relative to the value of the Decay Time property. By changing this value, you are changing the amount of time it takes for the high frequencies to decay compared to the mid frequencies of the reverb. Range [0.1f .. 2.0f] Default: 0.83f + EaxReverbDecayHFRatio = 0x0007, + ///Decay LF Ratio scales the decay time of low frequencies in the reverberation in the same manner that Decay HF Ratio handles high frequencies. Unit: Linear multiplier Range [0.1f .. 2.0f] Default: 1.0f + EaxReverbDecayLFRatio = 0x0008, + ///Reflections Gain sets the level of the early reflections in an environment. Early reflections are used as a cue for determining the size of the environment we are in. Unit: Linear gain Range [0.0f .. 3.16f] Default: 0.05f + EaxReverbReflectionsGain = 0x0009, + ///Reflections Delay controls the amount of time it takes for the first reflected wave front to reach the listener, relative to the arrival of the direct-path sound. Unit: Seconds Range [0.0f .. 0.3f] Default: 0.007f + EaxReverbReflectionsDelay = 0x000A, + ///The Late Reverb Gain property controls the overall amount of later reverberation relative to the Gain property. Range [0.0f .. 10.0f] Default: 1.26f + EaxReverbLateReverbGain = 0x000C, + ///The Late Reverb Delay property defines the begin time of the late reverberation relative to the time of the initial reflection (the first of the early reflections). It ranges from 0 to 100 milliseconds. Unit: Seconds Range [0.0f .. 0.1f] Default: 0.011f + EaxReverbLateReverbDelay = 0x000D, + ///Echo Time controls the rate at which the cyclic echo repeats itself along the reverberation decay. Range [0.075f .. 0.25f] Default: 0.25f + EaxReverbEchoTime = 0x000F, + ///Echo Depth introduces a cyclic echo in the reverberation decay, which will be noticeable with transient or percussive sounds. Range [0.0f .. 1.0f] Default: 0.0f + EaxReverbEchoDepth = 0x0010, + ///Modulation Time controls the speed of the rate of periodic changes in pitch (vibrato). Range [0.04f .. 4.0f] Default: 0.25f + EaxReverbModulationTime = 0x0011, + ///Modulation Depth controls the amount of pitch change. Low values of Diffusion will contribute to reinforcing the perceived effect by reducing the mixing of overlapping reflections in the reverberation decay. Range [0.0f .. 1.0f] Default: 0.0f + EaxReverbModulationDepth = 0x0012, + ///The Air Absorption Gain HF property controls the distance-dependent attenuation at high frequencies caused by the propagation medium. It applies to reflected sound only. Range [0.892f .. 1.0f] Default: 0.994f + EaxReverbAirAbsorptionGainHF = 0x0013, + ///The property HF reference determines the frequency at which the high-frequency effects created by Reverb properties are measured. Unit: Hz Range [1000.0f .. 20000.0f] Default: 5000.0f + EaxReverbHFReference = 0x0014, + ///The property LF reference determines the frequency at which the low-frequency effects created by Reverb properties are measured. Unit: Hz Range [20.0f .. 1000.0f] Default: 250.0f + EaxReverbLFReference = 0x0015, + ///The Room Rolloff Factor property is one of two methods available to attenuate the reflected sound (containing both reflections and reverberation) according to source-listener distance. It's defined the same way as OpenAL Rolloff Factor, but operates on reverb sound instead of direct-path sound. Range [0.0f .. 10.0f] Default: 0.0f + EaxReverbRoomRolloffFactor = 0x0016, + } + + ///A list of valid Math.Vector3 Effect/GetEffect parameters + public enum EfxEffect3f : int + { + /// Reverb Pan does for the Reverb what Reflections Pan does for the Reflections. Unit: Vector3 of length 0f to 1f Default: {0.0f, 0.0f, 0.0f} + EaxReverbLateReverbPan = 0x000E, + /// This Vector3 controls the spatial distribution of the cluster of early reflections. The direction of this vector controls the global direction of the reflections, while its magnitude controls how focused the reflections are towards this direction. For legacy reasons this Vector3 follows a left-handed co-ordinate system! Note that OpenAL uses a right-handed coordinate system. Unit: Vector3 of length 0f to 1f Default: {0.0f, 0.0f, 0.0f} + EaxReverbReflectionsPan = 0x000B, + } + + ///A list of valid Int32 Effect/GetEffect parameters + public enum EfxEffecti : int + { + ///This property sets the waveform shape of the low-frequency oscillator that controls the delay time of the delayed signals. Unit: (0) Sinusoid, (1) Triangle Range [0 .. 1] Default: 1 + ChorusWaveform = 0x0001, + ///This property controls the phase difference between the left and right low-frequency oscillators. At zero degrees the two low-frequency oscillators are synchronized. Unit: Degrees Range [-180 .. 180] Default: 90 + ChorusPhase = 0x0002, + + ///Selects the shape of the low-frequency oscillator waveform that controls the amount of the delay of the sampled signal. Unit: (0) Sinusoid, (1) Triangle Range [0 .. 1] Default: 1 + FlangerWaveform = 0x0001, + ///This changes the phase difference between the left and right low-frequency oscillator's. At zero degrees the two low-frequency oscillators are synchronized. Range [-180 .. +180] Default: 0 + FlangerPhase = 0x0002, + + ///These select which internal signals are added together to produce the output. Unit: (0) Down, (1) Up, (2) Off Range [0 .. 2] Default: 0 + FrequencyShifterLeftDirection = 0x0002, + ///These select which internal signals are added together to produce the output. Unit: (0) Down, (1) Up, (2) Off Range [0 .. 2] Default: 0 + FrequencyShifterRightDirection = 0x0003, + + ///Sets the vocal morpher 4-band formant filter A, used to impose vocal tract effects upon the input signal. The vocal morpher is not necessarily intended for use on voice signals; it is primarily intended for pitched noise effects, vocal-like wind effects, etc. Unit: Use enum EfxFormantFilterSettings Range [0 .. 29] Default: 0, "Phoneme A" + VocalMorpherPhonemeA = 0x0001, + ///This is used to adjust the pitch of phoneme filter A in 1-semitone increments. Unit: Semitones Range [-24 .. +24] Default: 0 + VocalMorpherPhonemeACoarseTuning = 0x0002, + ///Sets the vocal morpher 4-band formant filter B, used to impose vocal tract effects upon the input signal. The vocal morpher is not necessarily intended for use on voice signals; it is primarily intended for pitched noise effects, vocal-like wind effects, etc. Unit: Use enum EfxFormantFilterSettings Range [0 .. 29] Default: 10, "Phoneme ER" + VocalMorpherPhonemeB = 0x0003, + ///This is used to adjust the pitch of phoneme filter B in 1-semitone increments. Unit: Semitones Range [-24 .. +24] Default: 0 + VocalMorpherPhonemeBCoarseTuning = 0x0004, + ///This controls the shape of the low-frequency oscillator used to morph between the two phoneme filters. Unit: (0) Sinusoid, (1) Triangle, (2) Sawtooth Range [0 .. 2] Default: 0 + VocalMorpherWaveform = 0x0005, + + ///This sets the number of semitones by which the pitch is shifted. There are 12 semitones per octave. Unit: Semitones Range [-12 .. +12] Default: +12 + PitchShifterCoarseTune = 0x0001, + ///This sets the number of cents between Semitones a pitch is shifted. A Cent is 1/100th of a Semitone. Unit: Cents Range [-50 .. +50] Default: 0 + PitchShifterFineTune = 0x0002, + + ///This controls which waveform is used as the carrier signal. Traditional ring modulator and tremolo effects generally use a sinusoidal carrier. Unit: (0) Sinusoid, (1) Sawtooth, (2) Square Range [0 .. 2] Default: 0 + RingModulatorWaveform = 0x0003, + + ///Enabling this will result in audio exhibiting smaller variation in intensity between the loudest and quietest portions. Unit: (0) Off, (1) On Range [0 .. 1] Default: 1 + CompressorOnoff = 0x0001, + + ///When this flag is set, the high-frequency decay time automatically stays below a limit value that's derived from the setting of the property Air Absorption HF. Unit: (0) False, (1) True Range [False, True] Default: True + ReverbDecayHFLimit = 0x000D, + + ///When this flag is set, the high-frequency decay time automatically stays below a limit value that's derived from the setting of the property AirAbsorptionGainHF. Unit: (0) False, (1) True Range [False, True] Default: True + EaxReverbDecayHFLimit = 0x0017, + + /// Used with the enum EfxEffectType as it's parameter. + EffectType = 0x8001, + } + + ///Vocal morpher effect parameters. If both parameters are set to the same phoneme, that determines the filtering effect that will be heard. If these two parameters are set to different phonemes, the filtering effect will morph between the two settings at a rate specified by EfxEffectf.VocalMorpherRate. + public enum EfxFormantFilterSettings : int + { + /// + /// The A phoneme of the vocal morpher. + /// + VocalMorpherPhonemeA = 0, + + /// + /// The E phoneme of the vocal morpher. + /// + VocalMorpherPhonemeE = 1, + + /// + /// The I phoneme of the vocal morpher. + /// + VocalMorpherPhonemeI = 2, + + /// + /// The O phoneme of the vocal morpher. + /// + VocalMorpherPhonemeO = 3, + + /// + /// The U phoneme of the vocal morpher. + /// + VocalMorpherPhonemeU = 4, + + /// + /// The AA phoneme of the vocal morpher. + /// + VocalMorpherPhonemeAA = 5, + + /// + /// The AE phoneme of the vocal morpher. + /// + VocalMorpherPhonemeAE = 6, + + /// + /// The AH phoneme of the vocal morpher. + /// + VocalMorpherPhonemeAH = 7, + + /// + /// The AO phoneme of the vocal morpher. + /// + VocalMorpherPhonemeAO = 8, + + /// + /// The EH phoneme of the vocal morpher. + /// + VocalMorpherPhonemeEH = 9, + + /// + /// The ER phoneme of the vocal morpher. + /// + VocalMorpherPhonemeER = 10, + + /// + /// The IH phoneme of the vocal morpher. + /// + VocalMorpherPhonemeIH = 11, + + /// + /// The IY phoneme of the vocal morpher. + /// + VocalMorpherPhonemeIY = 12, + + /// + /// The UH phoneme of the vocal morpher. + /// + VocalMorpherPhonemeUH = 13, + + /// + /// The UW phoneme of the vocal morpher. + /// + VocalMorpherPhonemeUW = 14, + + /// + /// The B phoneme of the vocal morpher. + /// + VocalMorpherPhonemeB = 15, + + /// + /// The D phoneme of the vocal morpher. + /// + VocalMorpherPhonemeD = 16, + + /// + /// The F phoneme of the vocal morpher. + /// + VocalMorpherPhonemeF = 17, + + /// + /// The G phoneme of the vocal morpher. + /// + VocalMorpherPhonemeG = 18, + + /// + /// The J phoneme of the vocal morpher. + /// + VocalMorpherPhonemeJ = 19, + + /// + /// The K phoneme of the vocal morpher. + /// + VocalMorpherPhonemeK = 20, + + /// + /// The L phoneme of the vocal morpher. + /// + VocalMorpherPhonemeL = 21, + + /// + /// The M phoneme of the vocal morpher. + /// + VocalMorpherPhonemeM = 22, + + /// + /// The N phoneme of the vocal morpher. + /// + VocalMorpherPhonemeN = 23, + + /// + /// The P phoneme of the vocal morpher. + /// + VocalMorpherPhonemeP = 24, + + /// + /// The R phoneme of the vocal morpher. + /// + VocalMorpherPhonemeR = 25, + + /// + /// The S phoneme of the vocal morpher. + /// + VocalMorpherPhonemeS = 26, + + /// + /// The T phoneme of the vocal morpher. + /// + VocalMorpherPhonemeT = 27, + + /// + /// The V phoneme of the vocal morpher. + /// + VocalMorpherPhonemeV = 28, + + /// + /// The Z phoneme of the vocal morpher. + /// + VocalMorpherPhonemeZ = 29, + } + + ///Effect type definitions to be used with EfxEffecti.EffectType. + public enum EfxEffectType : int + { + ///No Effect, disable. This Effect type is used when an Effect object is initially created. + Null = 0x0000, + ///The Reverb effect is the standard Effects Extension's environmental reverberation effect. It is available on all Generic Software and Generic Hardware devices. + Reverb = 0x0001, + ///The Chorus effect essentially replays the input audio accompanied by another slightly delayed version of the signal, creating a "doubling" effect. + Chorus = 0x0002, + ///The Distortion effect simulates turning up (overdriving) the gain stage on a guitar amplifier or adding a distortion pedal to an instrument's output. + Distortion = 0x0003, + ///The Echo effect generates discrete, delayed instances of the input signal. + Echo = 0x0004, + ///The Flanger effect creates a "tearing" or "whooshing" sound, like a jet flying overhead. + Flanger = 0x0005, + ///The Frequency shifter is a single-sideband modulator, which translates all the component frequencies of the input signal by an equal amount. + FrequencyShifter = 0x0006, + ///The Vocal morpher consists of a pair of 4-band formant filters, used to impose vocal tract effects upon the input signal. + VocalMorpher = 0x0007, + ///The Pitch shifter applies time-invariant pitch shifting to the input signal, over a one octave range and controllable at a semi-tone and cent resolution. + PitchShifter = 0x0008, + ///The Ring modulator multiplies an input signal by a carrier signal in the time domain, resulting in tremolo or inharmonic effects. + RingModulator = 0x0009, + ///The Auto-wah effect emulates the sound of a wah-wah pedal used with an electric guitar, or a mute on a brass instrument. + Autowah = 0x000A, + ///The Compressor will boost quieter portions of the audio, while louder portions will stay the same or may even be reduced. + Compressor = 0x000B, + ///The Equalizer is very flexible, providing tonal control over four different adjustable frequency ranges. + Equalizer = 0x000C, + ///The EAX Reverb has a more advanced parameter set than EfxEffectType.Reverb, but is only natively supported on devices that support the EAX 3.0 or above. + EaxReverb = 0x8000, + } + + #endregion Effect + + #region Auxiliary Effect Slot + + ///A list of valid Int32 AuxiliaryEffectSlot/GetAuxiliaryEffectSlot parameters + public enum EfxAuxiliaryi : int + { + /// This property is used to attach an Effect object to the Auxiliary Effect Slot object. After the attachment, the Auxiliary Effect Slot object will contain the effect type and have the same effect parameters that were stored in the Effect object. Any Sources feeding the Auxiliary Effect Slot will immediate feed the new effect type and new effect parameters. + EffectslotEffect = 0x0001, + + /// This property is used to enable or disable automatic send adjustments based on the physical positions of the sources and the listener. This property should be enabled when an application wishes to use a reverb effect to simulate the environment surrounding a listener or a collection of Sources. Range [False, True] Default: True + EffectslotAuxiliarySendAuto = 0x0003, + } + + ///A list of valid 32-bits Float AuxiliaryEffectSlot/GetAuxiliaryEffectSlot parameters + public enum EfxAuxiliaryf : int + { + /// This property is used to specify an output level for the Auxiliary Effect Slot. Setting the gain to 0.0f mutes the output. Range [0.0f .. 1.0f] Default: 1.0f + EffectslotGain = 0x0002, + } + + #endregion Auxiliary Effect Slot + + #region Filter Object + + ///A list of valid 32-bits Float Filter/GetFilter parameters + public enum EfxFilterf : int + { + ///Range [0.0f .. 1.0f] Default: 1.0f + LowpassGain = 0x0001, + ///Range [0.0f .. 1.0f] Default: 1.0f + LowpassGainHF = 0x0002, + + ///Range [0.0f .. 1.0f] Default: 1.0f + HighpassGain = 0x0001, + ///Range [0.0f .. 1.0f] Default: 1.0f + HighpassGainLF = 0x0002, + + ///Range [0.0f .. 1.0f] Default: 1.0f + BandpassGain = 0x0001, + ///Range [0.0f .. 1.0f] Default: 1.0f + BandpassGainLF = 0x0002, + ///Range [0.0f .. 1.0f] Default: 1.0f + BandpassGainHF = 0x0003, + } + + ///A list of valid Int32 Filter/GetFilter parameters + public enum EfxFilteri : int + { + /// Used with the enum EfxFilterType as Parameter to select a filter logic. + FilterType = 0x8001, + } + + ///Filter type definitions to be used with EfxFilteri.FilterType. + public enum EfxFilterType : int + { + ///No Filter, disable. This Filter type is used when a Filter object is initially created. + Null = 0x0000, + /// A low-pass filter is used to remove high frequency content from a signal. + Lowpass = 0x0001, + ///Currently not implemented. A high-pass filter is used to remove low frequency content from a signal. + Highpass = 0x0002, + ///Currently not implemented. A band-pass filter is used to remove high and low frequency content from a signal. + Bandpass = 0x0003, + } + + #endregion Filter Object +} diff --git a/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionPresets.cs b/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionPresets.cs new file mode 100644 index 0000000..75e1f0a --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/EffectsExtensionPresets.cs @@ -0,0 +1,374 @@ +#region --- OpenTK.OpenAL License --- +/* EfxPresets.cs + * C headers: \OpenAL 1.1 SDK\include\ "efx.h", "efx-creative.h", "Efx-Util.h" + * Spec: Effects Extension Guide.pdf (bundled with OpenAL SDK) + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK.Audio.OpenAL +{ + public partial class EffectsExtension + { + // Todo: Add documentation + // Todo: CLS compliance. + +#pragma warning disable 1591 + + [CLSCompliant(false)] + public struct EaxReverb + { + public uint Environment; // TODO: EAX-EFX conversion + public float EnvironmentSize; // TODO: EAX-EFX conversion + public float EnvironmentDiffusion; // TODO: EAX-EFX conversion + public int Room; // TODO: EAX-EFX conversion + public int RoomHF; // TODO: EAX-EFX conversion + public int RoomLF; // TODO: EAX-EFX conversion + public float DecayTime; + public float DecayHFRatio; + public float DecayLFRatio; + public int Reflections; // TODO: EAX-EFX conversion + public float ReflectionsDelay; + public Vector3 ReflectionsPan; + public int Reverb; // TODO: EAX-EFX conversion + public float ReverbDelay; + public Vector3 ReverbPan; + public float EchoTime; + public float EchoDepth; + public float ModulationTime; + public float ModulationDepth; + public float AirAbsorptionHF; + public float HFReference; + public float LFReference; + public float RoomRolloffFactor; + public uint Flags; // TODO: EAX-EFX conversion + + public EaxReverb(uint environment, + float environmentSize, + float environmentDiffusion, + int room, + int roomHF, + int roomLF, + float decayTime, + float decayHFRatio, + float decayLFRatio, + int reflections, + float reflectionsDelay, + float reflectionsPanX, + float reflectionsPanY, + float reflectionsPanZ, + int reverb, + float reverbDelay, + float reverbPanX, + float reverbPanY, + float reverbPanZ, + float echoTime, + float echoDepth, + float modulationTime, + float modulationDepth, + float airAbsorptionHF, + float hfReference, + float lfReference, + float roomRolloffFactor, + uint flags) + { + Environment = environment; + EnvironmentSize = environmentSize; + EnvironmentDiffusion = environmentDiffusion; + Room = room; + RoomHF = roomHF; + RoomLF = roomLF; + DecayTime = decayTime; + DecayHFRatio = decayHFRatio; + DecayLFRatio = decayLFRatio; + Reflections = reflections; + ReflectionsDelay = reflectionsDelay; + ReflectionsPan = new Vector3(reflectionsPanX, reflectionsPanY, reflectionsPanZ); + Reverb = reverb; + ReverbDelay = reverbDelay; + ReverbPan = new Vector3(reverbPanX, reverbPanY, reverbPanZ); + EchoTime = echoTime; + EchoDepth = echoDepth; + ModulationTime = modulationTime; + ModulationDepth = modulationDepth; + AirAbsorptionHF = airAbsorptionHF; + HFReference = hfReference; + LFReference = lfReference; + RoomRolloffFactor = roomRolloffFactor; + Flags = flags; + } + + } + + // TODO: CLS compliance. + [CLSCompliant(false)] + public static void GetEaxFromEfxEax(ref EaxReverb input, out EfxEaxReverb output) + { + output.AirAbsorptionGainHF = 0.995f; // input.AirAbsorptionHF * somegain? + output.RoomRolloffFactor = input.RoomRolloffFactor; + + output.Density = 1f; // todo, currently default + output.Diffusion = 1f; // todo, currently default + + output.DecayTime = input.DecayTime; + output.DecayHFLimit = 1; // todo, currently default + output.DecayHFRatio = input.DecayHFRatio; + output.DecayLFRatio = input.DecayLFRatio; + + output.EchoDepth = input.EchoDepth; + output.EchoTime = input.EchoTime; + + output.Gain = 0.32f; // todo, currently default + output.GainHF = 0.89f; // todo, currently default + output.GainLF = 1f;// todo, currently default + + output.LFReference = input.LFReference; + output.HFReference = input.HFReference; + + output.LateReverbDelay = input.ReverbDelay; + output.LateReverbGain = 1.26f; // todo, currently default + output.LateReverbPan = input.ReverbPan; + + output.ModulationDepth = input.ModulationDepth; + output.ModulationTime = input.ModulationTime; + + output.ReflectionsDelay = input.ReflectionsDelay; + output.ReflectionsGain = 0.05f; // todo, currently default + output.ReflectionsPan = input.ReflectionsPan; + } + + public struct EfxEaxReverb + { + public float Density; + public float Diffusion; + public float Gain; + public float GainHF; + public float GainLF; + public float DecayTime; + public float DecayHFRatio; + public float DecayLFRatio; + public float ReflectionsGain; + public float ReflectionsDelay; + public Vector3 ReflectionsPan; + public float LateReverbGain; + public float LateReverbDelay; + public Vector3 LateReverbPan; + public float EchoTime; + public float EchoDepth; + public float ModulationTime; + public float ModulationDepth; + public float AirAbsorptionGainHF; + public float HFReference; + public float LFReference; + public float RoomRolloffFactor; + public int DecayHFLimit; + } + + /* + public struct _EAXOBSTRUCTIONPROPERTIES + { + public int lObstruction; + public float flObstructionLFRatio; + } + _EAXOBSTRUCTIONPROPERTIES EAXOBSTRUCTIONPROPERTIES;//, *LPEAXOBSTRUCTIONPROPERTIES; + + public struct _EAXOCCLUSIONPROPERTIES + { + public int lOcclusion; + public float flOcclusionLFRatio; + public float flOcclusionRoomRatio; + public float flOcclusionDirectRatio; + } + _EAXOCCLUSIONPROPERTIES EAXOCCLUSIONPROPERTIES;//, *LPEAXOCCLUSIONPROPERTIES; + + public struct _EAXEXCLUSIONPROPERTIES + { + public int lExclusion; + public float flExclusionLFRatio; + } + _EAXEXCLUSIONPROPERTIES EAXEXCLUSIONPROPERTIES;//, *LPEAXEXCLUSIONPROPERTIES; + + public struct _EFXLOWPASSFILTER + { + public float flGain; + public float flGainHF; + } + _EFXLOWPASSFILTER EFXLOWPASSFILTER;//, *LPEFXLOWPASSFILTER; + + + void ConvertReverbParameters(EAXREVERBPROPERTIES *pEAXProp, EFXEAXREVERBPROPERTIES *pEFXEAXReverb); + void ConvertObstructionParameters(EAXOBSTRUCTIONPROPERTIES *pObProp, EFXLOWPASSFILTER *pDirectLowPassFilter); + void ConvertExclusionParameters(EAXEXCLUSIONPROPERTIES *pExProp, EFXLOWPASSFILTER *pSendLowPassFilter); + void ConvertOcclusionParameters(EAXOCCLUSIONPROPERTIES *pOcProp, EFXLOWPASSFILTER *pDirectLowPassFilter, EFXLOWPASSFILTER *pSendLowPassFilter); + */ + + // TODO: CLS compliance. + ///EAX Reverb Presets in legacy format - use ConvertReverbParameters() to convert to EFX EAX Reverb Presets for use with the OpenAL Effects Extension. + [CLSCompliant(false)] + public static class ReverbPresets + { + // CASTLE PRESETS + + public static EaxReverb CastleSmallRoom = new EaxReverb(26, 8.3f, 0.890f, -1000, -800, -2000, 1.22f, 0.83f, 0.31f, -100, 0.022f, 0f, 0f, 0f, 600, 0.011f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleShortPassage = new EaxReverb(26, 8.3f, 0.890f, -1000, -1000, -2000, 2.32f, 0.83f, 0.31f, -100, 0.007f, 0f, 0f, 0f, 200, 0.023f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleMediumroom = new EaxReverb(26, 8.3f, 0.930f, -1000, -1100, -2000, 2.04f, 0.83f, 0.46f, -400, 0.022f, 0f, 0f, 0f, 400, 0.011f, 0f, 0f, 0f, 0.155f, 0.030f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleLongpassage = new EaxReverb(26, 8.3f, 0.890f, -1000, -800, -2000, 3.42f, 0.83f, 0.31f, -100, 0.007f, 0f, 0f, 0f, 300, 0.023f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleLargeroom = new EaxReverb(26, 8.3f, 0.820f, -1000, -1100, -1800, 2.53f, 0.83f, 0.50f, -700, 0.034f, 0f, 0f, 0f, 200, 0.016f, 0f, 0f, 0f, 0.185f, 0.070f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleHall = new EaxReverb(26, 8.3f, 0.810f, -1000, -1100, -1500, 3.14f, 0.79f, 0.62f, -1500, 0.056f, 0f, 0f, 0f, 100, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleCupboard = new EaxReverb(26, 8.3f, 0.890f, -1000, -1100, -2000, 0.67f, 0.87f, 0.31f, 300, 0.010f, 0f, 0f, 0f, 1100, 0.007f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + public static EaxReverb CastleCourtyard = new EaxReverb(26, 8.3f, 0.420f, -1000, -700, -1400, 2.13f, 0.61f, 0.23f, -1300, 0.160f, 0f, 0f, 0f, -300, 0.036f, 0f, 0f, 0f, 0.250f, 0.370f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb CastleAlcove = new EaxReverb(26, 8.3f, 0.890f, -1000, -600, -2000, 1.64f, 0.87f, 0.31f, 00, 0.007f, 0f, 0f, 0f, 300, 0.034f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20); + + // FACTORY PRESETS + + public static EaxReverb FactoryAlcove = new EaxReverb(26, 1.8f, 0.590f, -1200, -200, -600, 3.14f, 0.65f, 1.31f, 300, 0.010f, 0f, 0f, 0f, 000, 0.038f, 0f, 0f, 0f, 0.114f, 0.100f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryShortpassage = new EaxReverb(26, 1.8f, 0.640f, -1200, -200, -600, 2.53f, 0.65f, 1.31f, 0, 0.010f, 0f, 0f, 0f, 200, 0.038f, 0f, 0f, 0f, 0.135f, 0.230f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryMediumroom = new EaxReverb(26, 1.9f, 0.820f, -1200, -200, -600, 2.76f, 0.65f, 1.31f, -1100, 0.022f, 0f, 0f, 0f, 300, 0.023f, 0f, 0f, 0f, 0.174f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryLongpassage = new EaxReverb(26, 1.8f, 0.640f, -1200, -200, -600, 4.06f, 0.65f, 1.31f, 0, 0.020f, 0f, 0f, 0f, 200, 0.037f, 0f, 0f, 0f, 0.135f, 0.230f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryLargeroom = new EaxReverb(26, 1.9f, 0.750f, -1200, -300, -400, 4.24f, 0.51f, 1.31f, -1500, 0.039f, 0f, 0f, 0f, 100, 0.023f, 0f, 0f, 0f, 0.231f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryHall = new EaxReverb(26, 1.9f, 0.750f, -1000, -300, -400, 7.43f, 0.51f, 1.31f, -2400, 0.073f, 0f, 0f, 0f, -100, 0.027f, 0f, 0f, 0f, 0.250f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryCupboard = new EaxReverb(26, 1.7f, 0.630f, -1200, -200, -600, 0.49f, 0.65f, 1.31f, 200, 0.010f, 0f, 0f, 0f, 600, 0.032f, 0f, 0f, 0f, 0.107f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactoryCourtyard = new EaxReverb(26, 1.7f, 0.570f, -1000, -1000, -400, 2.32f, 0.29f, 0.56f, -1300, 0.140f, 0f, 0f, 0f, -800, 0.039f, 0f, 0f, 0f, 0.250f, 0.290f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + public static EaxReverb FactorySmallroom = new EaxReverb(26, 1.8f, 0.820f, -1000, -200, -600, 1.72f, 0.65f, 1.31f, -300, 0.010f, 0f, 0f, 0f, 500, 0.024f, 0f, 0f, 0f, 0.119f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20); + + // ICE PALACE PRESETS + + public static EaxReverb IcepalaceAlcove = new EaxReverb(26, 2.7f, 0.840f, -1000, -500, -1100, 2.76f, 1.46f, 0.28f, 100, 0.010f, 0f, 0f, 0f, -100, 0.030f, 0f, 0f, 0f, 0.161f, 0.090f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceShortpassage = new EaxReverb(26, 2.7f, 0.750f, -1000, -500, -1100, 1.79f, 1.46f, 0.28f, -600, 0.010f, 0f, 0f, 0f, 100, 0.019f, 0f, 0f, 0f, 0.177f, 0.090f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceMediumroom = new EaxReverb(26, 2.7f, 0.870f, -1000, -500, -700, 2.22f, 1.53f, 0.32f, -800, 0.039f, 0f, 0f, 0f, 100, 0.027f, 0f, 0f, 0f, 0.186f, 0.120f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceLongpassage = new EaxReverb(26, 2.7f, 0.770f, -1000, -500, -800, 3.01f, 1.46f, 0.28f, -200, 0.012f, 0f, 0f, 0f, 200, 0.025f, 0f, 0f, 0f, 0.186f, 0.040f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceLargeroom = new EaxReverb(26, 2.9f, 0.810f, -1000, -500, -700, 3.14f, 1.53f, 0.32f, -1200, 0.039f, 0f, 0f, 0f, 000, 0.027f, 0f, 0f, 0f, 0.214f, 0.110f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceHall = new EaxReverb(26, 2.9f, 0.760f, -1000, -700, -500, 5.49f, 1.53f, 0.38f, -1900, 0.054f, 0f, 0f, 0f, -400, 0.052f, 0f, 0f, 0f, 0.226f, 0.110f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceCupboard = new EaxReverb(26, 2.7f, 0.830f, -1000, -600, -1300, 0.76f, 1.53f, 0.26f, 100, 0.012f, 0f, 0f, 0f, 600, 0.016f, 0f, 0f, 0f, 0.143f, 0.080f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceCourtyard = new EaxReverb(26, 2.9f, 0.590f, -1000, -1100, -1000, 2.04f, 1.20f, 0.38f, -1000, 0.173f, 0f, 0f, 0f, -1000, 0.043f, 0f, 0f, 0f, 0.235f, 0.480f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + public static EaxReverb IcepalaceSmallroom = new EaxReverb(26, 2.7f, 0.840f, -1000, -500, -1100, 1.51f, 1.53f, 0.27f, -100, 0.010f, 0f, 0f, 0f, 300, 0.011f, 0f, 0f, 0f, 0.164f, 0.140f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20); + + // SPACE STATION PRESETS + + public static EaxReverb SpacestationAlcove = new EaxReverb(26, 1.5f, 0.780f, -1000, -300, -100, 1.16f, 0.81f, 0.55f, 300, 0.007f, 0f, 0f, 0f, 000, 0.018f, 0f, 0f, 0f, 0.192f, 0.210f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationMediumroom = new EaxReverb(26, 1.5f, 0.750f, -1000, -400, -100, 3.01f, 0.50f, 0.55f, -800, 0.034f, 0f, 0f, 0f, 100, 0.035f, 0f, 0f, 0f, 0.209f, 0.310f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationShortpassage = new EaxReverb(26, 1.5f, 0.870f, -1000, -400, -100, 3.57f, 0.50f, 0.55f, 0, 0.012f, 0f, 0f, 0f, 100, 0.016f, 0f, 0f, 0f, 0.172f, 0.200f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationLongpassage = new EaxReverb(26, 1.9f, 0.820f, -1000, -400, -100, 4.62f, 0.62f, 0.55f, 0, 0.012f, 0f, 0f, 0f, 200, 0.031f, 0f, 0f, 0f, 0.250f, 0.230f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationLargeroom = new EaxReverb(26, 1.8f, 0.810f, -1000, -400, -100, 3.89f, 0.38f, 0.61f, -1000, 0.056f, 0f, 0f, 0f, -100, 0.035f, 0f, 0f, 0f, 0.233f, 0.280f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationHall = new EaxReverb(26, 1.9f, 0.870f, -1000, -400, -100, 7.11f, 0.38f, 0.61f, -1500, 0.100f, 0f, 0f, 0f, -400, 0.047f, 0f, 0f, 0f, 0.250f, 0.250f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationCupboard = new EaxReverb(26, 1.4f, 0.560f, -1000, -300, -100, 0.79f, 0.81f, 0.55f, 300, 0.007f, 0f, 0f, 0f, 500, 0.018f, 0f, 0f, 0f, 0.181f, 0.310f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + public static EaxReverb SpacestationSmallroom = new EaxReverb(26, 1.5f, 0.700f, -1000, -300, -100, 1.72f, 0.82f, 0.55f, -200, 0.007f, 0f, 0f, 0f, 300, 0.013f, 0f, 0f, 0f, 0.188f, 0.260f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20); + + // WOODEN GALLEON PRESETS + + public static EaxReverb WoodenAlcove = new EaxReverb(26, 7.5f, 1f, -1000, -1800, -1000, 1.22f, 0.62f, 0.91f, 100, 0.012f, 0f, 0f, 0f, -300, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenShortpassage = new EaxReverb(26, 7.5f, 1f, -1000, -1800, -1000, 1.75f, 0.50f, 0.87f, -100, 0.012f, 0f, 0f, 0f, -400, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenMediumroom = new EaxReverb(26, 7.5f, 1f, -1000, -2000, -1100, 1.47f, 0.42f, 0.82f, -100, 0.049f, 0f, 0f, 0f, -100, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenLongpassage = new EaxReverb(26, 7.5f, 1f, -1000, -2000, -1000, 1.99f, 0.40f, 0.79f, 000, 0.020f, 0f, 0f, 0f, -700, 0.036f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenLargeroom = new EaxReverb(26, 7.5f, 1f, -1000, -2100, -1100, 2.65f, 0.33f, 0.82f, -100, 0.066f, 0f, 0f, 0f, -200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenHall = new EaxReverb(26, 7.5f, 1f, -1000, -2200, -1100, 3.45f, 0.30f, 0.82f, -100, 0.088f, 0f, 0f, 0f, -200, 0.063f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenCupboard = new EaxReverb(26, 7.5f, 1f, -1000, -1700, -1000, 0.56f, 0.46f, 0.91f, 100, 0.012f, 0f, 0f, 0f, 100, 0.028f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenSmallroom = new EaxReverb(26, 7.5f, 1f, -1000, -1900, -1000, 0.79f, 0.32f, 0.87f, 00, 0.032f, 0f, 0f, 0f, -100, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + public static EaxReverb WoodenCourtyard = new EaxReverb(26, 7.5f, 0.650f, -1000, -2200, -1000, 1.79f, 0.35f, 0.79f, -500, 0.123f, 0f, 0f, 0f, -2000, 0.032f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f); + + // SPORTS PRESETS + + public static EaxReverb SportEmptystadium = new EaxReverb(26, 7.2f, 1f, -1000, -700, -200, 6.26f, 0.51f, 1.10f, -2400, 0.183f, 0f, 0f, 0f, -800, 0.038f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20); + public static EaxReverb SportSquashcourt = new EaxReverb(26, 7.5f, 0.750f, -1000, -1000, -200, 2.22f, 0.91f, 1.16f, -700, 0.007f, 0f, 0f, 0f, -200, 0.011f, 0f, 0f, 0f, 0.126f, 0.190f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20); + public static EaxReverb SportSmallswimmingpool = new EaxReverb(26, 36.2f, 0.700f, -1000, -200, -100, 2.76f, 1.25f, 1.14f, -400, 0.020f, 0f, 0f, 0f, -200, 0.030f, 0f, 0f, 0f, 0.179f, 0.150f, 0.895f, 0.190f, -5f, 5000f, 250f, 0f, 0x0); + public static EaxReverb SportLargeswimmingpool = new EaxReverb(26, 36.2f, 0.820f, -1000, -200, 0, 5.49f, 1.31f, 1.14f, -700, 0.039f, 0f, 0f, 0f, -600, 0.049f, 0f, 0f, 0f, 0.222f, 0.550f, 1.159f, 0.210f, -5f, 5000f, 250f, 0f, 0x0); + public static EaxReverb SportGymnasium = new EaxReverb(26, 7.5f, 0.810f, -1000, -700, -100, 3.14f, 1.06f, 1.35f, -800, 0.029f, 0f, 0f, 0f, -500, 0.045f, 0f, 0f, 0f, 0.146f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20); + public static EaxReverb SportFullstadium = new EaxReverb(26, 7.2f, 1f, -1000, -2300, -200, 5.25f, 0.17f, 0.80f, -2000, 0.188f, 0f, 0f, 0f, -1100, 0.038f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20); + public static EaxReverb SportStadimtannoy = new EaxReverb(26, 3f, 0.780f, -1000, -500, -600, 2.53f, 0.88f, 0.68f, -1100, 0.230f, 0f, 0f, 0f, -600, 0.063f, 0f, 0f, 0f, 0.250f, 0.200f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20); + + // PREFAB PRESETS + + public static EaxReverb PrefabWorkshop = new EaxReverb(26, 1.9f, 1f, -1000, -1700, -800, 0.76f, 1f, 1f, 0, 0.012f, 0f, 0f, 0f, 100, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x0); + public static EaxReverb PrefabSchoolroom = new EaxReverb(26, 1.86f, 0.690f, -1000, -400, -600, 0.98f, 0.45f, 0.18f, 300, 0.017f, 0f, 0f, 0f, 300, 0.015f, 0f, 0f, 0f, 0.095f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20); + public static EaxReverb PrefabPractiseroom = new EaxReverb(26, 1.86f, 0.870f, -1000, -800, -600, 1.12f, 0.56f, 0.18f, 200, 0.010f, 0f, 0f, 0f, 300, 0.011f, 0f, 0f, 0f, 0.095f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20); + public static EaxReverb PrefabOuthouse = new EaxReverb(26, 80.3f, 0.820f, -1000, -1900, -1600, 1.38f, 0.38f, 0.35f, -100, 0.024f, 0f, 0f, -0f, -400, 0.044f, 0f, 0f, 0f, 0.121f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0); + public static EaxReverb PrefabCaravan = new EaxReverb(26, 8.3f, 1f, -1000, -2100, -1800, 0.43f, 1.50f, 1f, 0, 0.012f, 0f, 0f, 0f, 600, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f); + + // DOME AND PIPE PRESETS + + public static EaxReverb DomeTomb = new EaxReverb(26, 51.8f, 0.790f, -1000, -900, -1300, 4.18f, 0.21f, 0.10f, -825, 0.030f, 0f, 0f, 0f, 450, 0.022f, 0f, 0f, 0f, 0.177f, 0.190f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0); + public static EaxReverb DomeSaintPauls = new EaxReverb(26, 50.3f, 0.870f, -1000, -900, -1300, 10.48f, 0.19f, 0.10f, -1500, 0.090f, 0f, 0f, 0f, 200, 0.042f, 0f, 0f, 0f, 0.250f, 0.120f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f); + public static EaxReverb PipeSmall = new EaxReverb(26, 50.3f, 1f, -1000, -900, -1300, 5.04f, 0.10f, 0.10f, -600, 0.032f, 0f, 0f, 0f, 800, 0.015f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f); + public static EaxReverb PipeLongthin = new EaxReverb(26, 1.6f, 0.910f, -1000, -700, -1100, 9.21f, 0.18f, 0.10f, -300, 0.010f, 0f, 0f, 0f, -300, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0); + public static EaxReverb PipeLarge = new EaxReverb(26, 50.3f, 1f, -1000, -900, -1300, 8.45f, 0.10f, 0.10f, -800, 0.046f, 0f, 0f, 0f, 400, 0.032f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f); + public static EaxReverb PipeResonant = new EaxReverb(26, 1.3f, 0.910f, -1000, -700, -1100, 6.81f, 0.18f, 0.10f, -300, 0.010f, 0f, 0f, 0f, 00, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0); + + // OUTDOORS PRESETS + + public static EaxReverb OutdoorsBackyard = new EaxReverb(26, 80.3f, 0.450f, -1000, -1200, -600, 1.12f, 0.34f, 0.46f, -700, 0.069f, 0f, 0f, -0f, -300, 0.023f, 0f, 0f, 0f, 0.218f, 0.340f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0); + public static EaxReverb OutdoorsRollingplains = new EaxReverb(26, 80.3f, 0f, -1000, -3900, -400, 2.13f, 0.21f, 0.46f, -1500, 0.300f, 0f, 0f, -0f, -700, 0.019f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0); + public static EaxReverb OutdoorsDeepcanyon = new EaxReverb(26, 80.3f, 0.740f, -1000, -1500, -400, 3.89f, 0.21f, 0.46f, -1000, 0.223f, 0f, 0f, -0f, -900, 0.019f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0); + public static EaxReverb OutdoorsCreek = new EaxReverb(26, 80.3f, 0.350f, -1000, -1500, -600, 2.13f, 0.21f, 0.46f, -800, 0.115f, 0f, 0f, -0f, -1400, 0.031f, 0f, 0f, 0f, 0.218f, 0.340f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0); + public static EaxReverb OutdoorsValley = new EaxReverb(26, 80.3f, 0.280f, -1000, -3100, -1600, 2.88f, 0.26f, 0.35f, -1700, 0.263f, 0f, 0f, -0f, -800, 0.100f, 0f, 0f, 0f, 0.250f, 0.340f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0); + + // MOOD PRESETS + + public static EaxReverb MoodHeaven = new EaxReverb(26, 19.6f, 0.940f, -1000, -200, -700, 5.04f, 1.12f, 0.56f, -1230, 0.020f, 0f, 0f, 0f, 200, 0.029f, 0f, 0f, 0f, 0.250f, 0.080f, 2.742f, 0.050f, -2f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb MoodHell = new EaxReverb(26, 100f, 0.570f, -1000, -900, -700, 3.57f, 0.49f, 2f, -10000, 0.020f, 0f, 0f, 0f, 300, 0.030f, 0f, 0f, 0f, 0.110f, 0.040f, 2.109f, 0.520f, -5f, 5000f, 139.5f, 0f, 0x40); + public static EaxReverb MoodMemory = new EaxReverb(26, 8f, 0.850f, -1000, -400, -900, 4.06f, 0.82f, 0.56f, -2800, 0f, 0f, 0f, 0f, 100, 0f, 0f, 0f, 0f, 0.250f, 0f, 0.474f, 0.450f, -10f, 5000f, 250f, 0f, 0x0); + + // DRIVING SIMULATION PRESETS + + public static EaxReverb DrivingCommentator = new EaxReverb(26, 3f, 0f, 1000, -500, -600, 2.42f, 0.88f, 0.68f, -1400, 0.093f, 0f, 0f, 0f, -1200, 0.017f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -10f, 5000f, 250f, 0f, 0x20); + public static EaxReverb DrivingPitgarage = new EaxReverb(26, 1.9f, 0.590f, -1000, -300, -500, 1.72f, 0.93f, 0.87f, -500, 0f, 0f, 0f, 0f, 200, 0.016f, 0f, 0f, 0f, 0.250f, 0.110f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x0); + public static EaxReverb DrivingIncarRacer = new EaxReverb(26, 1.1f, 0.800f, -1000, 0, -200, 0.17f, 2f, 0.41f, 500, 0.007f, 0f, 0f, 0f, -300, 0.015f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20); + public static EaxReverb DrivingIncarSports = new EaxReverb(26, 1.1f, 0.800f, -1000, -400, 0, 0.17f, 0.75f, 0.41f, 0, 0.010f, 0f, 0f, 0f, -500, 0f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20); + public static EaxReverb DrivingIncarLuxury = new EaxReverb(26, 1.6f, 1f, -1000, -2000, -600, 0.13f, 0.41f, 0.46f, -200, 0.010f, 0f, 0f, 0f, 400, 0.010f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20); + public static EaxReverb DrivingFullgrandstand = new EaxReverb(26, 8.3f, 1f, -1000, -1100, -400, 3.01f, 1.37f, 1.28f, -900, 0.090f, 0f, 0f, 0f, -1500, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10420.2f, 250f, 0f, 0x1f); + public static EaxReverb DrivingEmptygrandstand = new EaxReverb(26, 8.3f, 1f, -1000, 0, -200, 4.62f, 1.75f, 1.40f, -1363, 0.090f, 0f, 0f, 0f, -1200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10420.2f, 250f, 0f, 0x1f); + public static EaxReverb DrivingTunnel = new EaxReverb(26, 3.1f, 0.810f, -1000, -800, -100, 3.42f, 0.94f, 1.31f, -300, 0.051f, 0f, 0f, 0f, -300, 0.047f, 0f, 0f, 0f, 0.214f, 0.050f, 0.250f, 0f, -5f, 5000f, 155.3f, 0f, 0x20); + + // CITY PRESETS + + public static EaxReverb CityStreets = new EaxReverb(26, 3f, 0.780f, -1000, -300, -100, 1.79f, 1.12f, 0.91f, -1100, 0.046f, 0f, 0f, 0f, -1400, 0.028f, 0f, 0f, 0f, 0.250f, 0.200f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20); + public static EaxReverb CitySubway = new EaxReverb(26, 3f, 0.740f, -1000, -300, -100, 3.01f, 1.23f, 0.91f, -300, 0.046f, 0f, 0f, 0f, 200, 0.028f, 0f, 0f, 0f, 0.125f, 0.210f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20); + public static EaxReverb CityMuseum = new EaxReverb(26, 80.3f, 0.820f, -1000, -1500, -1500, 3.28f, 1.40f, 0.57f, -1200, 0.039f, 0f, 0f, -0f, -100, 0.034f, 0f, 0f, 0f, 0.130f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0); + public static EaxReverb CityLibrary = new EaxReverb(26, 80.3f, 0.820f, -1000, -1100, -2100, 2.76f, 0.89f, 0.41f, -900, 0.029f, 0f, 0f, -0f, -100, 0.020f, 0f, 0f, 0f, 0.130f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0); + public static EaxReverb CityUnderpass = new EaxReverb(26, 3f, 0.820f, -1000, -700, -100, 3.57f, 1.12f, 0.91f, -800, 0.059f, 0f, 0f, 0f, -100, 0.037f, 0f, 0f, 0f, 0.250f, 0.140f, 0.250f, 0f, -7f, 5000f, 250f, 0f, 0x20); + public static EaxReverb CityAbandoned = new EaxReverb(26, 3f, 0.690f, -1000, -200, -100, 3.28f, 1.17f, 0.91f, -700, 0.044f, 0f, 0f, 0f, -1100, 0.024f, 0f, 0f, 0f, 0.250f, 0.200f, 0.250f, 0f, -3f, 5000f, 250f, 0f, 0x20); + + // MISC ROOMS + + public static EaxReverb Generic = new EaxReverb(0, 7.5f, 1f, -1000, -100, 0, 1.49f, 0.83f, 1f, -2602, 0.007f, 0f, 0f, 0f, 200, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Paddedcell = new EaxReverb(1, 1.4f, 1f, -1000, -6000, 0, 0.17f, 0.10f, 1f, -1204, 0.001f, 0f, 0f, 0f, 207, 0.002f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Room = new EaxReverb(2, 1.9f, 1f, -1000, -454, 0, 0.40f, 0.83f, 1f, -1646, 0.002f, 0f, 0f, 0f, 53, 0.003f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Bathroom = new EaxReverb(3, 1.4f, 1f, -1000, -1200, 0, 1.49f, 0.54f, 1f, -370, 0.007f, 0f, 0f, 0f, 1030, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Livingroom = new EaxReverb(4, 2.5f, 1f, -1000, -6000, 0, 0.50f, 0.10f, 1f, -1376, 0.003f, 0f, 0f, 0f, -1104, 0.004f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Stoneroom = new EaxReverb(5, 11.6f, 1f, -1000, -300, 0, 2.31f, 0.64f, 1f, -711, 0.012f, 0f, 0f, 0f, 83, 0.017f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Auditorium = new EaxReverb(6, 21.6f, 1f, -1000, -476, 0, 4.32f, 0.59f, 1f, -789, 0.020f, 0f, 0f, 0f, -289, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Concerthall = new EaxReverb(7, 19.6f, 1f, -1000, -500, 0, 3.92f, 0.70f, 1f, -1230, 0.020f, 0f, 0f, 0f, -02, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Cave = new EaxReverb(8, 14.6f, 1f, -1000, 0, 0, 2.91f, 1.30f, 1f, -602, 0.015f, 0f, 0f, 0f, -302, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Arena = new EaxReverb(9, 36.2f, 1f, -1000, -698, 0, 7.24f, 0.33f, 1f, -1166, 0.020f, 0f, 0f, 0f, 16, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Hangar = new EaxReverb(10, 50.3f, 1f, -1000, -1000, 0, 10.05f, 0.23f, 1f, -602, 0.020f, 0f, 0f, 0f, 198, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Carpettedhallway = new EaxReverb(11, 1.9f, 1f, -1000, -4000, 0, 0.30f, 0.10f, 1f, -1831, 0.002f, 0f, 0f, 0f, -1630, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Hallway = new EaxReverb(12, 1.8f, 1f, -1000, -300, 0, 1.49f, 0.59f, 1f, -1219, 0.007f, 0f, 0f, 0f, 441, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Stonecorridor = new EaxReverb(13, 13.5f, 1f, -1000, -237, 0, 2.70f, 0.79f, 1f, -1214, 0.013f, 0f, 0f, 0f, 395, 0.020f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Alley = new EaxReverb(14, 7.5f, 0.300f, -1000, -270, 0, 1.49f, 0.86f, 1f, -1204, 0.007f, 0f, 0f, 0f, -4, 0.011f, 0f, 0f, 0f, 0.125f, 0.950f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Forest = new EaxReverb(15, 38f, 0.300f, -1000, -3300, 0, 1.49f, 0.54f, 1f, -2560, 0.162f, 0f, 0f, 0f, -229, 0.088f, 0f, 0f, 0f, 0.125f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb City = new EaxReverb(16, 7.5f, 0.500f, -1000, -800, 0, 1.49f, 0.67f, 1f, -2273, 0.007f, 0f, 0f, 0f, -1691, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Mountains = new EaxReverb(17, 100f, 0.270f, -1000, -2500, 0, 1.49f, 0.21f, 1f, -2780, 0.300f, 0f, 0f, 0f, -1434, 0.100f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Quarry = new EaxReverb(18, 17.5f, 1f, -1000, -1000, 0, 1.49f, 0.83f, 1f, -10000, 0.061f, 0f, 0f, 0f, 500, 0.025f, 0f, 0f, 0f, 0.125f, 0.700f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Plain = new EaxReverb(19, 42.5f, 0.210f, -1000, -2000, 0, 1.49f, 0.50f, 1f, -2466, 0.179f, 0f, 0f, 0f, -1926, 0.100f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Parkinglot = new EaxReverb(20, 8.3f, 1f, -1000, 0, 0, 1.65f, 1.50f, 1f, -1363, 0.008f, 0f, 0f, 0f, -1153, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Sewerpipe = new EaxReverb(21, 1.7f, 0.800f, -1000, -1000, 0, 2.81f, 0.14f, 1f, 429, 0.014f, 0f, 0f, 0f, 1023, 0.021f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Underwater = new EaxReverb(22, 1.8f, 1f, -1000, -4000, 0, 1.49f, 0.10f, 1f, -449, 0.007f, 0f, 0f, 0f, 1700, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 1.180f, 0.348f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Drugged = new EaxReverb(23, 1.9f, 0.500f, -1000, 0, 0, 8.39f, 1.39f, 1f, -115, 0.002f, 0f, 0f, 0f, 985, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 1f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Dizzy = new EaxReverb(24, 1.8f, 0.600f, -1000, -400, 0, 17.23f, 0.56f, 1f, -1713, 0.020f, 0f, 0f, 0f, -613, 0.030f, 0f, 0f, 0f, 0.250f, 1f, 0.810f, 0.310f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Psychotic = new EaxReverb(25, 1f, 0.500f, -1000, -151, 0, 7.56f, 0.91f, 1f, -626, 0.020f, 0f, 0f, 0f, 774, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 4f, 1f, -5f, 5000f, 250f, 0f, 0x1f); + public static EaxReverb Dustyroom = new EaxReverb(26, 1.8f, 0.560f, -1000, -200, -300, 1.79f, 0.38f, 0.21f, -600, 0.002f, 0f, 0f, 0f, 200, 0.006f, 0f, 0f, 0f, 0.202f, 0.050f, 0.250f, 0f, -10f, 13046f, 163.3f, 0f, 0x20); + public static EaxReverb Chapel = new EaxReverb(26, 19.6f, 0.840f, -1000, -500, 0, 4.62f, 0.64f, 1.23f, -700, 0.032f, 0f, 0f, 0f, -200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0.110f, -5f, 5000f, 250f, 0f, 0x3f); + public static EaxReverb Smallwaterroom = new EaxReverb(26, 36.2f, 0.700f, -1000, -698, 0, 1.51f, 1.25f, 1.14f, -100, 0.020f, 0f, 0f, 0f, 300, 0.030f, 0f, 0f, 0f, 0.179f, 0.150f, 0.895f, 0.190f, -7f, 5000f, 250f, 0f, 0x0); + } + +#pragma warning restore 1591 + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Audio/OpenAL/AL/XRamExtension.cs b/src/MiniTK/Audio/OpenAL/AL/XRamExtension.cs new file mode 100644 index 0000000..eae97dd --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/AL/XRamExtension.cs @@ -0,0 +1,208 @@ +#region --- OpenTK.OpenAL License --- +/* XRamExtension.cs + * C header: \OpenAL 1.1 SDK\include\xram.h + * Spec: ? + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details (MIT) + * http://www.OpenTK.net */ +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +// flibit Added This!!! +#pragma warning disable 3021 +#pragma warning disable 3014 +#pragma warning disable 3003 + +namespace OpenTK.Audio.OpenAL +{ + + /// + ///The X-Ram Extension is provided on the top-end Sound Blaster X-Fi solutions (Sound Blaster X-Fi Fatal1ty, Sound Blaster X-Fi Elite Pro, or later). + ///These products feature 64MB of X-Ram that can only be used for audio purposes, which can be controlled by this Extension. + /// + [CLSCompliant(true)] + public sealed class XRamExtension + { + #region Instance state + + private bool _valid = false; + + /// Returns True if the X-Ram Extension has been found and could be initialized. + public bool IsInitialized + { + get { return _valid; } + } + + #endregion Instance state + + #region X-RAM Function pointer definitions + + // [CLSCompliant(false)] + private delegate bool Delegate_SetBufferMode(int n, ref uint buffers, int value); + //typedef ALboolean (__cdecl *EAXSetBufferMode)(ALsizei n, ALuint *buffers, ALint value); + + // [CLSCompliant( false )] + private delegate int Delegate_GetBufferMode(uint buffer, IntPtr value); + //typedef ALenum (__cdecl *EAXGetBufferMode)(ALuint buffer, ALint *value); + + //[CLSCompliant(false)] + private Delegate_SetBufferMode Imported_SetBufferMode; + //[CLSCompliant(false)] + private Delegate_GetBufferMode Imported_GetBufferMode; + + #endregion X-RAM Function pointer definitions + + #region X-RAM Tokens + + private int AL_EAX_RAM_SIZE, AL_EAX_RAM_FREE, + AL_STORAGE_AUTOMATIC, AL_STORAGE_HARDWARE, AL_STORAGE_ACCESSIBLE; + + #endregion X-RAM Tokens + + #region Constructor / Extension Loading + + /// + /// Constructs a new XRamExtension instance. + /// + public XRamExtension() + { // Query if Extension supported and retrieve Tokens/Pointers if it is. + _valid = false; + if (AL.IsExtensionPresent("EAX-RAM") == false) + return; + + AL_EAX_RAM_SIZE = AL.GetEnumValue("AL_EAX_RAM_SIZE"); + AL_EAX_RAM_FREE = AL.GetEnumValue("AL_EAX_RAM_FREE"); + AL_STORAGE_AUTOMATIC = AL.GetEnumValue("AL_STORAGE_AUTOMATIC"); + AL_STORAGE_HARDWARE = AL.GetEnumValue("AL_STORAGE_HARDWARE"); + AL_STORAGE_ACCESSIBLE = AL.GetEnumValue("AL_STORAGE_ACCESSIBLE"); + + // Console.WriteLine("RamSize: {0} RamFree: {1} StorageAuto: {2} StorageHW: {3} StorageAccess: {4}",AL_EAX_RAM_SIZE,AL_EAX_RAM_FREE,AL_STORAGE_AUTOMATIC,AL_STORAGE_HARDWARE,AL_STORAGE_ACCESSIBLE); + + if (AL_EAX_RAM_SIZE == 0 || + AL_EAX_RAM_FREE == 0 || + AL_STORAGE_AUTOMATIC == 0 || + AL_STORAGE_HARDWARE == 0 || + AL_STORAGE_ACCESSIBLE == 0) + { + Debug.WriteLine("X-Ram: Token values could not be retrieved."); + return; + } + + // Console.WriteLine("Free Ram: {0} / {1}",GetRamFree( ),GetRamSize( )); + + try + { + Imported_GetBufferMode = (Delegate_GetBufferMode)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("EAXGetBufferMode"), typeof(Delegate_GetBufferMode)); + Imported_SetBufferMode = (Delegate_SetBufferMode)Marshal.GetDelegateForFunctionPointer(AL.GetProcAddress("EAXSetBufferMode"), typeof(Delegate_SetBufferMode)); + } + catch (Exception e) + { + Debug.WriteLine("X-Ram: Attempt to marshal function pointers with AL.GetProcAddress failed. " + e.ToString()); + return; + } + + _valid = true; + } + + #endregion Constructor / Extension Loading + + #region Public Methods + + /// Query total amount of X-RAM in bytes. + public int GetRamSize + { + get + { + return AL.Get((ALGetInteger)AL_EAX_RAM_SIZE); + } + } + + /// Query free X-RAM available in bytes. + public int GetRamFree + { + get + { + return AL.Get((ALGetInteger)AL_EAX_RAM_FREE); + } + } + + /// This enum is used to abstract the need of using AL.GetEnumValue() with the Extension. The values do NOT correspond to AL_STORAGE_* tokens! + public enum XRamStorage : byte + { + /// Put an Open AL Buffer into X-RAM if memory is available, otherwise use host RAM. This is the default mode. + Automatic = 0, + /// Force an Open AL Buffer into X-RAM, good for non-streaming buffers. + Hardware = 1, + /// Force an Open AL Buffer into 'accessible' (currently host) RAM, good for streaming buffers. + Accessible = 2, + } + + /// This function is used to set the storage Mode of an array of OpenAL Buffers. + /// The number of OpenAL Buffers pointed to by buffer. + /// An array of OpenAL Buffer handles. + /// The storage mode that should be used for all the given buffers. Should be the value of one of the following enum names: XRamStorage.Automatic, XRamStorage.Hardware, XRamStorage.Accessible + /// True if all the Buffers were successfully set to the requested storage mode, False otherwise. + [CLSCompliant(false)] + public bool SetBufferMode(int n, ref uint buffer, XRamStorage mode) + { + switch (mode) + { + case XRamStorage.Accessible: + return Imported_SetBufferMode(n, ref buffer, AL_STORAGE_ACCESSIBLE); + case XRamStorage.Hardware: + return Imported_SetBufferMode(n, ref buffer, AL_STORAGE_HARDWARE); + default: + return Imported_SetBufferMode(n, ref buffer, AL_STORAGE_AUTOMATIC); + } + } + + /// This function is used to set the storage Mode of an array of OpenAL Buffers. + /// The number of OpenAL Buffers pointed to by buffer. + /// An array of OpenAL Buffer handles. + /// The storage mode that should be used for all the given buffers. Should be the value of one of the following enum names: XRamStorage.Automatic, XRamStorage.Hardware, XRamStorage.Accessible + /// True if all the Buffers were successfully set to the requested storage mode, False otherwise. + [CLSCompliant(true)] + public bool SetBufferMode(int n, ref int buffer, XRamStorage mode) + { + uint temp = (uint)buffer; + return SetBufferMode(n, ref temp, mode); + } + + /// This function is used to retrieve the storage Mode of a single OpenAL Buffer. + /// The handle of an OpenAL Buffer. + /// The current Mode of the Buffer. + [CLSCompliant(false)] + public XRamStorage GetBufferMode(ref uint buffer) + { + int tempresult = Imported_GetBufferMode(buffer, IntPtr.Zero); // IntPtr.Zero due to the parameter being unused/reserved atm + + if (tempresult == AL_STORAGE_ACCESSIBLE) + return XRamStorage.Accessible; + if (tempresult == AL_STORAGE_HARDWARE) + return XRamStorage.Hardware; + // default: + return XRamStorage.Automatic; + } + + /// This function is used to retrieve the storage Mode of a single OpenAL Buffer. + /// The handle of an OpenAL Buffer. + /// The current Mode of the Buffer. + [CLSCompliant(true)] + public XRamStorage GetBufferMode(ref int buffer) + { + uint temp = (uint)buffer; + return GetBufferMode(ref temp); + } + + #endregion Public Methods + } + +} + +// flibit Added This!!! +#pragma warning restore 3021 +#pragma warning restore 3014 +#pragma warning restore 3003 \ No newline at end of file diff --git a/src/MiniTK/Audio/OpenAL/Alc/Alc.cs b/src/MiniTK/Audio/OpenAL/Alc/Alc.cs new file mode 100644 index 0000000..d85f712 --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/Alc/Alc.cs @@ -0,0 +1,448 @@ +#region --- OpenTK.OpenAL License --- +/* AlcFunctions.cs + * C header: \OpenAL 1.1 SDK\include\Alc.h + * Spec: http://www.openal.org/openal_webstf/specs/OpenAL11Specification.pdf + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; + +// flibit Added This!!! +#pragma warning disable 3021 + +/* Type Mapping +// 8-bit boolean +typedef char ALCboolean; + * byte +// character +typedef char ALCchar; + * byte +// signed 8-bit 2's complement integer +typedef char ALCbyte; + * byte + +// unsigned 8-bit integer +typedef unsigned char ALCubyte; + * ubyte + +// signed 16-bit 2's complement integer +typedef short ALCshort; + * short + +// unsigned 16-bit integer +typedef unsigned short ALCushort; + * ushort + +// unsigned 32-bit integer +typedef unsigned int ALCuint; + * uint + +// signed 32-bit 2's complement integer +typedef int ALCint; + * int +// non-negative 32-bit binary integer size +typedef int ALCsizei; + * int +// enumerated 32-bit value +typedef int ALCenum; + * int + +// 32-bit IEEE754 floating-point +typedef float ALCfloat; + * float + +// 64-bit IEEE754 floating-point +typedef double ALCdouble; + * double + +// void type (for opaque pointers only) +typedef void ALCvoid; + * void + + * ALCdevice + * ALCcontext *context + * IntPtr +*/ + +namespace OpenTK.Audio.OpenAL +{ + + /// Alc = Audio Library Context + public static class Alc + { + #region Constants + + private const string Lib = AL.Lib; + private const CallingConvention Style = CallingConvention.Cdecl; + + #endregion Constants + + #region Context Management + + #region CreateContext + + [DllImport(Alc.Lib, EntryPoint = "alcCreateContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity] + unsafe static extern IntPtr sys_CreateContext([In] IntPtr device, [In] int* attrlist); + + /// This function creates a context using a specified device. + /// a pointer to a device + /// a pointer to a set of attributes: ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_REFRESH, ALC_STEREO_SOURCES, ALC_SYNC + /// Returns a pointer to the new context (NULL on failure). The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values. + [CLSCompliant(false)] + unsafe public static ContextHandle CreateContext([In] IntPtr device, [In] int* attrlist) + { + return new ContextHandle(sys_CreateContext(device, attrlist)); + } + + // ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ); + + /// This function creates a context using a specified device. + /// a pointer to a device + /// an array of a set of attributes: ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_REFRESH, ALC_STEREO_SOURCES, ALC_SYNC + /// Returns a pointer to the new context (NULL on failure). + /// The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values. + public static ContextHandle CreateContext(IntPtr device, int[] attriblist) + { + unsafe + { + fixed (int* attriblist_ptr = attriblist) + { + return CreateContext(device, attriblist_ptr); + } + } + } + + #endregion + + [DllImport(Alc.Lib, EntryPoint = "alcMakeContextCurrent", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + static extern bool MakeContextCurrent(IntPtr context); + + /// This function makes a specified context the current context. + /// A pointer to the new context. + /// Returns True on success, or False on failure. + public static bool MakeContextCurrent(ContextHandle context) + { + return MakeContextCurrent(context.Handle); + } + // ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context ); + + [DllImport(Alc.Lib, EntryPoint = "alcProcessContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + static extern void ProcessContext(IntPtr context); + + /// This function tells a context to begin processing. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. alcSuspendContext can be used to suspend a context, and then all the OpenAL state changes can be applied at once, followed by a call to alcProcessContext to apply all the state changes immediately. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP. + /// a pointer to the new context + public static void ProcessContext(ContextHandle context) + { + ProcessContext(context.Handle); + } + // ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context ); + + [DllImport(Alc.Lib, EntryPoint = "alcSuspendContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + static extern void SuspendContext(IntPtr context); + + /// This function suspends processing on a specified context. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. A typical use of alcSuspendContext would be to suspend a context, apply all the OpenAL state changes at once, and then call alcProcessContext to apply all the state changes at once. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP. + /// a pointer to the context to be suspended. + public static void SuspendContext(ContextHandle context) + { + SuspendContext(context.Handle); + } + // ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context ); + + [DllImport(Alc.Lib, EntryPoint = "alcDestroyContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + static extern void DestroyContext(IntPtr context); + + /// This function destroys a context. + /// a pointer to the new context. + public static void DestroyContext(ContextHandle context) + { + DestroyContext(context.Handle); + } + // ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context ); + + [DllImport(Alc.Lib, EntryPoint = "alcGetCurrentContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + private static extern IntPtr sys_GetCurrentContext(); + + /// This function retrieves the current context. + /// Returns a pointer to the current context. + public static ContextHandle GetCurrentContext() + { + return new ContextHandle(sys_GetCurrentContext()); + } + // ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void ); + + [DllImport(Alc.Lib, EntryPoint = "alcGetContextsDevice", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + static extern IntPtr GetContextsDevice(IntPtr context); + + /// This function retrieves a context's device pointer. + /// a pointer to a context. + /// Returns a pointer to the specified context's device. + public static IntPtr GetContextsDevice(ContextHandle context) + { + return GetContextsDevice(context.Handle); + } + // ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context ); + + #endregion Context Management + + #region Device Management + + /// This function opens a device by name. + /// a null-terminated string describing a device. + /// Returns a pointer to the opened device. The return value will be NULL if there is an error. + [DllImport(Alc.Lib, EntryPoint = "alcOpenDevice", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern IntPtr OpenDevice([In] string devicename); + // ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename ); + + /// This function closes a device by name. + /// a pointer to an opened device + /// True will be returned on success or False on failure. Closing a device will fail if the device contains any contexts or buffers. + [DllImport(Alc.Lib, EntryPoint = "alcCloseDevice", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern bool CloseDevice([In] IntPtr device); + // ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device ); + + #endregion Device Management + + #region Error support. + + /// This function retrieves the current context error state. + /// a pointer to the device to retrieve the error state from + /// Errorcode Int32. + [DllImport(Alc.Lib, EntryPoint = "alcGetError", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern AlcError GetError([In] IntPtr device); + // ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device ); + + #endregion Error support. + + #region Extension support. + + /// This function queries if a specified context extension is available. + /// a pointer to the device to be queried for an extension. + /// a null-terminated string describing the extension. + /// Returns True if the extension is available, False if the extension is not available. + [DllImport(Alc.Lib, EntryPoint = "alcIsExtensionPresent", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern bool IsExtensionPresent([In] IntPtr device, [In] string extname); + // ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ); + + /// This function retrieves the address of a specified context extension function. + /// a pointer to the device to be queried for the function. + /// a null-terminated string describing the function. + /// Returns the address of the function, or NULL if it is not found. + [DllImport(Alc.Lib, EntryPoint = "alcGetProcAddress", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern IntPtr GetProcAddress([In] IntPtr device, [In] string funcname); + // ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ); + + /// This function retrieves the enum value for a specified enumeration name. + /// a pointer to the device to be queried. + /// a null terminated string describing the enum value. + /// Returns the enum value described by the enumName string. This is most often used for querying an enum value for an ALC extension. + [DllImport(Alc.Lib, EntryPoint = "alcGetEnumValue", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern int GetEnumValue([In] IntPtr device, [In] string enumname); + // ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ); + + #endregion Extension support. + + #region Query functions + + [DllImport(Alc.Lib, EntryPoint = "alcGetString", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + private static extern IntPtr GetStringPrivate([In] IntPtr device, AlcGetString param); + // ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param ); + + /// This function returns pointers to strings related to the context. + /// + /// ALC_DEFAULT_DEVICE_SPECIFIER will return the name of the default output device. + /// ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER will return the name of the default capture device. + /// ALC_DEVICE_SPECIFIER will return the name of the specified output device if a pointer is supplied, or will return a list of all available devices if a NULL device pointer is supplied. A list is a pointer to a series of strings separated by NULL characters, with the list terminated by two NULL characters. See Enumeration Extension for more details. + /// ALC_CAPTURE_DEVICE_SPECIFIER will return the name of the specified capture device if a pointer is supplied, or will return a list of all available devices if a NULL device pointer is supplied. + /// ALC_EXTENSIONS returns a list of available context extensions, with each extension separated by a space and the list terminated by a NULL character. + /// + /// a pointer to the device to be queried. + /// an attribute to be retrieved: ALC_DEFAULT_DEVICE_SPECIFIER, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER, ALC_DEVICE_SPECIFIER, ALC_CAPTURE_DEVICE_SPECIFIER, ALC_EXTENSIONS + /// A string containing the name of the Device. + public static string GetString(IntPtr device, AlcGetString param) + { + return Marshal.PtrToStringAnsi(GetStringPrivate(device, param)); + } + + /// This function returns a List of strings related to the context. + /// + /// ALC_DEVICE_SPECIFIER will return the name of the specified output device if a pointer is supplied, or will return a list of all available devices if a NULL device pointer is supplied. A list is a pointer to a series of strings separated by NULL characters, with the list terminated by two NULL characters. See Enumeration Extension for more details. + /// ALC_CAPTURE_DEVICE_SPECIFIER will return the name of the specified capture device if a pointer is supplied, or will return a list of all available devices if a NULL device pointer is supplied. + /// ALC_EXTENSIONS returns a list of available context extensions, with each extension separated by a space and the list terminated by a NULL character. + /// + /// a pointer to the device to be queried. + /// an attribute to be retrieved: ALC_DEVICE_SPECIFIER, ALC_CAPTURE_DEVICE_SPECIFIER, ALC_ALL_DEVICES_SPECIFIER + /// A List of strings containing the names of the Devices. + public static IList GetString(IntPtr device, AlcGetStringList param) + { + List result = new List(); + IntPtr t = GetStringPrivate(IntPtr.Zero, (AlcGetString)param); + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + byte b; + int offset = 0; + do + { + b = Marshal.ReadByte(t, offset++); + if (b != 0) + sb.Append((char)b); + if (b == 0) + { + result.Add(sb.ToString()); + if (Marshal.ReadByte(t, offset) == 0) // offset already properly increased through ++ + break; // 2x null + else + sb.Remove(0, sb.Length); // 1x null + } + } while (true); + + return (IList)result; + } + + [DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + unsafe static extern void GetInteger(IntPtr device, AlcGetInteger param, int size, int* data); + // ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *buffer ); + + /// This function returns integers related to the context. + /// a pointer to the device to be queried. + /// an attribute to be retrieved: ALC_MAJOR_VERSION, ALC_MINOR_VERSION, ALC_ATTRIBUTES_SIZE, ALC_ALL_ATTRIBUTES + /// the size of the destination buffer provided, in number of integers. + /// a pointer to the buffer to be returned + public static void GetInteger(IntPtr device, AlcGetInteger param, int size, out int data) + { + unsafe + { + fixed (int* data_ptr = &data) + { + GetInteger(device, param, size, data_ptr); + } + } + } + + /// This function returns integers related to the context. + /// a pointer to the device to be queried. + /// an attribute to be retrieved: ALC_MAJOR_VERSION, ALC_MINOR_VERSION, ALC_ATTRIBUTES_SIZE, ALC_ALL_ATTRIBUTES + /// the size of the destination buffer provided, in number of integers. + /// a pointer to the buffer to be returned + public static void GetInteger(IntPtr device, AlcGetInteger param, int size, int[] data) + { + unsafe + { + fixed (int* data_ptr = data) + { + GetInteger(device, param, size, data_ptr); + } + } + } + + #endregion Query functions + + #region Capture functions + + /// This function opens a capture device by name. + /// a pointer to a device name string. + /// the frequency that the buffer should be captured at. + /// the requested capture buffer format. + /// the size of the capture buffer in samples, not bytes. + /// Returns the capture device pointer, or NULL on failure. + [CLSCompliant(false), DllImport(Alc.Lib, EntryPoint = "alcCaptureOpenDevice", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern IntPtr CaptureOpenDevice(string devicename, uint frequency, ALFormat format, int buffersize); + + /// This function opens a capture device by name. + /// a pointer to a device name string. + /// the frequency that the buffer should be captured at. + /// the requested capture buffer format. + /// the size of the capture buffer in samples, not bytes. + /// Returns the capture device pointer, or NULL on failure. + [DllImport(Alc.Lib, EntryPoint = "alcCaptureOpenDevice", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()] + public static extern IntPtr CaptureOpenDevice(string devicename, int frequency, ALFormat format, int buffersize); + + // ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); + + /// This function closes the specified capture device. + /// a pointer to a capture device. + /// Returns True if the close operation was successful, False on failure. + [DllImport(Alc.Lib, EntryPoint = "alcCaptureCloseDevice", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern bool CaptureCloseDevice([In] IntPtr device); + // ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device ); + + /// This function begins a capture operation. + /// alcCaptureStart will begin recording to an internal ring buffer of the size specified when opening the capture device. The application can then retrieve the number of samples currently available using the ALC_CAPTURE_SAPMPLES token with alcGetIntegerv. When the application determines that enough samples are available for processing, then it can obtain them with a call to alcCaptureSamples. + /// a pointer to a capture device. + [DllImport(Alc.Lib, EntryPoint = "alcCaptureStart", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern void CaptureStart([In] IntPtr device); + // ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device ); + + /// This function stops a capture operation. + /// a pointer to a capture device. + [DllImport(Alc.Lib, EntryPoint = "alcCaptureStop", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern void CaptureStop([In] IntPtr device); + // ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device ); + + /// This function completes a capture operation, and does not block. + /// a pointer to a capture device. + /// a pointer to a buffer, which must be large enough to accommodate the number of samples. + /// the number of samples to be retrieved. + [DllImport(Alc.Lib, EntryPoint = "alcCaptureSamples", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()] + public static extern void CaptureSamples(IntPtr device, IntPtr buffer, int samples); + // ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + + /// This function completes a capture operation, and does not block. + /// a pointer to a capture device. + /// a reference to a buffer, which must be large enough to accommodate the number of samples. + /// the number of samples to be retrieved. + public static void CaptureSamples(IntPtr device, ref T buffer, int samples) + where T : struct + { + GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + CaptureSamples(device, handle.AddrOfPinnedObject(), samples); + } + finally + { + handle.Free(); + } + } + + /// This function completes a capture operation, and does not block. + /// a pointer to a capture device. + /// a buffer, which must be large enough to accommodate the number of samples. + /// the number of samples to be retrieved. + public static void CaptureSamples(IntPtr device, T[] buffer, int samples) + where T : struct + { + CaptureSamples(device, ref buffer[0], samples); + } + + /// This function completes a capture operation, and does not block. + /// a pointer to a capture device. + /// a buffer, which must be large enough to accommodate the number of samples. + /// the number of samples to be retrieved. + public static void CaptureSamples(IntPtr device, T[,] buffer, int samples) + where T : struct + { + CaptureSamples(device, ref buffer[0, 0], samples); + } + + /// This function completes a capture operation, and does not block. + /// a pointer to a capture device. + /// a buffer, which must be large enough to accommodate the number of samples. + /// the number of samples to be retrieved. + public static void CaptureSamples(IntPtr device, T[, ,] buffer, int samples) + where T : struct + { + CaptureSamples(device, ref buffer[0, 0, 0], samples); + } + + #endregion Capture functions + + } + +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Audio/OpenAL/Alc/AlcEnums.cs b/src/MiniTK/Audio/OpenAL/Alc/AlcEnums.cs new file mode 100644 index 0000000..6f68fc6 --- /dev/null +++ b/src/MiniTK/Audio/OpenAL/Alc/AlcEnums.cs @@ -0,0 +1,135 @@ +#region --- OpenTK.OpenAL License --- +/* AlcTokens.cs + * C header: \OpenAL 1.1 SDK\include\Alc.h + * Spec: http://www.openal.org/openal_webstf/specs/OpenAL11Specification.pdf + * Copyright (c) 2008 Christoph Brandtner and Stefanos Apostolopoulos + * See license.txt for license details + * http://www.OpenTK.net */ +#endregion + +using System; + +namespace OpenTK.Audio.OpenAL +{ + /// + /// Defines available context attributes. + /// + public enum AlcContextAttributes : int + { + ///Followed by System.Int32 Hz + Frequency = 0x1007, + + ///Followed by System.Int32 Hz + Refresh = 0x1008, + + ///Followed by AlBoolean.True, or AlBoolean.False + Sync = 0x1009, + + ///Followed by System.Int32 Num of requested Mono (3D) Sources + MonoSources = 0x1010, + + ///Followed by System.Int32 Num of requested Stereo Sources + StereoSources = 0x1011, + + /// (EFX Extension) This Context property can be passed to OpenAL during Context creation (alcCreateContext) to request a maximum number of Auxiliary Sends desired on each Source. It is not guaranteed that the desired number of sends will be available, so an application should query this property after creating the context using alcGetIntergerv. Default: 2 + EfxMaxAuxiliarySends = 0x20003, + } + + /// + /// Defines OpenAL context errors. + /// + public enum AlcError : int + { + ///There is no current error. + NoError = 0, + + ///No Device. The device handle or specifier names an inaccessible driver/server. + InvalidDevice = 0xA001, + + ///Invalid context ID. The Context argument does not name a valid context. + InvalidContext = 0xA002, + + ///Bad enum. A token used is not valid, or not applicable. + InvalidEnum = 0xA003, + + ///Bad value. A value (e.g. Attribute) is not valid, or not applicable. + InvalidValue = 0xA004, + + ///Out of memory. Unable to allocate memory. + OutOfMemory = 0xA005, + } + + /// + /// Defines available parameters for . + /// + public enum AlcGetString : int + { + ///The specifier string for the default device. + DefaultDeviceSpecifier = 0x1004, + + ///A list of available context extensions separated by spaces. + Extensions = 0x1006, + + ///The name of the default capture device + CaptureDefaultDeviceSpecifier = 0x311, // ALC_EXT_CAPTURE extension. + + /// a list of the default devices. + DefaultAllDevicesSpecifier = 0x1012, + + // duplicates from AlcGetStringList: + + ///Will only return the first Device, not a list. Use AlcGetStringList.CaptureDeviceSpecifier. ALC_EXT_CAPTURE_EXT + CaptureDeviceSpecifier = 0x310, + + ///Will only return the first Device, not a list. Use AlcGetStringList.DeviceSpecifier + DeviceSpecifier = 0x1005, + + /// Will only return the first Device, not a list. Use AlcGetStringList.AllDevicesSpecifier + AllDevicesSpecifier = 0x1013, + } + + /// + /// Defines available parameters for . + /// + public enum AlcGetStringList : int + { + ///The name of the specified capture device, or a list of all available capture devices if no capture device is specified. ALC_EXT_CAPTURE_EXT + CaptureDeviceSpecifier = 0x310, + + ///The specifier strings for all available devices. ALC_ENUMERATION_EXT + DeviceSpecifier = 0x1005, + + /// The specifier strings for all available devices. ALC_ENUMERATE_ALL_EXT + AllDevicesSpecifier = 0x1013, + } + + /// + /// Defines available parameters for . + /// + public enum AlcGetInteger : int + { + ///The specification revision for this implementation (major version). NULL is an acceptable device. + MajorVersion = 0x1000, + + ///The specification revision for this implementation (minor version). NULL is an acceptable device. + MinorVersion = 0x1001, + + ///The size (number of ALCint values) required for a zero-terminated attributes list, for the current context. NULL is an invalid device. + AttributesSize = 0x1002, + + ///Expects a destination of ALC_ATTRIBUTES_SIZE, and provides an attribute list for the current context of the specified device. NULL is an invalid device. + AllAttributes = 0x1003, + + ///The number of capture samples available. NULL is an invalid device. + CaptureSamples = 0x312, + + /// (EFX Extension) This property can be used by the application to retrieve the Major version number of the Effects Extension supported by this OpenAL implementation. As this is a Context property is should be retrieved using alcGetIntegerv. + EfxMajorVersion = 0x20001, + + /// (EFX Extension) This property can be used by the application to retrieve the Minor version number of the Effects Extension supported by this OpenAL implementation. As this is a Context property is should be retrieved using alcGetIntegerv. + EfxMinorVersion = 0x20002, + + /// (EFX Extension) This Context property can be passed to OpenAL during Context creation (alcCreateContext) to request a maximum number of Auxiliary Sends desired on each Source. It is not guaranteed that the desired number of sends will be available, so an application should query this property after creating the context using alcGetIntergerv. Default: 2 + EfxMaxAuxiliarySends = 0x20003, + } +} diff --git a/src/MiniTK/BlittableValueType.cs b/src/MiniTK/BlittableValueType.cs new file mode 100644 index 0000000..abc9e48 --- /dev/null +++ b/src/MiniTK/BlittableValueType.cs @@ -0,0 +1,291 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2010 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Reflection; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + #region BlittableValueType + + /// + /// Checks whether the specified type parameter is a blittable value type. + /// + /// + /// A blittable value type is a struct that only references other value types recursively, + /// which allows it to be passed to unmanaged code directly. + /// + public static class BlittableValueType + { + #region Fields + + static readonly Type Type; + static readonly int stride; + + #endregion + + #region Constructors + + static BlittableValueType() + { + Type = typeof(T); + if (Type.IsValueType && !Type.IsGenericType) + { + // Does this support generic types? On Mono 2.4.3 it does + // On .Net it doesn't. + // http://msdn.microsoft.com/en-us/library/5s4920fa.aspx + stride = Marshal.SizeOf(typeof(T)); + } + } + + #endregion + + #region Public Members + + /// + /// Gets the size of the type in bytes or 0 for non-blittable types. + /// + /// + /// This property returns 0 for non-blittable types. + /// + public static int Stride { get { return stride; } } + + #region Check + + /// + /// Checks whether the current typename T is blittable. + /// + /// True if T is blittable; false otherwise. + public static bool Check() + { + return Check(Type); + } + + /// + /// Checks whether type is a blittable value type. + /// + /// A System.Type to check. + /// True if T is blittable; false otherwise. + public static bool Check(Type type) + { + if (!CheckStructLayoutAttribute(type)) + Debug.Print("Warning: type {0} does not specify a StructLayoutAttribute with Pack=1. The memory layout of the struct may change between platforms.", type.Name); + + return CheckType(type); + } + + #endregion + + #endregion + + #region Private Members + + // Checks whether the parameter is a primitive type or consists of primitive types recursively. + // Throws a NotSupportedException if it is not. + static bool CheckType(Type type) + { + //Debug.Print("Checking type {0} (size: {1} bytes).", type.Name, Marshal.SizeOf(type)); + if (type.IsPrimitive) + return true; + + if (!type.IsValueType) + return false; + + FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + Debug.Indent(); + foreach (FieldInfo field in fields) + { + if (!CheckType(field.FieldType)) + return false; + } + Debug.Unindent(); + + return Stride != 0; + } + + // Checks whether the specified struct defines [StructLayout(LayoutKind.Sequential, Pack=1)] + // or [StructLayout(LayoutKind.Explicit)] + static bool CheckStructLayoutAttribute(Type type) + { + StructLayoutAttribute[] attr = (StructLayoutAttribute[]) + type.GetCustomAttributes(typeof(StructLayoutAttribute), true); + + if ((attr == null) || + (attr != null && attr.Length > 0 && attr[0].Value != LayoutKind.Explicit && attr[0].Pack != 1)) + return false; + + return true; + } + + #endregion + } + + #endregion + + #region BlittableValueType + + /// + /// Checks whether the specified type parameter is a blittable value type. + /// + /// + /// A blittable value type is a struct that only references other value types recursively, + /// which allows it to be passed to unmanaged code directly. + /// + public static class BlittableValueType + { + #region Check + + /// + /// Checks whether type is a blittable value type. + /// + /// An instance of the type to check. + /// True if T is blittable; false otherwise. + public static bool Check(T type) + { + return BlittableValueType.Check(); + } + + /// + /// Checks whether type is a blittable value type. + /// + /// An instance of the type to check. + /// True if T is blittable; false otherwise. + public static bool Check(T[] type) + { + return BlittableValueType.Check(); + } + + /// + /// Checks whether type is a blittable value type. + /// + /// An instance of the type to check. + /// True if T is blittable; false otherwise. + public static bool Check(T[,] type) + { + return BlittableValueType.Check(); + } + + /// + /// Checks whether type is a blittable value type. + /// + /// An instance of the type to check. + /// True if T is blittable; false otherwise. + public static bool Check(T[, ,] type) + { + return BlittableValueType.Check(); + } + + /// + /// Checks whether type is a blittable value type. + /// + /// An instance of the type to check. + /// True if T is blittable; false otherwise. + [CLSCompliant(false)] + public static bool Check(T[][] type) + { + return BlittableValueType.Check(); + } + + #endregion + + #region StrideOf + + /// + /// Returns the size of the specified value type in bytes or 0 if the type is not blittable. + /// + /// The value type. Must be blittable. + /// An instance of the value type. + /// An integer, specifying the size of the type in bytes. + /// Occurs when type is not blittable. + public static int StrideOf(T type) + { + if (!Check(type)) + throw new ArgumentException("type"); + + return BlittableValueType.Stride; + } + + /// + /// Returns the size of a single array element in bytes or 0 if the element is not blittable. + /// + /// The value type. + /// An instance of the value type. + /// An integer, specifying the size of the type in bytes. + /// Occurs when type is not blittable. + public static int StrideOf(T[] type) + { + if (!Check(type)) + throw new ArgumentException("type"); + + return BlittableValueType.Stride; + } + + /// + /// Returns the size of a single array element in bytes or 0 if the element is not blittable. + /// + /// The value type. + /// An instance of the value type. + /// An integer, specifying the size of the type in bytes. + /// Occurs when type is not blittable. + public static int StrideOf(T[,] type) + { + if (!Check(type)) + throw new ArgumentException("type"); + + return BlittableValueType.Stride; + } + + /// + /// Returns the size of a single array element in bytes or 0 if the element is not blittable. + /// + /// The value type. + /// An instance of the value type. + /// An integer, specifying the size of the type in bytes. + /// Occurs when type is not blittable. + public static int StrideOf(T[, ,] type) + { + if (!Check(type)) + throw new ArgumentException("type"); + + return BlittableValueType.Stride; + } + + #endregion + } + + #endregion +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/ContextHandle.cs b/src/MiniTK/ContextHandle.cs new file mode 100644 index 0000000..362489d --- /dev/null +++ b/src/MiniTK/ContextHandle.cs @@ -0,0 +1,177 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Represents a handle to an OpenGL or OpenAL context. + /// + public struct ContextHandle : IComparable, IEquatable + { + #region Fields + + IntPtr handle; + + /// + /// Gets a System.IntPtr that represents the handle of this ContextHandle. + /// + public IntPtr Handle { get { return handle; } } + + /// A read-only field that represents a handle that has been initialized to zero. + public static readonly ContextHandle Zero = new ContextHandle(IntPtr.Zero); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance with the specified handle. + /// + /// A System.IntPtr containing the value for this instance. + public ContextHandle(IntPtr h) { handle = h; } + + #endregion + + #region Public Members + + #region ToString + + /// + /// Converts this instance to its equivalent string representation. + /// + /// A System.String that contains the string representation of this instance. + public override string ToString() + { + return Handle.ToString(); + } + + #endregion + + #region Equals + + /// + /// Compares this instance to the specified object. + /// + /// The System.Object to compare to. + /// True if obj is a ContextHandle that is equal to this instance; false otherwise. + public override bool Equals(object obj) + { + if (obj is ContextHandle) + return this.Equals((ContextHandle)obj); + return false; + } + + #endregion + + #region GetHashCode + + /// + /// Returns the hash code for this instance. + /// + /// A System.Int32 with the hash code of this instance. + public override int GetHashCode() + { + return Handle.GetHashCode(); + } + + #endregion + + #region public static explicit operator IntPtr(ContextHandle c) + + /// + /// Converts the specified ContextHandle to the equivalent IntPtr. + /// + /// The ContextHandle to convert. + /// A System.IntPtr equivalent to the specified ContextHandle. + public static explicit operator IntPtr(ContextHandle c) + { + return c != ContextHandle.Zero ? c.handle : IntPtr.Zero; + } + + #endregion + + #region public static explicit operator ContextHandle(IntPtr p) + + /// + /// Converts the specified IntPtr to the equivalent ContextHandle. + /// + /// The System.IntPtr to convert. + /// A ContextHandle equivalent to the specified IntPtr. + public static explicit operator ContextHandle(IntPtr p) + { + return new ContextHandle(p); + } + + #endregion + + #region public static bool operator ==(ContextHandle left, ContextHandle right) + + /// + /// Compares two ContextHandles for equality. + /// + /// The ContextHandle to compare. + /// The ContextHandle to compare to. + /// True if left is equal to right; false otherwise. + public static bool operator ==(ContextHandle left, ContextHandle right) + { + return left.Equals(right); + } + + #endregion + + #region public static bool operator !=(ContextHandle left, ContextHandle right) + + /// + /// Compares two ContextHandles for inequality. + /// + /// The ContextHandle to compare. + /// The ContextHandle to compare to. + /// True if left is not equal to right; false otherwise. + public static bool operator !=(ContextHandle left, ContextHandle right) + { + return !left.Equals(right); + } + + #endregion + + #endregion + + #region IComparable Members + + /// + /// Compares the numerical value of this instance to the specified ContextHandle and + /// returns a value indicating their relative order. + /// + /// The ContextHandle to compare to. + /// Less than 0, if this instance is less than other; 0 if both are equal; Greater than 0 if other is greater than this instance. + public int CompareTo(ContextHandle other) + { + unsafe { return (int)((int*)other.handle.ToPointer() - (int*)this.handle.ToPointer()); } + } + + #endregion + + #region IEquatable Members + + /// + /// Compares this instance to the specified ContextHandle for equality. + /// + /// The ContextHandle to compare to. + /// True if this instance is equal to other; false otherwise. + public bool Equals(ContextHandle other) + { + return Handle == other.Handle; + } + + #endregion + } +} diff --git a/src/MiniTK/Math/BezierCurve.cs b/src/MiniTK/Math/BezierCurve.cs new file mode 100644 index 0000000..4e3035b --- /dev/null +++ b/src/MiniTK/Math/BezierCurve.cs @@ -0,0 +1,261 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + * + * Contributions by Georg W�chter. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Represents a bezier curve with as many points as you want. + /// + [Serializable] + public struct BezierCurve + { + #region Fields + + private List points; + + /// + /// The parallel value. + /// + /// This value defines whether the curve should be calculated as a + /// parallel curve to the original bezier curve. A value of 0.0f represents + /// the original curve, 5.0f i.e. stands for a curve that has always a distance + /// of 5.0f to the orignal curve at any point. + public float Parallel; + + #endregion + + #region Properties + + /// + /// Gets the points of this curve. + /// + /// The first point and the last points represent the anchor points. + public IList Points + { + get + { + return points; + } + } + + #endregion + + #region Constructors + + /// + /// Constructs a new . + /// + /// The points. + public BezierCurve(IEnumerable points) + { + if (points == null) + throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures."); + + this.points = new List(points); + this.Parallel = 0.0f; + } + + /// + /// Constructs a new . + /// + /// The points. + public BezierCurve(params Vector2[] points) + { + if (points == null) + throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures."); + + this.points = new List(points); + this.Parallel = 0.0f; + } + + /// + /// Constructs a new . + /// + /// The parallel value. + /// The points. + public BezierCurve(float parallel, params Vector2[] points) + { + if (points == null) + throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures."); + + this.Parallel = parallel; + this.points = new List(points); + } + + /// + /// Constructs a new . + /// + /// The parallel value. + /// The points. + public BezierCurve(float parallel, IEnumerable points) + { + if (points == null) + throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures."); + + this.Parallel = parallel; + this.points = new List(points); + } + + #endregion + + #region Functions + + + /// + /// Calculates the point with the specified t. + /// + /// The t value, between 0.0f and 1.0f. + /// Resulting point. + public Vector2 CalculatePoint(float t) + { + return BezierCurve.CalculatePoint(points, t, Parallel); + } + + /// + /// Calculates the length of this bezier curve. + /// + /// The precision. + /// Length of curve. + /// The precision gets better as the + /// value gets smaller. + public float CalculateLength(float precision) + { + return BezierCurve.CalculateLength(points, precision, Parallel); + } + + #region Static methods + + /// + /// Calculates the length of the specified bezier curve. + /// + /// The points. + /// The precision value. + /// The precision gets better as the + /// value gets smaller. + public static float CalculateLength(IList points, float precision) + { + return BezierCurve.CalculateLength(points, precision, 0.0f); + } + + /// + /// Calculates the length of the specified bezier curve. + /// + /// The points. + /// The precision value. + /// The parallel value. + /// Length of curve. + /// The precision gets better as the + /// value gets smaller. + /// The parameter defines whether the curve should be calculated as a + /// parallel curve to the original bezier curve. A value of 0.0f represents + /// the original curve, 5.0f represents a curve that has always a distance + /// of 5.0f to the orignal curve. + public static float CalculateLength(IList points, float precision, float parallel) + { + float length = 0.0f; + Vector2 old = BezierCurve.CalculatePoint(points, 0.0f, parallel); + + for (float i = precision; i < (1.0f + precision); i += precision) + { + Vector2 n = CalculatePoint(points, i, parallel); + length += (n - old).Length; + old = n; + } + + return length; + } + + /// + /// Calculates the point on the given bezier curve with the specified t parameter. + /// + /// The points. + /// The t parameter, a value between 0.0f and 1.0f. + /// Resulting point. + public static Vector2 CalculatePoint(IList points, float t) + { + return BezierCurve.CalculatePoint(points, t, 0.0f); + } + + /// + /// Calculates the point on the given bezier curve with the specified t parameter. + /// + /// The points. + /// The t parameter, a value between 0.0f and 1.0f. + /// The parallel value. + /// Resulting point. + /// The parameter defines whether the curve should be calculated as a + /// parallel curve to the original bezier curve. A value of 0.0f represents + /// the original curve, 5.0f represents a curve that has always a distance + /// of 5.0f to the orignal curve. + public static Vector2 CalculatePoint(IList points, float t, float parallel) + { + Vector2 r = new Vector2(); + double c = 1.0d - (double)t; + float temp; + int i = 0; + + foreach (Vector2 pt in points) + { + temp = (float)MathHelper.BinomialCoefficient(points.Count - 1, i) * (float)(System.Math.Pow(t, i) * + System.Math.Pow(c, (points.Count - 1) - i)); + + r.X += temp * pt.X; + r.Y += temp * pt.Y; + i++; + } + + if (parallel == 0.0f) + return r; + + Vector2 perpendicular = new Vector2(); + + if (t != 0.0f) + perpendicular = r - BezierCurve.CalculatePointOfDerivative(points, t); + else + perpendicular = points[1] - points[0]; + + return r + Vector2.Normalize(perpendicular).PerpendicularRight * parallel; + } + + /// + /// Calculates the point with the specified t of the derivative of the given bezier function. + /// + /// The points. + /// The t parameter, value between 0.0f and 1.0f. + /// Resulting point. + private static Vector2 CalculatePointOfDerivative(IList points, float t) + { + Vector2 r = new Vector2(); + double c = 1.0d - (double)t; + float temp; + int i = 0; + + foreach (Vector2 pt in points) + { + temp = (float)MathHelper.BinomialCoefficient(points.Count - 2, i) * (float)(System.Math.Pow(t, i) * + System.Math.Pow(c, (points.Count - 2) - i)); + + r.X += temp * pt.X; + r.Y += temp * pt.Y; + i++; + } + + return r; + } + + #endregion + + #endregion + } +} diff --git a/src/MiniTK/Math/BezierCurveCubic.cs b/src/MiniTK/Math/BezierCurveCubic.cs new file mode 100644 index 0000000..149bbf7 --- /dev/null +++ b/src/MiniTK/Math/BezierCurveCubic.cs @@ -0,0 +1,163 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + * + * Contributions by Georg W�chter. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Represents a cubic bezier curve with two anchor and two control points. + /// + [Serializable] + public struct BezierCurveCubic + { + #region Fields + + /// + /// Start anchor point. + /// + public Vector2 StartAnchor; + + /// + /// End anchor point. + /// + public Vector2 EndAnchor; + + /// + /// First control point, controls the direction of the curve start. + /// + public Vector2 FirstControlPoint; + + /// + /// Second control point, controls the direction of the curve end. + /// + public Vector2 SecondControlPoint; + + /// + /// Gets or sets the parallel value. + /// + /// This value defines whether the curve should be calculated as a + /// parallel curve to the original bezier curve. A value of 0.0f represents + /// the original curve, 5.0f i.e. stands for a curve that has always a distance + /// of 5.f to the orignal curve at any point. + public float Parallel; + + #endregion + + #region Constructors + + /// + /// Constructs a new . + /// + /// The start anchor point. + /// The end anchor point. + /// The first control point. + /// The second control point. + public BezierCurveCubic(Vector2 startAnchor, Vector2 endAnchor, Vector2 firstControlPoint, Vector2 secondControlPoint) + { + this.StartAnchor = startAnchor; + this.EndAnchor = endAnchor; + this.FirstControlPoint = firstControlPoint; + this.SecondControlPoint = secondControlPoint; + this.Parallel = 0.0f; + } + + /// + /// Constructs a new . + /// + /// The parallel value. + /// The start anchor point. + /// The end anchor point. + /// The first control point. + /// The second control point. + public BezierCurveCubic(float parallel, Vector2 startAnchor, Vector2 endAnchor, Vector2 firstControlPoint, Vector2 secondControlPoint) + { + this.Parallel = parallel; + this.StartAnchor = startAnchor; + this.EndAnchor = endAnchor; + this.FirstControlPoint = firstControlPoint; + this.SecondControlPoint = secondControlPoint; + } + + #endregion + + #region Functions + + /// + /// Calculates the point with the specified t. + /// + /// The t value, between 0.0f and 1.0f. + /// Resulting point. + public Vector2 CalculatePoint(float t) + { + Vector2 r = new Vector2(); + float c = 1.0f - t; + + r.X = (StartAnchor.X * c * c * c) + (FirstControlPoint.X * 3 * t * c * c) + (SecondControlPoint.X * 3 * t * t * c) + + EndAnchor.X * t * t * t; + r.Y = (StartAnchor.Y * c * c * c) + (FirstControlPoint.Y * 3 * t * c * c) + (SecondControlPoint.Y * 3 * t * t * c) + + EndAnchor.Y * t * t * t; + + if (Parallel == 0.0f) + return r; + + Vector2 perpendicular = new Vector2(); + + if (t == 0.0f) + perpendicular = FirstControlPoint - StartAnchor; + else + perpendicular = r - CalculatePointOfDerivative(t); + + return r + Vector2.Normalize(perpendicular).PerpendicularRight * Parallel; + } + + /// + /// Calculates the point with the specified t of the derivative of this function. + /// + /// The t, value between 0.0f and 1.0f. + /// Resulting point. + private Vector2 CalculatePointOfDerivative(float t) + { + Vector2 r = new Vector2(); + float c = 1.0f - t; + + r.X = (c * c * StartAnchor.X) + (2 * t * c * FirstControlPoint.X) + (t * t * SecondControlPoint.X); + r.Y = (c * c * StartAnchor.Y) + (2 * t * c * FirstControlPoint.Y) + (t * t * SecondControlPoint.Y); + + return r; + } + + /// + /// Calculates the length of this bezier curve. + /// + /// The precision. + /// Length of the curve. + /// The precision gets better when the + /// value gets smaller. + public float CalculateLength(float precision) + { + float length = 0.0f; + Vector2 old = CalculatePoint(0.0f); + + for (float i = precision; i < (1.0f + precision); i += precision) + { + Vector2 n = CalculatePoint(i); + length += (n - old).Length; + old = n; + } + + return length; + } + + #endregion + } +} diff --git a/src/MiniTK/Math/BezierCurveQuadric.cs b/src/MiniTK/Math/BezierCurveQuadric.cs new file mode 100644 index 0000000..500b7ff --- /dev/null +++ b/src/MiniTK/Math/BezierCurveQuadric.cs @@ -0,0 +1,151 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + * + * Contributions by Georg W�chter. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Represents a quadric bezier curve with two anchor and one control point. + /// + [Serializable] + public struct BezierCurveQuadric + { + #region Fields + + /// + /// Start anchor point. + /// + public Vector2 StartAnchor; + + /// + /// End anchor point. + /// + public Vector2 EndAnchor; + + /// + /// Control point, controls the direction of both endings of the curve. + /// + public Vector2 ControlPoint; + + /// + /// The parallel value. + /// + /// This value defines whether the curve should be calculated as a + /// parallel curve to the original bezier curve. A value of 0.0f represents + /// the original curve, 5.0f i.e. stands for a curve that has always a distance + /// of 5.f to the orignal curve at any point. + public float Parallel; + + #endregion + + #region Constructors + + /// + /// Constructs a new . + /// + /// The start anchor. + /// The end anchor. + /// The control point. + public BezierCurveQuadric(Vector2 startAnchor, Vector2 endAnchor, Vector2 controlPoint) + { + this.StartAnchor = startAnchor; + this.EndAnchor = endAnchor; + this.ControlPoint = controlPoint; + this.Parallel = 0.0f; + } + + /// + /// Constructs a new . + /// + /// The parallel value. + /// The start anchor. + /// The end anchor. + /// The control point. + public BezierCurveQuadric(float parallel, Vector2 startAnchor, Vector2 endAnchor, Vector2 controlPoint) + { + this.Parallel = parallel; + this.StartAnchor = startAnchor; + this.EndAnchor = endAnchor; + this.ControlPoint = controlPoint; + } + + #endregion + + #region Functions + + /// + /// Calculates the point with the specified t. + /// + /// The t value, between 0.0f and 1.0f. + /// Resulting point. + public Vector2 CalculatePoint(float t) + { + Vector2 r = new Vector2(); + float c = 1.0f - t; + + r.X = (c * c * StartAnchor.X) + (2 * t * c * ControlPoint.X) + (t * t * EndAnchor.X); + r.Y = (c * c * StartAnchor.Y) + (2 * t * c * ControlPoint.Y) + (t * t * EndAnchor.Y); + + if (Parallel == 0.0f) + return r; + + Vector2 perpendicular = new Vector2(); + + if (t == 0.0f) + perpendicular = ControlPoint - StartAnchor; + else + perpendicular = r - CalculatePointOfDerivative(t); + + return r + Vector2.Normalize(perpendicular).PerpendicularRight * Parallel; + } + + /// + /// Calculates the point with the specified t of the derivative of this function. + /// + /// The t, value between 0.0f and 1.0f. + /// Resulting point. + private Vector2 CalculatePointOfDerivative(float t) + { + Vector2 r = new Vector2(); + + r.X = (1.0f - t) * StartAnchor.X + t * ControlPoint.X; + r.Y = (1.0f - t) * StartAnchor.Y + t * ControlPoint.Y; + + return r; + } + + /// + /// Calculates the length of this bezier curve. + /// + /// The precision. + /// Length of curve. + /// The precision gets better when the + /// value gets smaller. + public float CalculateLength(float precision) + { + float length = 0.0f; + Vector2 old = CalculatePoint(0.0f); + + for (float i = precision; i < (1.0f + precision); i += precision) + { + Vector2 n = CalculatePoint(i); + length += (n - old).Length; + old = n; + } + + return length; + } + + #endregion + } +} diff --git a/src/MiniTK/Math/Box2.cs b/src/MiniTK/Math/Box2.cs new file mode 100644 index 0000000..4c54b62 --- /dev/null +++ b/src/MiniTK/Math/Box2.cs @@ -0,0 +1,99 @@ +#region --- License --- +/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos + * See license.txt for license info + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +namespace OpenTK +{ + /// + /// Defines a 2d box (rectangle). + /// + [StructLayout(LayoutKind.Sequential)] + public struct Box2 + { + /// + /// The left boundary of the structure. + /// + public float Left; + + /// + /// The right boundary of the structure. + /// + public float Right; + + /// + /// The top boundary of the structure. + /// + public float Top; + + /// + /// The bottom boundary of the structure. + /// + public float Bottom; + + /// + /// Constructs a new Box2 with the specified dimensions. + /// + /// AnOpenTK.Vector2 describing the top-left corner of the Box2. + /// An OpenTK.Vector2 describing the bottom-right corner of the Box2. + public Box2(Vector2 topLeft, Vector2 bottomRight) + { + Left = topLeft.X; + Top = topLeft.Y; + Right = bottomRight.X; + Bottom = bottomRight.Y; + } + + /// + /// Constructs a new Box2 with the specified dimensions. + /// + /// The position of the left boundary. + /// The position of the top boundary. + /// The position of the right boundary. + /// The position of the bottom boundary. + public Box2(float left, float top, float right, float bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + /// + /// Creates a new Box2 with the specified dimensions. + /// + /// The position of the top boundary. + /// The position of the left boundary. + /// The position of the right boundary. + /// The position of the bottom boundary. + /// A new OpenTK.Box2 with the specfied dimensions. + public static Box2 FromTLRB(float top, float left, float right, float bottom) + { + return new Box2(left, top, right, bottom); + } + + /// + /// Gets a float describing the width of the Box2 structure. + /// + public float Width { get { return (float)System.Math.Abs(Right - Left); } } + + /// + /// Gets a float describing the height of the Box2 structure. + /// + public float Height { get { return (float)System.Math.Abs(Bottom - Top); } } + + /// + /// Returns a describing the current instance. + /// + /// + public override string ToString() + { + return String.Format("({0},{1})-({2},{3})", Left, Top, Right, Bottom); + } + } +} diff --git a/src/MiniTK/Math/Functions.cs b/src/MiniTK/Math/Functions.cs new file mode 100644 index 0000000..15fd0f6 --- /dev/null +++ b/src/MiniTK/Math/Functions.cs @@ -0,0 +1,371 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + * + * Contributions by Andy Gill, James Talton and Georg Wächter. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Contains mathematical functions for the OpenTK.Math toolkit. + /// + [Obsolete("Use OpenTK.MathHelper instead.")] + public static class Functions + { + #region NextPowerOfTwo + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static long NextPowerOfTwo(long n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (long)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static int NextPowerOfTwo(int n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (int)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static float NextPowerOfTwo(float n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (float)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static double NextPowerOfTwo(double n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + #endregion + + #region Factorial + + /// Calculates the factorial of a given natural number. + /// + /// The number. + /// n! + public static long Factorial(int n) + { + long result = 1; + + for (; n > 1; n--) + result *= n; + + return result; + } + + #endregion + + #region BinomialCoefficient + + /// + /// Calculates the binomial coefficient above . + /// + /// The n. + /// The k. + /// n! / (k! * (n - k)!) + public static long BinomialCoefficient(int n, int k) + { + return Factorial(n) / (Factorial(k) * Factorial(n - k)); + } + + #endregion + + #region InverseSqrtFast + + /// + /// Returns an approximation of the inverse square root of left number. + /// + /// A number. + /// An approximation of the inverse square root of the specified number, with an upper error bound of 0.001 + /// + /// This is an improved implementation of the the method known as Carmack's inverse square root + /// which is found in the Quake III source code. This implementation comes from + /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see + /// http://www.beyond3d.com/content/articles/8/ + /// + public static float InverseSqrtFast(float x) + { + unsafe + { + float xhalf = 0.5f * x; + int i = *(int*)&x; // Read bits as integer. + i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation + x = *(float*)&i; // Convert bits back to float + x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step. + return x; + } + } + + /// + /// Returns an approximation of the inverse square root of left number. + /// + /// A number. + /// An approximation of the inverse square root of the specified number, with an upper error bound of 0.001 + /// + /// This is an improved implementation of the the method known as Carmack's inverse square root + /// which is found in the Quake III source code. This implementation comes from + /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see + /// http://www.beyond3d.com/content/articles/8/ + /// + public static double InverseSqrtFast(double x) + { + return InverseSqrtFast((float)x); + // TODO: The following code is wrong. Fix it, to improve precision. +#if false + unsafe + { + double xhalf = 0.5f * x; + int i = *(int*)&x; // Read bits as integer. + i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation + x = *(float*)&i; // Convert bits back to float + x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step. + return x; + } +#endif + } + + #endregion + + #region DegreesToRadians + + /// + /// Convert degrees to radians + /// + /// An angle in degrees + /// The angle expressed in radians + public static float DegreesToRadians(float degrees) + { + const float degToRad = (float)System.Math.PI / 180.0f; + return degrees * degToRad; + } + + /// + /// Convert radians to degrees + /// + /// An angle in radians + /// The angle expressed in degrees + public static float RadiansToDegrees(float radians) + { + const float radToDeg = 180.0f / (float)System.Math.PI; + return radians * radToDeg; + } + + #endregion + + #region Mathematical constants + + /// + /// Obsolete. Do not use. + /// + public static readonly float PIF = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930382f; + + /// + /// Obsolete. Do not use. + /// + public static readonly float RTODF = 180.0f / PIF; + + /// + /// Obsolete. Do not use. + /// + public static readonly float DTORF = PIF / 180.0f; + + /// + /// Obsolete. Do not use. + /// + public static readonly double PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930382d; + + /// + /// Obsolete. Do not use. + /// + public static readonly double RTOD = 180.0d / PIF; + + /// + /// Obsolete. Do not use. + /// + public static readonly double DTOR = PIF / 180.0d; + + #endregion + + #region Swap + + /// + /// Swaps two float values. + /// + /// The first value. + /// The second value. + public static void Swap(ref double a, ref double b) + { + double temp = a; + a = b; + b = temp; + } + + /// + /// Swaps two float values. + /// + /// The first value. + /// The second value. + public static void Swap(ref float a, ref float b) + { + float temp = a; + a = b; + b = temp; + } + + #endregion + } + +#if false + public static partial class Math + { + #region --- Vectors --- + + #region --- Addition --- + + /// + /// Adds the given Vector2 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector2 Add(Vector2 left, Vector2 right) + { + return new Vector2(left).Add(right); + } + + /// + /// Adds the given Vector3 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector3 Add(Vector2 left, Vector3 right) + { + return new Vector3(left).Add(right); + } + + /// + /// Adds the given Vector4 to the current Vector3. W-coordinate remains unaffected. + /// + /// The right operand of the addition. + /// A new Vector4 containing the result of the addition. + public static Vector4 Add(Vector2 left, Vector4 right) + { + return new Vector4(left).Add(right); + } + + /// + /// Adds the given Vector2 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector3 Add(Vector3 left, Vector2 right) + { + return new Vector3(left).Add(right); + } + + /// + /// Adds the given Vector3 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector3 Add(Vector3 left, Vector3 right) + { + return new Vector3(left).Add(right); + } + + /// + /// Adds the given Vector4 to the current Vector3. W-coordinate remains unaffected. + /// + /// The right operand of the addition. + /// A new Vector4 containing the result of the addition. + public static Vector4 Add(Vector3 left, Vector4 right) + { + return new Vector4(left).Add(right); + } + + /// + /// Adds the given Vector2 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector4 Add(Vector4 left, Vector2 right) + { + return new Vector4(left).Add(right); + } + + /// + /// Adds the given Vector3 to the current Vector3. + /// + /// The right operand of the addition. + /// A new Vector3 containing the result of the addition. + public static Vector4 Add(Vector4 left, Vector3 right) + { + return new Vector4(left).Add(right); + } + + /// + /// Adds the given Vector4 to the current Vector3. W-coordinate remains unaffected. + /// + /// The right operand of the addition. + /// A new Vector4 containing the result of the addition. + public static Vector4 Add(Vector4 left, Vector4 right) + { + return new Vector4(left).Add(right); + } + + #endregion + + #region --- Subtraction --- + + + + #endregion + + #region --- Cross --- + + /// + /// Computes the cross product between the current and the given Vector3. The current Vector3 is set to the result of the computation. + /// + /// The right operand of the cross product + /// The current + public static Vector3 Cross(Vector3 left, Vector3 right) + { + return new Vector3(left).Cross(right); + } + + #endregion + + #endregion + } +#endif +} diff --git a/src/MiniTK/Math/Half.cs b/src/MiniTK/Math/Half.cs new file mode 100644 index 0000000..3e5f406 --- /dev/null +++ b/src/MiniTK/Math/Half.cs @@ -0,0 +1,588 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +/* +The conversion functions are derived from OpenEXR's implementation and are +governed by the following license: + +Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +Digital Ltd. LLC + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. +* Neither the name of Industrial Light & Magic nor the names of +its contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#endregion --- License --- + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace OpenTK +{ + + /// + /// The name Half is derived from half-precision floating-point number. + /// It occupies only 16 bits, which are split into 1 Sign bit, 5 Exponent bits and 10 Mantissa bits. + /// + /// + /// Quote from ARB_half_float_pixel specification: + /// Any representable 16-bit floating-point value is legal as input to a GL command that accepts 16-bit floating-point data. The + /// result of providing a value that is not a floating-point number (such as infinity or NaN) to such a command is unspecified, + /// but must not lead to GL interruption or termination. Providing a denormalized number or negative zero to GL must yield + /// predictable results. + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct Half : ISerializable, IComparable, IFormattable, IEquatable + { + #region Internal Field + + UInt16 bits; + + #endregion Internal Field + + #region Properties + + /// Returns true if the Half is zero. + public bool IsZero { get { return (bits == 0) || (bits == 0x8000); } } + + /// Returns true if the Half represents Not A Number (NaN) + public bool IsNaN { get { return (((bits & 0x7C00) == 0x7C00) && (bits & 0x03FF) != 0x0000); } } + + /// Returns true if the Half represents positive infinity. + public bool IsPositiveInfinity { get { return (bits == 31744); } } + + /// Returns true if the Half represents negative infinity. + public bool IsNegativeInfinity { get { return (bits == 64512); } } + + #endregion Properties + + #region Constructors + + /// + /// The new Half instance will convert the parameter into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + public Half(Single f) + : this() + { + unsafe + { + bits = SingleToHalf(*(int*)&f); + } + } + + /// + /// The new Half instance will convert the parameter into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// Enable checks that will throw if the conversion result is not meaningful. + public Half(Single f, bool throwOnError) + : this(f) + { + if (throwOnError) + { + // handle cases that cause overflow rather than silently ignoring it + if (f > Half.MaxValue) throw new ArithmeticException("Half: Positive maximum value exceeded."); + if (f < -Half.MaxValue) throw new ArithmeticException("Half: Negative minimum value exceeded."); + + // handle cases that make no sense + if (Single.IsNaN(f)) throw new ArithmeticException("Half: Input is not a number (NaN)."); + if (Single.IsPositiveInfinity(f)) throw new ArithmeticException("Half: Input is positive infinity."); + if (Single.IsNegativeInfinity(f)) throw new ArithmeticException("Half: Input is negative infinity."); + } + } + + /// + /// The new Half instance will convert the parameter into 16-bit half-precision floating-point. + /// + /// 64-bit double-precision floating-point number. + public Half(Double d) : this((Single)d) { } + + /// + /// The new Half instance will convert the parameter into 16-bit half-precision floating-point. + /// + /// 64-bit double-precision floating-point number. + /// Enable checks that will throw if the conversion result is not meaningful. + public Half(Double d, bool throwOnError) : this((Single)d, throwOnError) { } + + #endregion Constructors + + #region Single -> Half + + /// Ported from OpenEXR's IlmBase 1.0.1 + private UInt16 SingleToHalf(Int32 si32) + { + // Our floating point number, F, is represented by the bit pattern in integer i. + // Disassemble that bit pattern into the sign, S, the exponent, E, and the significand, M. + // Shift S into the position where it will go in in the resulting half number. + // Adjust E, accounting for the different exponent bias of float and half (127 versus 15). + + Int32 sign = (si32 >> 16) & 0x00008000; + Int32 exponent = ((si32 >> 23) & 0x000000ff) - (127 - 15); + Int32 mantissa = si32 & 0x007fffff; + + // Now reassemble S, E and M into a half: + + if (exponent <= 0) + { + if (exponent < -10) + { + // E is less than -10. The absolute value of F is less than Half.MinValue + // (F may be a small normalized float, a denormalized float or a zero). + // + // We convert F to a half zero with the same sign as F. + + return (UInt16)sign; + } + + // E is between -10 and 0. F is a normalized float whose magnitude is less than Half.MinNormalizedValue. + // + // We convert F to a denormalized half. + + // Add an explicit leading 1 to the significand. + + mantissa = mantissa | 0x00800000; + + // Round to M to the nearest (10+E)-bit value (with E between -10 and 0); in case of a tie, round to the nearest even value. + // + // Rounding may cause the significand to overflow and make our number normalized. Because of the way a half's bits + // are laid out, we don't have to treat this case separately; the code below will handle it correctly. + + Int32 t = 14 - exponent; + Int32 a = (1 << (t - 1)) - 1; + Int32 b = (mantissa >> t) & 1; + + mantissa = (mantissa + a + b) >> t; + + // Assemble the half from S, E (==zero) and M. + + return (UInt16)(sign | mantissa); + } + else if (exponent == 0xff - (127 - 15)) + { + if (mantissa == 0) + { + // F is an infinity; convert F to a half infinity with the same sign as F. + + return (UInt16)(sign | 0x7c00); + } + else + { + // F is a NAN; we produce a half NAN that preserves the sign bit and the 10 leftmost bits of the + // significand of F, with one exception: If the 10 leftmost bits are all zero, the NAN would turn + // into an infinity, so we have to set at least one bit in the significand. + + mantissa >>= 13; + return (UInt16)(sign | 0x7c00 | mantissa | ((mantissa == 0) ? 1 : 0)); + } + } + else + { + // E is greater than zero. F is a normalized float. We try to convert F to a normalized half. + + // Round to M to the nearest 10-bit value. In case of a tie, round to the nearest even value. + + mantissa = mantissa + 0x00000fff + ((mantissa >> 13) & 1); + + if ((mantissa & 0x00800000) == 1) + { + mantissa = 0; // overflow in significand, + exponent += 1; // adjust exponent + } + + // exponent overflow + if (exponent > 30) throw new ArithmeticException("Half: Hardware floating-point overflow."); + + // Assemble the half from S, E and M. + + return (UInt16)(sign | (exponent << 10) | (mantissa >> 13)); + } + } + + #endregion Single -> Half + + #region Half -> Single + + /// Converts the 16-bit half to 32-bit floating-point. + /// A single-precision floating-point number. + public Single ToSingle() + { + int i = HalfToFloat(bits); + + unsafe + { + return *(float*)&i; + } + } + + /// Ported from OpenEXR's IlmBase 1.0.1 + private Int32 HalfToFloat(UInt16 ui16) + { + + Int32 sign = (ui16 >> 15) & 0x00000001; + Int32 exponent = (ui16 >> 10) & 0x0000001f; + Int32 mantissa = ui16 & 0x000003ff; + + if (exponent == 0) + { + if (mantissa == 0) + { + // Plus or minus zero + + return sign << 31; + } + else + { + // Denormalized number -- renormalize it + + while ((mantissa & 0x00000400) == 0) + { + mantissa <<= 1; + exponent -= 1; + } + + exponent += 1; + mantissa &= ~0x00000400; + } + } + else if (exponent == 31) + { + if (mantissa == 0) + { + // Positive or negative infinity + + return (sign << 31) | 0x7f800000; + } + else + { + // Nan -- preserve sign and significand bits + + return (sign << 31) | 0x7f800000 | (mantissa << 13); + } + } + + // Normalized number + + exponent = exponent + (127 - 15); + mantissa = mantissa << 13; + + // Assemble S, E and M. + + return (sign << 31) | (exponent << 23) | mantissa; + } + + #endregion Half -> Single + + #region Conversions + + /// + /// Converts a System.Single to a OpenTK.Half. + /// + /// The value to convert. + /// A + /// + /// The result of the conversion. + /// A + /// + public static explicit operator Half(float f) + { + return new Half(f); + } + + /// + /// Converts a System.Double to a OpenTK.Half. + /// + /// The value to convert. + /// A + /// + /// The result of the conversion. + /// A + /// + public static explicit operator Half(double d) + { + return new Half(d); + } + + /// + /// Converts a OpenTK.Half to a System.Single. + /// + /// The value to convert. + /// A + /// + /// The result of the conversion. + /// A + /// + public static implicit operator float(Half h) + { + return h.ToSingle(); + } + + /// + /// Converts a OpenTK.Half to a System.Double. + /// + /// The value to convert. + /// A + /// + /// The result of the conversion. + /// A + /// + public static implicit operator double(Half h) + { + return (double)h.ToSingle(); + } + + #endregion Conversions + + #region Constants + + /// The size in bytes for an instance of the Half struct. + public static readonly Int32 SizeInBytes = 2; + + /// Smallest positive half + public static readonly Single MinValue = 5.96046448e-08f; + + /// Smallest positive normalized half + public static readonly Single MinNormalizedValue = 6.10351562e-05f; + + /// Largest positive half + public static readonly Single MaxValue = 65504.0f; + + /// Smallest positive e for which half (1.0 + e) != half (1.0) + public static readonly Single Epsilon = 0.00097656f; + + #endregion Constants + + #region ISerializable + + /// Constructor used by ISerializable to deserialize the object. + /// + /// + public Half(SerializationInfo info, StreamingContext context) + { + this.bits = (ushort)info.GetValue("bits", typeof(ushort)); + } + + /// Used by ISerialize to serialize the object. + /// + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("bits", this.bits); + } + + #endregion ISerializable + + #region Binary dump + + /// Updates the Half by reading from a Stream. + /// A BinaryReader instance associated with an open Stream. + public void FromBinaryStream(BinaryReader bin) + { + this.bits = bin.ReadUInt16(); + + } + + /// Writes the Half into a Stream. + /// A BinaryWriter instance associated with an open Stream. + public void ToBinaryStream(BinaryWriter bin) + { + bin.Write(this.bits); + } + + #endregion Binary dump + + #region IEquatable Members + + const int maxUlps = 1; + + /// + /// Returns a value indicating whether this instance is equal to a specified OpenTK.Half value. + /// + /// OpenTK.Half object to compare to this instance.. + /// True, if other is equal to this instance; false otherwise. + public bool Equals(Half other) + { + short aInt, bInt; + unchecked { aInt = (short)other.bits; } + unchecked { bInt = (short)this.bits; } + + // Make aInt lexicographically ordered as a twos-complement int + if (aInt < 0) + aInt = (short)(0x8000 - aInt); + + // Make bInt lexicographically ordered as a twos-complement int + if (bInt < 0) + bInt = (short)(0x8000 - bInt); + + short intDiff = System.Math.Abs((short)(aInt - bInt)); + + if (intDiff <= maxUlps) + return true; + + return false; + } + + #endregion + + #region IComparable Members + + /// + /// Compares this instance to a specified half-precision floating-point number + /// and returns an integer that indicates whether the value of this instance + /// is less than, equal to, or greater than the value of the specified half-precision + /// floating-point number. + /// + /// A half-precision floating-point number to compare. + /// + /// A signed number indicating the relative values of this instance and value. If the number is: + /// Less than zero, then this instance is less than other, or this instance is not a number + /// (OpenTK.Half.NaN) and other is a number. + /// Zero: this instance is equal to value, or both this instance and other + /// are not a number (OpenTK.Half.NaN), OpenTK.Half.PositiveInfinity, or + /// OpenTK.Half.NegativeInfinity. + /// Greater than zero: this instance is greater than othrs, or this instance is a number + /// and other is not a number (OpenTK.Half.NaN). + /// + public int CompareTo(Half other) + { + return ((float)this).CompareTo((float)other); + } + + #endregion IComparable Members + + #region IFormattable Members + + /// Converts this Half into a human-legible string representation. + /// The string representation of this instance. + public override string ToString() + { + return this.ToSingle().ToString(); + } + + /// Converts this Half into a human-legible string representation. + /// Formatting for the output string. + /// Culture-specific formatting information. + /// The string representation of this instance. + public string ToString(string format, IFormatProvider formatProvider) + { + return this.ToSingle().ToString(format, formatProvider); + } + + #endregion IFormattable Members + + #region String -> Half + + /// Converts the string representation of a number to a half-precision floating-point equivalent. + /// String representation of the number to convert. + /// A new Half instance. + public static Half Parse(string s) + { + return (Half)Single.Parse(s); + } + + /// Converts the string representation of a number to a half-precision floating-point equivalent. + /// String representation of the number to convert. + /// Specifies the format of s. + /// Culture-specific formatting information. + /// A new Half instance. + public static Half Parse(string s, System.Globalization.NumberStyles style, IFormatProvider provider) + { + return (Half)Single.Parse(s, style, provider); + } + + /// Converts the string representation of a number to a half-precision floating-point equivalent. Returns success. + /// String representation of the number to convert. + /// The Half instance to write to. + /// Success. + public static bool TryParse(string s, out Half result) + { + float f; + bool b = Single.TryParse(s, out f); + result = (Half)f; + return b; + } + + /// Converts the string representation of a number to a half-precision floating-point equivalent. Returns success. + /// String representation of the number to convert. + /// Specifies the format of s. + /// Culture-specific formatting information. + /// The Half instance to write to. + /// Success. + public static bool TryParse(string s, System.Globalization.NumberStyles style, IFormatProvider provider, out Half result) + { + float f; + bool b = Single.TryParse(s, style, provider, out f); + result = (Half)f; + return b; + } + + #endregion String -> Half + + #region BitConverter + + /// Returns the Half as an array of bytes. + /// The Half to convert. + /// The input as byte array. + public static byte[] GetBytes(Half h) + { + return BitConverter.GetBytes(h.bits); + } + + /// Converts an array of bytes into Half. + /// A Half in it's byte[] representation. + /// The starting position within value. + /// A new Half instance. + public static Half FromBytes(byte[] value, int startIndex) + { + Half h; + h.bits = BitConverter.ToUInt16(value, startIndex); + return h; + } + + #endregion BitConverter + } +} \ No newline at end of file diff --git a/src/MiniTK/Math/MathHelper.cs b/src/MiniTK/Math/MathHelper.cs new file mode 100644 index 0000000..215f540 --- /dev/null +++ b/src/MiniTK/Math/MathHelper.cs @@ -0,0 +1,293 @@ +#region --- License --- +/* Licensed under the MIT/X11 license. + * Copyright (c) 2006-2008 the OpenTK Team. + * This notice may not be removed from any source distribution. + * See license.txt for licensing detailed licensing details. + * + * Contributions by Andy Gill, James Talton and Georg Wächter. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ + /// + /// Contains common mathematical functions and constants. + /// + public static class MathHelper + { + #region Fields + + /// + /// Defines the value of Pi as a . + /// + public const float Pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930382f; + + /// + /// Defines the value of Pi divided by two as a . + /// + public const float PiOver2 = Pi / 2; + + /// + /// Defines the value of Pi divided by three as a . + /// + public const float PiOver3 = Pi / 3; + + /// + /// Definesthe value of Pi divided by four as a . + /// + public const float PiOver4 = Pi / 4; + + /// + /// Defines the value of Pi divided by six as a . + /// + public const float PiOver6 = Pi / 6; + + /// + /// Defines the value of Pi multiplied by two as a . + /// + public const float TwoPi = 2 * Pi; + + /// + /// Defines the value of Pi multiplied by 3 and divided by two as a . + /// + public const float ThreePiOver2 = 3 * Pi / 2; + + /// + /// Defines the value of E as a . + /// + public const float E = 2.71828182845904523536f; + + /// + /// Defines the base-10 logarithm of E. + /// + public const float Log10E = 0.434294482f; + + /// + /// Defines the base-2 logarithm of E. + /// + public const float Log2E = 1.442695041f; + + #endregion + + #region Public Members + + #region NextPowerOfTwo + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static long NextPowerOfTwo(long n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (long)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static int NextPowerOfTwo(int n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (int)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static float NextPowerOfTwo(float n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return (float)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + /// + /// Returns the next power of two that is larger than the specified number. + /// + /// The specified number. + /// The next power of two. + public static double NextPowerOfTwo(double n) + { + if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive."); + return System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2))); + } + + #endregion + + #region Factorial + + /// Calculates the factorial of a given natural number. + /// + /// The number. + /// n! + public static long Factorial(int n) + { + long result = 1; + + for (; n > 1; n--) + result *= n; + + return result; + } + + #endregion + + #region BinomialCoefficient + + /// + /// Calculates the binomial coefficient above . + /// + /// The n. + /// The k. + /// n! / (k! * (n - k)!) + public static long BinomialCoefficient(int n, int k) + { + return Factorial(n) / (Factorial(k) * Factorial(n - k)); + } + + #endregion + + #region InverseSqrtFast + + /// + /// Returns an approximation of the inverse square root of left number. + /// + /// A number. + /// An approximation of the inverse square root of the specified number, with an upper error bound of 0.001 + /// + /// This is an improved implementation of the the method known as Carmack's inverse square root + /// which is found in the Quake III source code. This implementation comes from + /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see + /// http://www.beyond3d.com/content/articles/8/ + /// + public static float InverseSqrtFast(float x) + { + unsafe + { + float xhalf = 0.5f * x; + int i = *(int*)&x; // Read bits as integer. + i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation + x = *(float*)&i; // Convert bits back to float + x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step. + return x; + } + } + + /// + /// Returns an approximation of the inverse square root of left number. + /// + /// A number. + /// An approximation of the inverse square root of the specified number, with an upper error bound of 0.001 + /// + /// This is an improved implementation of the the method known as Carmack's inverse square root + /// which is found in the Quake III source code. This implementation comes from + /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see + /// http://www.beyond3d.com/content/articles/8/ + /// + public static double InverseSqrtFast(double x) + { + return InverseSqrtFast((float)x); + // TODO: The following code is wrong. Fix it, to improve precision. +#if false + unsafe + { + double xhalf = 0.5f * x; + int i = *(int*)&x; // Read bits as integer. + i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation + x = *(float*)&i; // Convert bits back to float + x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step. + return x; + } +#endif + } + + #endregion + + #region DegreesToRadians + + /// + /// Convert degrees to radians + /// + /// An angle in degrees + /// The angle expressed in radians + public static float DegreesToRadians(float degrees) + { + const float degToRad = (float)System.Math.PI / 180.0f; + return degrees * degToRad; + } + + /// + /// Convert radians to degrees + /// + /// An angle in radians + /// The angle expressed in degrees + public static float RadiansToDegrees(float radians) + { + const float radToDeg = 180.0f / (float)System.Math.PI; + return radians * radToDeg; + } + + /// + /// Convert degrees to radians + /// + /// An angle in degrees + /// The angle expressed in radians + public static double DegreesToRadians(double degrees) + { + const double degToRad = System.Math.PI / 180.0; + return degrees * degToRad; + } + + /// + /// Convert radians to degrees + /// + /// An angle in radians + /// The angle expressed in degrees + public static double RadiansToDegrees(double radians) + { + const double radToDeg = 180.0 / System.Math.PI; + return radians * radToDeg; + } + + #endregion + + #region Swap + + /// + /// Swaps two double values. + /// + /// The first value. + /// The second value. + public static void Swap(ref double a, ref double b) + { + double temp = a; + a = b; + b = temp; + } + + /// + /// Swaps two float values. + /// + /// The first value. + /// The second value. + public static void Swap(ref float a, ref float b) + { + float temp = a; + a = b; + b = temp; + } + + #endregion + + #endregion + } +} diff --git a/src/MiniTK/Math/Matrix3d.cs b/src/MiniTK/Math/Matrix3d.cs new file mode 100644 index 0000000..800d799 --- /dev/null +++ b/src/MiniTK/Math/Matrix3d.cs @@ -0,0 +1,828 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + // Todo: Remove this warning when the code goes public. + #pragma warning disable 3019 +#if false + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Matrix3d : IEquatable + { + #region Fields & Access + + /// Row 0, Column 0 + public double R0C0; + + /// Row 0, Column 1 + public double R0C1; + + /// Row 0, Column 2 + public double R0C2; + + /// Row 1, Column 0 + public double R1C0; + + /// Row 1, Column 1 + public double R1C1; + + /// Row 1, Column 2 + public double R1C2; + + /// Row 2, Column 0 + public double R2C0; + + /// Row 2, Column 1 + public double R2C1; + + /// Row 2, Column 2 + public double R2C2; + + /// Gets the component at the given row and column in the matrix. + /// The row of the matrix. + /// The column of the matrix. + /// The component at the given row and column in the matrix. + public double this[int row, int column] + { + get + { + switch( row ) + { + case 0: + switch (column) + { + case 0: return R0C0; + case 1: return R0C1; + case 2: return R0C2; + } + break; + + case 1: + switch (column) + { + case 0: return R1C0; + case 1: return R1C1; + case 2: return R1C2; + } + break; + + case 2: + switch (column) + { + case 0: return R2C0; + case 1: return R2C1; + case 2: return R2C2; + } + break; + } + + throw new IndexOutOfRangeException(); + } + set + { + switch( row ) + { + case 0: + switch (column) + { + case 0: R0C0 = value; return; + case 1: R0C1 = value; return; + case 2: R0C2 = value; return; + } + break; + + case 1: + switch (column) + { + case 0: R1C0 = value; return; + case 1: R1C1 = value; return; + case 2: R1C2 = value; return; + } + break; + + case 2: + switch (column) + { + case 0: R2C0 = value; return; + case 1: R2C1 = value; return; + case 2: R2C2 = value; return; + } + break; + } + + throw new IndexOutOfRangeException(); + } + } + + /// Gets the component at the index into the matrix. + /// The index into the components of the matrix. + /// The component at the given index into the matrix. + public double this[int index] + { + get + { + switch (index) + { + case 0: return R0C0; + case 1: return R0C1; + case 2: return R0C2; + case 3: return R1C0; + case 4: return R1C1; + case 5: return R1C2; + case 6: return R2C0; + case 7: return R2C1; + case 8: return R2C2; + default: throw new IndexOutOfRangeException(); + } + } + set + { + switch (index) + { + case 0: R0C0 = value; return; + case 1: R0C1 = value; return; + case 2: R0C2 = value; return; + case 3: R1C0 = value; return; + case 4: R1C1 = value; return; + case 5: R1C2 = value; return; + case 6: R2C0 = value; return; + case 7: R2C1 = value; return; + case 8: R2C2 = value; return; + default: throw new IndexOutOfRangeException(); + } + } + } + + /// Converts the matrix into an IntPtr. + /// The matrix to convert. + /// An IntPtr for the matrix. + public static explicit operator IntPtr(Matrix3d matrix) + { + unsafe + { + return (IntPtr)(&matrix.R0C0); + } + } + + /// Converts the matrix into left double*. + /// The matrix to convert. + /// A double* for the matrix. + [CLSCompliant(false)] + unsafe public static explicit operator double*(Matrix3d matrix) + { + return &matrix.R0C0; + } + + /// Converts the matrix into an array of doubles. + /// The matrix to convert. + /// An array of doubles for the matrix. + public static explicit operator double[](Matrix3d matrix) + { + return new double[9] + { + matrix.R0C0, + matrix.R0C1, + matrix.R0C2, + matrix.R1C0, + matrix.R1C1, + matrix.R1C2, + matrix.R2C0, + matrix.R2C1, + matrix.R2C2 + }; + } + + #endregion + + #region Constructors + + /// Constructs left matrix with the same components as the given matrix. + /// The matrix whose components to copy. + public Matrix3d(ref Matrix3d matrix) + { + this.R0C0 = matrix.R0C0; + this.R0C1 = matrix.R0C1; + this.R0C2 = matrix.R0C2; + this.R1C0 = matrix.R1C0; + this.R1C1 = matrix.R1C1; + this.R1C2 = matrix.R1C2; + this.R2C0 = matrix.R2C0; + this.R2C1 = matrix.R2C1; + this.R2C2 = matrix.R2C2; + } + + /// Constructs left matrix with the given values. + /// The value for row 0 column 0. + /// The value for row 0 column 1. + /// The value for row 0 column 2. + /// The value for row 1 column 0. + /// The value for row 1 column 1. + /// The value for row 1 column 2. + /// The value for row 2 column 0. + /// The value for row 2 column 1. + /// The value for row 2 column 2. + public Matrix3d + ( + double r0c0, + double r0c1, + double r0c2, + double r1c0, + double r1c1, + double r1c2, + double r2c0, + double r2c1, + double r2c2 + ) + { + this.R0C0 = r0c0; + this.R0C1 = r0c1; + this.R0C2 = r0c2; + this.R1C0 = r1c0; + this.R1C1 = r1c1; + this.R1C2 = r1c2; + this.R2C0 = r2c0; + this.R2C1 = r2c1; + this.R2C2 = r2c2; + } + + /// Constructs left matrix from the given array of double-precision floating-point numbers. + /// The array of doubles for the components of the matrix. + public Matrix3d(double[] doubleArray) + { + if (doubleArray == null || doubleArray.GetLength(0) < 9) throw new MissingFieldException(); + + this.R0C0 = doubleArray[0]; + this.R0C1 = doubleArray[1]; + this.R0C2 = doubleArray[2]; + this.R1C0 = doubleArray[3]; + this.R1C1 = doubleArray[4]; + this.R1C2 = doubleArray[5]; + this.R2C0 = doubleArray[6]; + this.R2C1 = doubleArray[7]; + this.R2C2 = doubleArray[8]; + } + + /// Constructs left matrix from the given quaternion. + /// The quaternion to use to construct the martix. + public Matrix3d(Quaterniond quaternion) + { + quaternion.Normalize(); + + double xx = quaternion.X * quaternion.X; + double yy = quaternion.Y * quaternion.Y; + double zz = quaternion.Z * quaternion.Z; + double xy = quaternion.X * quaternion.Y; + double xz = quaternion.X * quaternion.Z; + double yz = quaternion.Y * quaternion.Z; + double wx = quaternion.W * quaternion.X; + double wy = quaternion.W * quaternion.Y; + double wz = quaternion.W * quaternion.Z; + + R0C0 = 1 - 2 * (yy + zz); + R0C1 = 2 * (xy - wz); + R0C2 = 2 * (xz + wy); + + R1C0 = 2 * (xy + wz); + R1C1 = 1 - 2 * (xx + zz); + R1C2 = 2 * (yz - wx); + + R2C0 = 2 * (xz - wy); + R2C1 = 2 * (yz + wx); + R2C2 = 1 - 2 * (xx + yy); + } + + #endregion + + #region Equality + + /// Indicates whether the current matrix is equal to another matrix. + /// The OpenTK.Matrix3d structure to compare with. + /// true if the current matrix is equal to the matrix parameter; otherwise, false. + [CLSCompliant(false)] + public bool Equals(Matrix3d matrix) + { + return + R0C0 == matrix.R0C0 && + R0C1 == matrix.R0C1 && + R0C2 == matrix.R0C2 && + R1C0 == matrix.R1C0 && + R1C1 == matrix.R1C1 && + R1C2 == matrix.R1C2 && + R2C0 == matrix.R2C0 && + R2C1 == matrix.R2C1 && + R2C2 == matrix.R2C2; + } + + /// Indicates whether the current matrix is equal to another matrix. + /// The OpenTK.Matrix3d structure to compare to. + /// true if the current matrix is equal to the matrix parameter; otherwise, false. + public bool Equals(ref Matrix3d matrix) + { + return + R0C0 == matrix.R0C0 && + R0C1 == matrix.R0C1 && + R0C2 == matrix.R0C2 && + R1C0 == matrix.R1C0 && + R1C1 == matrix.R1C1 && + R1C2 == matrix.R1C2 && + R2C0 == matrix.R2C0 && + R2C1 == matrix.R2C1 && + R2C2 == matrix.R2C2; + } + + /// Indicates whether the current matrix is equal to another matrix. + /// The left-hand operand. + /// The right-hand operand. + /// true if the current matrix is equal to the matrix parameter; otherwise, false. + public static bool Equals(ref Matrix3d left, ref Matrix3d right) + { + return + left.R0C0 == right.R0C0 && + left.R0C1 == right.R0C1 && + left.R0C2 == right.R0C2 && + left.R1C0 == right.R1C0 && + left.R1C1 == right.R1C1 && + left.R1C2 == right.R1C2 && + left.R2C0 == right.R2C0 && + left.R2C1 == right.R2C1 && + left.R2C2 == right.R2C2; + } + + /// Indicates whether the current matrix is approximately equal to another matrix. + /// The OpenTK.Matrix3d structure to compare with. + /// The limit below which the matrices are considered equal. + /// true if the current matrix is approximately equal to the matrix parameter; otherwise, false. + public bool EqualsApprox(ref Matrix3d matrix, double tolerance) + { + return + System.Math.Abs(R0C0 - matrix.R0C0) <= tolerance && + System.Math.Abs(R0C1 - matrix.R0C1) <= tolerance && + System.Math.Abs(R0C2 - matrix.R0C2) <= tolerance && + System.Math.Abs(R1C0 - matrix.R1C0) <= tolerance && + System.Math.Abs(R1C1 - matrix.R1C1) <= tolerance && + System.Math.Abs(R1C2 - matrix.R1C2) <= tolerance && + System.Math.Abs(R2C0 - matrix.R2C0) <= tolerance && + System.Math.Abs(R2C1 - matrix.R2C1) <= tolerance && + System.Math.Abs(R2C2 - matrix.R2C2) <= tolerance; + } + + /// Indicates whether the current matrix is approximately equal to another matrix. + /// The left-hand operand. + /// The right-hand operand. + /// The limit below which the matrices are considered equal. + /// true if the current matrix is approximately equal to the matrix parameter; otherwise, false. + public static bool EqualsApprox(ref Matrix3d left, ref Matrix3d right, double tolerance) + { + return + System.Math.Abs(left.R0C0 - right.R0C0) <= tolerance && + System.Math.Abs(left.R0C1 - right.R0C1) <= tolerance && + System.Math.Abs(left.R0C2 - right.R0C2) <= tolerance && + System.Math.Abs(left.R1C0 - right.R1C0) <= tolerance && + System.Math.Abs(left.R1C1 - right.R1C1) <= tolerance && + System.Math.Abs(left.R1C2 - right.R1C2) <= tolerance && + System.Math.Abs(left.R2C0 - right.R2C0) <= tolerance && + System.Math.Abs(left.R2C1 - right.R2C1) <= tolerance && + System.Math.Abs(left.R2C2 - right.R2C2) <= tolerance; + } + + #endregion + + #region Arithmetic Operators + + + /// Add left matrix to this matrix. + /// The matrix to add. + public void Add(ref Matrix3d matrix) + { + R0C0 = R0C0 + matrix.R0C0; + R0C1 = R0C1 + matrix.R0C1; + R0C2 = R0C2 + matrix.R0C2; + R1C0 = R1C0 + matrix.R1C0; + R1C1 = R1C1 + matrix.R1C1; + R1C2 = R1C2 + matrix.R1C2; + R2C0 = R2C0 + matrix.R2C0; + R2C1 = R2C1 + matrix.R2C1; + R2C2 = R2C2 + matrix.R2C2; + } + + /// Add left matrix to this matrix. + /// The matrix to add. + /// The resulting matrix of the addition. + public void Add(ref Matrix3d matrix, out Matrix3d result) + { + result.R0C0 = R0C0 + matrix.R0C0; + result.R0C1 = R0C1 + matrix.R0C1; + result.R0C2 = R0C2 + matrix.R0C2; + result.R1C0 = R1C0 + matrix.R1C0; + result.R1C1 = R1C1 + matrix.R1C1; + result.R1C2 = R1C2 + matrix.R1C2; + result.R2C0 = R2C0 + matrix.R2C0; + result.R2C1 = R2C1 + matrix.R2C1; + result.R2C2 = R2C2 + matrix.R2C2; + } + + /// Add left matrix to left matrix. + /// The matrix on the matrix side of the equation. + /// The matrix on the right side of the equation + /// The resulting matrix of the addition. + public static void Add(ref Matrix3d left, ref Matrix3d right, out Matrix3d result) + { + result.R0C0 = left.R0C0 + right.R0C0; + result.R0C1 = left.R0C1 + right.R0C1; + result.R0C2 = left.R0C2 + right.R0C2; + result.R1C0 = left.R1C0 + right.R1C0; + result.R1C1 = left.R1C1 + right.R1C1; + result.R1C2 = left.R1C2 + right.R1C2; + result.R2C0 = left.R2C0 + right.R2C0; + result.R2C1 = left.R2C1 + right.R2C1; + result.R2C2 = left.R2C2 + right.R2C2; + } + + + /// Subtract left matrix from this matrix. + /// The matrix to subtract. + public void Subtract(ref Matrix3d matrix) + { + R0C0 = R0C0 + matrix.R0C0; + R0C1 = R0C1 + matrix.R0C1; + R0C2 = R0C2 + matrix.R0C2; + R1C0 = R1C0 + matrix.R1C0; + R1C1 = R1C1 + matrix.R1C1; + R1C2 = R1C2 + matrix.R1C2; + R2C0 = R2C0 + matrix.R2C0; + R2C1 = R2C1 + matrix.R2C1; + R2C2 = R2C2 + matrix.R2C2; + } + + /// Subtract left matrix from this matrix. + /// The matrix to subtract. + /// The resulting matrix of the subtraction. + public void Subtract(ref Matrix3d matrix, out Matrix3d result) + { + result.R0C0 = R0C0 + matrix.R0C0; + result.R0C1 = R0C1 + matrix.R0C1; + result.R0C2 = R0C2 + matrix.R0C2; + result.R1C0 = R1C0 + matrix.R1C0; + result.R1C1 = R1C1 + matrix.R1C1; + result.R1C2 = R1C2 + matrix.R1C2; + result.R2C0 = R2C0 + matrix.R2C0; + result.R2C1 = R2C1 + matrix.R2C1; + result.R2C2 = R2C2 + matrix.R2C2; + } + + /// Subtract left matrix from left matrix. + /// The matrix on the matrix side of the equation. + /// The matrix on the right side of the equation + /// The resulting matrix of the subtraction. + public static void Subtract(ref Matrix3d left, ref Matrix3d right, out Matrix3d result) + { + result.R0C0 = left.R0C0 + right.R0C0; + result.R0C1 = left.R0C1 + right.R0C1; + result.R0C2 = left.R0C2 + right.R0C2; + result.R1C0 = left.R1C0 + right.R1C0; + result.R1C1 = left.R1C1 + right.R1C1; + result.R1C2 = left.R1C2 + right.R1C2; + result.R2C0 = left.R2C0 + right.R2C0; + result.R2C1 = left.R2C1 + right.R2C1; + result.R2C2 = left.R2C2 + right.R2C2; + } + + + /// Multiply left martix times this matrix. + /// The matrix to multiply. + public void Multiply(ref Matrix3d matrix) + { + double r0c0 = matrix.R0C0 * R0C0 + matrix.R0C1 * R1C0 + matrix.R0C2 * R2C0; + double r0c1 = matrix.R0C0 * R0C1 + matrix.R0C1 * R1C1 + matrix.R0C2 * R2C1; + double r0c2 = matrix.R0C0 * R0C2 + matrix.R0C1 * R1C2 + matrix.R0C2 * R2C2; + + double r1c0 = matrix.R1C0 * R0C0 + matrix.R1C1 * R1C0 + matrix.R1C2 * R2C0; + double r1c1 = matrix.R1C0 * R0C1 + matrix.R1C1 * R1C1 + matrix.R1C2 * R2C1; + double r1c2 = matrix.R1C0 * R0C2 + matrix.R1C1 * R1C2 + matrix.R1C2 * R2C2; + + R2C0 = matrix.R2C0 * R0C0 + matrix.R2C1 * R1C0 + matrix.R2C2 * R2C0; + R2C1 = matrix.R2C0 * R0C1 + matrix.R2C1 * R1C1 + matrix.R2C2 * R2C1; + R2C2 = matrix.R2C0 * R0C2 + matrix.R2C1 * R1C2 + matrix.R2C2 * R2C2; + + + R0C0 = r0c0; + R0C1 = r0c1; + R0C2 = r0c2; + + R1C0 = r1c0; + R1C1 = r1c1; + R1C2 = r1c2; + } + + /// Multiply matrix times this matrix. + /// The matrix to multiply. + /// The resulting matrix of the multiplication. + public void Multiply(ref Matrix3d matrix, out Matrix3d result) + { + result.R0C0 = matrix.R0C0 * R0C0 + matrix.R0C1 * R1C0 + matrix.R0C2 * R2C0; + result.R0C1 = matrix.R0C0 * R0C1 + matrix.R0C1 * R1C1 + matrix.R0C2 * R2C1; + result.R0C2 = matrix.R0C0 * R0C2 + matrix.R0C1 * R1C2 + matrix.R0C2 * R2C2; + result.R1C0 = matrix.R1C0 * R0C0 + matrix.R1C1 * R1C0 + matrix.R1C2 * R2C0; + result.R1C1 = matrix.R1C0 * R0C1 + matrix.R1C1 * R1C1 + matrix.R1C2 * R2C1; + result.R1C2 = matrix.R1C0 * R0C2 + matrix.R1C1 * R1C2 + matrix.R1C2 * R2C2; + result.R2C0 = matrix.R2C0 * R0C0 + matrix.R2C1 * R1C0 + matrix.R2C2 * R2C0; + result.R2C1 = matrix.R2C0 * R0C1 + matrix.R2C1 * R1C1 + matrix.R2C2 * R2C1; + result.R2C2 = matrix.R2C0 * R0C2 + matrix.R2C1 * R1C2 + matrix.R2C2 * R2C2; + } + + /// Multiply left matrix times left matrix. + /// The matrix on the matrix side of the equation. + /// The matrix on the right side of the equation + /// The resulting matrix of the multiplication. + public static void Multiply(ref Matrix3d left, ref Matrix3d right, out Matrix3d result) + { + result.R0C0 = right.R0C0 * left.R0C0 + right.R0C1 * left.R1C0 + right.R0C2 * left.R2C0; + result.R0C1 = right.R0C0 * left.R0C1 + right.R0C1 * left.R1C1 + right.R0C2 * left.R2C1; + result.R0C2 = right.R0C0 * left.R0C2 + right.R0C1 * left.R1C2 + right.R0C2 * left.R2C2; + result.R1C0 = right.R1C0 * left.R0C0 + right.R1C1 * left.R1C0 + right.R1C2 * left.R2C0; + result.R1C1 = right.R1C0 * left.R0C1 + right.R1C1 * left.R1C1 + right.R1C2 * left.R2C1; + result.R1C2 = right.R1C0 * left.R0C2 + right.R1C1 * left.R1C2 + right.R1C2 * left.R2C2; + result.R2C0 = right.R2C0 * left.R0C0 + right.R2C1 * left.R1C0 + right.R2C2 * left.R2C0; + result.R2C1 = right.R2C0 * left.R0C1 + right.R2C1 * left.R1C1 + right.R2C2 * left.R2C1; + result.R2C2 = right.R2C0 * left.R0C2 + right.R2C1 * left.R1C2 + right.R2C2 * left.R2C2; + } + + + /// Multiply matrix times this matrix. + /// The matrix to multiply. + public void Multiply(double scalar) + { + R0C0 = scalar * R0C0; + R0C1 = scalar * R0C1; + R0C2 = scalar * R0C2; + R1C0 = scalar * R1C0; + R1C1 = scalar * R1C1; + R1C2 = scalar * R1C2; + R2C0 = scalar * R2C0; + R2C1 = scalar * R2C1; + R2C2 = scalar * R2C2; + } + + /// Multiply matrix times this matrix. + /// The matrix to multiply. + /// The resulting matrix of the multiplication. + public void Multiply(double scalar, out Matrix3d result) + { + result.R0C0 = scalar * R0C0; + result.R0C1 = scalar * R0C1; + result.R0C2 = scalar * R0C2; + result.R1C0 = scalar * R1C0; + result.R1C1 = scalar * R1C1; + result.R1C2 = scalar * R1C2; + result.R2C0 = scalar * R2C0; + result.R2C1 = scalar * R2C1; + result.R2C2 = scalar * R2C2; + } + + /// Multiply left matrix times left matrix. + /// The matrix on the matrix side of the equation. + /// The matrix on the right side of the equation + /// The resulting matrix of the multiplication. + public static void Multiply(ref Matrix3d matrix, double scalar, out Matrix3d result) + { + result.R0C0 = scalar * matrix.R0C0; + result.R0C1 = scalar * matrix.R0C1; + result.R0C2 = scalar * matrix.R0C2; + result.R1C0 = scalar * matrix.R1C0; + result.R1C1 = scalar * matrix.R1C1; + result.R1C2 = scalar * matrix.R1C2; + result.R2C0 = scalar * matrix.R2C0; + result.R2C1 = scalar * matrix.R2C1; + result.R2C2 = scalar * matrix.R2C2; + } + + + #endregion + + #region Functions + + public double Determinant + { + get + { + return R0C0 * R1C1 * R2C2 - R0C0 * R1C2 * R2C1 - R0C1 * R1C0 * R2C2 + R0C2 * R1C0 * R2C1 + R0C1 * R1C2 * R2C0 - R0C2 * R1C1 * R2C0; + } + } + + public void Transpose() + { + Functions.Swap(ref R0C1, ref R1C0); + Functions.Swap(ref R0C2, ref R2C0); + Functions.Swap(ref R1C2, ref R2C1); + } + public void Transpose(out Matrix3d result) + { + result.R0C0 = R0C0; + result.R0C1 = R1C0; + result.R0C2 = R2C0; + result.R1C0 = R0C1; + result.R1C1 = R1C1; + result.R1C2 = R2C1; + result.R2C0 = R0C2; + result.R2C1 = R1C2; + result.R2C2 = R2C2; + } + public static void Transpose(ref Matrix3d matrix, out Matrix3d result) + { + result.R0C0 = matrix.R0C0; + result.R0C1 = matrix.R1C0; + result.R0C2 = matrix.R2C0; + result.R1C0 = matrix.R0C1; + result.R1C1 = matrix.R1C1; + result.R1C2 = matrix.R2C1; + result.R2C0 = matrix.R0C2; + result.R2C1 = matrix.R1C2; + result.R2C2 = matrix.R2C2; + } + + #endregion + + #region Transformation Functions + + public void Transform(ref Vector3d vector) + { + double x = R0C0 * vector.X + R0C1 * vector.Y + R0C2 * vector.Z; + double y = R1C0 * vector.X + R1C1 * vector.Y + R1C2 * vector.Z; + vector.Z = R2C0 * vector.X + R2C1 * vector.Y + R2C2 * vector.Z; + vector.X = x; + vector.Y = y; + } + public static void Transform(ref Matrix3d matrix, ref Vector3d vector) + { + double x = matrix.R0C0 * vector.X + matrix.R0C1 * vector.Y + matrix.R0C2 * vector.Z; + double y = matrix.R1C0 * vector.X + matrix.R1C1 * vector.Y + matrix.R1C2 * vector.Z; + vector.Z = matrix.R2C0 * vector.X + matrix.R2C1 * vector.Y + matrix.R2C2 * vector.Z; + vector.X = x; + vector.Y = y; + } + public void Transform(ref Vector3d vector, out Vector3d result) + { + result.X = R0C0 * vector.X + R0C1 * vector.Y + R0C2 * vector.Z; + result.Y = R1C0 * vector.X + R1C1 * vector.Y + R1C2 * vector.Z; + result.Z = R2C0 * vector.X + R2C1 * vector.Y + R2C2 * vector.Z; + } + public static void Transform(ref Matrix3d matrix, ref Vector3d vector, out Vector3d result) + { + result.X = matrix.R0C0 * vector.X + matrix.R0C1 * vector.Y + matrix.R0C2 * vector.Z; + result.Y = matrix.R1C0 * vector.X + matrix.R1C1 * vector.Y + matrix.R1C2 * vector.Z; + result.Z = matrix.R2C0 * vector.X + matrix.R2C1 * vector.Y + matrix.R2C2 * vector.Z; + } + + public void Rotate(double angle) + { + double angleRadians = Functions.DTOR * angle; + double sin = (double)System.Math.Sin(angleRadians); + double cos = (double)System.Math.Cos(angleRadians); + + double r0c0 = cos * R0C0 + sin * R1C0; + double r0c1 = cos * R0C1 + sin * R1C1; + double r0c2 = cos * R0C2 + sin * R1C2; + + R1C0 = cos * R1C0 - sin * R0C0; + R1C1 = cos * R1C1 - sin * R0C1; + R1C2 = cos * R1C2 - sin * R0C2; + + R0C0 = r0c0; + R0C1 = r0c1; + R0C2 = r0c2; + } + public void Rotate(double angle, out Matrix3d result) + { + double angleRadians = Functions.DTOR * angle; + double sin = (double)System.Math.Sin(angleRadians); + double cos = (double)System.Math.Cos(angleRadians); + + result.R0C0 = cos * R0C0 + sin * R1C0; + result.R0C1 = cos * R0C1 + sin * R1C1; + result.R0C2 = cos * R0C2 + sin * R1C2; + result.R1C0 = cos * R1C0 - sin * R0C0; + result.R1C1 = cos * R1C1 - sin * R0C1; + result.R1C2 = cos * R1C2 - sin * R0C2; + result.R2C0 = R2C0; + result.R2C1 = R2C1; + result.R2C2 = R2C2; + } + public static void Rotate(ref Matrix3d matrix, double angle, out Matrix3d result) + { + double angleRadians = Functions.DTOR * angle; + double sin = (double)System.Math.Sin(angleRadians); + double cos = (double)System.Math.Cos(angleRadians); + + result.R0C0 = cos * matrix.R0C0 + sin * matrix.R1C0; + result.R0C1 = cos * matrix.R0C1 + sin * matrix.R1C1; + result.R0C2 = cos * matrix.R0C2 + sin * matrix.R1C2; + result.R1C0 = cos * matrix.R1C0 - sin * matrix.R0C0; + result.R1C1 = cos * matrix.R1C1 - sin * matrix.R0C1; + result.R1C2 = cos * matrix.R1C2 - sin * matrix.R0C2; + result.R2C0 = matrix.R2C0; + result.R2C1 = matrix.R2C1; + result.R2C2 = matrix.R2C2; + } + public static void RotateMatrix(double angle, out Matrix3d result) + { + double angleRadians = Functions.DTOR * angle; + double sin = (double)System.Math.Sin(angleRadians); + double cos = (double)System.Math.Cos(angleRadians); + + result.R0C0 = cos; + result.R0C1 = sin; + result.R0C2 = 0; + result.R1C0 = -sin; + result.R1C1 = cos; + result.R1C2 = 0; + result.R2C0 = 0; + result.R2C1 = 0; + result.R2C2 = 1; + } + + public Quaterniond ToQuaternion() + { + //return new Quaterniond(ref this); + } + + #endregion + + #region Constants + + /// The identity matrix. + public static readonly Matrix3d Identity = new Matrix3d + ( + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + ); + + /// A matrix of all zeros. + public static readonly Matrix3d Zero = new Matrix3d + ( + 0, 0, 0, + 0, 0, 0, + 0, 0, 0 + ); + + #endregion + + #region HashCode + + /// Returns the hash code for this instance. + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + return + R0C0.GetHashCode() ^ R0C1.GetHashCode() ^ R0C2.GetHashCode() ^ + R1C0.GetHashCode() ^ R1C1.GetHashCode() ^ R1C2.GetHashCode() ^ + R2C0.GetHashCode() ^ R2C1.GetHashCode() ^ R2C2.GetHashCode(); + } + + #endregion + + #region String + + /// Returns the fully qualified type name of this instance. + /// A System.String containing left fully qualified type name. + public override string ToString() + { + return String.Format( + "|{00}, {01}, {02}|\n" + + "|{03}, {04}, {05}|\n" + + "|{06}, {07}, {18}|\n" + + R0C0, R0C1, R0C2, + R1C0, R1C1, R1C2, + R2C0, R2C1, R2C2); + } + + #endregion + } +#endif + #pragma warning restore 3019 +} diff --git a/src/MiniTK/Math/Matrix4.cs b/src/MiniTK/Math/Matrix4.cs new file mode 100644 index 0000000..643361b --- /dev/null +++ b/src/MiniTK/Math/Matrix4.cs @@ -0,0 +1,1229 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + /// + /// Represents a 4x4 Matrix + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Matrix4 : IEquatable + { + #region Fields + + /// + /// Top row of the matrix + /// + public Vector4 Row0; + /// + /// 2nd row of the matrix + /// + public Vector4 Row1; + /// + /// 3rd row of the matrix + /// + public Vector4 Row2; + /// + /// Bottom row of the matrix + /// + public Vector4 Row3; + + /// + /// The identity matrix + /// + public static Matrix4 Identity = new Matrix4(Vector4.UnitX, Vector4.UnitY, Vector4.UnitZ, Vector4.UnitW); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// Top row of the matrix + /// Second row of the matrix + /// Third row of the matrix + /// Bottom row of the matrix + public Matrix4(Vector4 row0, Vector4 row1, Vector4 row2, Vector4 row3) + { + Row0 = row0; + Row1 = row1; + Row2 = row2; + Row3 = row3; + } + + /// + /// Constructs a new instance. + /// + /// First item of the first row of the matrix. + /// Second item of the first row of the matrix. + /// Third item of the first row of the matrix. + /// Fourth item of the first row of the matrix. + /// First item of the second row of the matrix. + /// Second item of the second row of the matrix. + /// Third item of the second row of the matrix. + /// Fourth item of the second row of the matrix. + /// First item of the third row of the matrix. + /// Second item of the third row of the matrix. + /// Third item of the third row of the matrix. + /// First item of the third row of the matrix. + /// Fourth item of the fourth row of the matrix. + /// Second item of the fourth row of the matrix. + /// Third item of the fourth row of the matrix. + /// Fourth item of the fourth row of the matrix. + public Matrix4( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + Row0 = new Vector4(m00, m01, m02, m03); + Row1 = new Vector4(m10, m11, m12, m13); + Row2 = new Vector4(m20, m21, m22, m23); + Row3 = new Vector4(m30, m31, m32, m33); + } + + #endregion + + #region Public Members + + #region Properties + + /// + /// The determinant of this matrix + /// + public float Determinant + { + get + { + return + Row0.X * Row1.Y * Row2.Z * Row3.W - Row0.X * Row1.Y * Row2.W * Row3.Z + Row0.X * Row1.Z * Row2.W * Row3.Y - Row0.X * Row1.Z * Row2.Y * Row3.W + + Row0.X * Row1.W * Row2.Y * Row3.Z - Row0.X * Row1.W * Row2.Z * Row3.Y - Row0.Y * Row1.Z * Row2.W * Row3.X + Row0.Y * Row1.Z * Row2.X * Row3.W + - Row0.Y * Row1.W * Row2.X * Row3.Z + Row0.Y * Row1.W * Row2.Z * Row3.X - Row0.Y * Row1.X * Row2.Z * Row3.W + Row0.Y * Row1.X * Row2.W * Row3.Z + + Row0.Z * Row1.W * Row2.X * Row3.Y - Row0.Z * Row1.W * Row2.Y * Row3.X + Row0.Z * Row1.X * Row2.Y * Row3.W - Row0.Z * Row1.X * Row2.W * Row3.Y + + Row0.Z * Row1.Y * Row2.W * Row3.X - Row0.Z * Row1.Y * Row2.X * Row3.W - Row0.W * Row1.X * Row2.Y * Row3.Z + Row0.W * Row1.X * Row2.Z * Row3.Y + - Row0.W * Row1.Y * Row2.Z * Row3.X + Row0.W * Row1.Y * Row2.X * Row3.Z - Row0.W * Row1.Z * Row2.X * Row3.Y + Row0.W * Row1.Z * Row2.Y * Row3.X; + } + } + + /// + /// The first column of this matrix + /// + public Vector4 Column0 + { + get { return new Vector4(Row0.X, Row1.X, Row2.X, Row3.X); } + } + + /// + /// The second column of this matrix + /// + public Vector4 Column1 + { + get { return new Vector4(Row0.Y, Row1.Y, Row2.Y, Row3.Y); } + } + + /// + /// The third column of this matrix + /// + public Vector4 Column2 + { + get { return new Vector4(Row0.Z, Row1.Z, Row2.Z, Row3.Z); } + } + + /// + /// The fourth column of this matrix + /// + public Vector4 Column3 + { + get { return new Vector4(Row0.W, Row1.W, Row2.W, Row3.W); } + } + + /// + /// Gets or sets the value at row 1, column 1 of this instance. + /// + public float M11 { get { return Row0.X; } set { Row0.X = value; } } + + /// + /// Gets or sets the value at row 1, column 2 of this instance. + /// + public float M12 { get { return Row0.Y; } set { Row0.Y = value; } } + + /// + /// Gets or sets the value at row 1, column 3 of this instance. + /// + public float M13 { get { return Row0.Z; } set { Row0.Z = value; } } + + /// + /// Gets or sets the value at row 1, column 4 of this instance. + /// + public float M14 { get { return Row0.W; } set { Row0.W = value; } } + + /// + /// Gets or sets the value at row 2, column 1 of this instance. + /// + public float M21 { get { return Row1.X; } set { Row1.X = value; } } + + /// + /// Gets or sets the value at row 2, column 2 of this instance. + /// + public float M22 { get { return Row1.Y; } set { Row1.Y = value; } } + + /// + /// Gets or sets the value at row 2, column 3 of this instance. + /// + public float M23 { get { return Row1.Z; } set { Row1.Z = value; } } + + /// + /// Gets or sets the value at row 2, column 4 of this instance. + /// + public float M24 { get { return Row1.W; } set { Row1.W = value; } } + + /// + /// Gets or sets the value at row 3, column 1 of this instance. + /// + public float M31 { get { return Row2.X; } set { Row2.X = value; } } + + /// + /// Gets or sets the value at row 3, column 2 of this instance. + /// + public float M32 { get { return Row2.Y; } set { Row2.Y = value; } } + + /// + /// Gets or sets the value at row 3, column 3 of this instance. + /// + public float M33 { get { return Row2.Z; } set { Row2.Z = value; } } + + /// + /// Gets or sets the value at row 3, column 4 of this instance. + /// + public float M34 { get { return Row2.W; } set { Row2.W = value; } } + + /// + /// Gets or sets the value at row 4, column 1 of this instance. + /// + public float M41 { get { return Row3.X; } set { Row3.X = value; } } + + /// + /// Gets or sets the value at row 4, column 2 of this instance. + /// + public float M42 { get { return Row3.Y; } set { Row3.Y = value; } } + + /// + /// Gets or sets the value at row 4, column 3 of this instance. + /// + public float M43 { get { return Row3.Z; } set { Row3.Z = value; } } + + /// + /// Gets or sets the value at row 4, column 4 of this instance. + /// + public float M44 { get { return Row3.W; } set { Row3.W = value; } } + + #endregion + + #region Instance + + #region public void Invert() + + /// + /// Converts this instance into its inverse. + /// + public void Invert() + { + this = Matrix4.Invert(this); + } + + #endregion + + #region public void Transpose() + + /// + /// Converts this instance into its transpose. + /// + public void Transpose() + { + this = Matrix4.Transpose(this); + } + + #endregion + + #endregion + + #region Static + + #region CreateFromAxisAngle + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + public static void CreateFromAxisAngle(Vector3 axis, float angle, out Matrix4 result) + { + float cos = (float)System.Math.Cos(-angle); + float sin = (float)System.Math.Sin(-angle); + float t = 1.0f - cos; + + axis.Normalize(); + + result = new Matrix4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f, + t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f, + t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f, + 0, 0, 0, 1); + } + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle) + { + Matrix4 result; + CreateFromAxisAngle(axis, angle, out result); + return result; + } + + #endregion + + #region CreateRotation[XYZ] + + /// + /// Builds a rotation matrix for a rotation around the x-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationX(float angle, out Matrix4 result) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + result.Row0 = Vector4.UnitX; + result.Row1 = new Vector4(0.0f, cos, sin, 0.0f); + result.Row2 = new Vector4(0.0f, -sin, cos, 0.0f); + result.Row3 = Vector4.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the x-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4 CreateRotationX(float angle) + { + Matrix4 result; + CreateRotationX(angle, out result); + return result; + } + + /// + /// Builds a rotation matrix for a rotation around the y-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationY(float angle, out Matrix4 result) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + result.Row0 = new Vector4(cos, 0.0f, -sin, 0.0f); + result.Row1 = Vector4.UnitY; + result.Row2 = new Vector4(sin, 0.0f, cos, 0.0f); + result.Row3 = Vector4.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the y-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4 CreateRotationY(float angle) + { + Matrix4 result; + CreateRotationY(angle, out result); + return result; + } + + /// + /// Builds a rotation matrix for a rotation around the z-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationZ(float angle, out Matrix4 result) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + result.Row0 = new Vector4(cos, sin, 0.0f, 0.0f); + result.Row1 = new Vector4(-sin, cos, 0.0f, 0.0f); + result.Row2 = Vector4.UnitZ; + result.Row3 = Vector4.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the z-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4 CreateRotationZ(float angle) + { + Matrix4 result; + CreateRotationZ(angle, out result); + return result; + } + + #endregion + + #region CreateTranslation + + /// + /// Creates a translation matrix. + /// + /// X translation. + /// Y translation. + /// Z translation. + /// The resulting Matrix4 instance. + public static void CreateTranslation(float x, float y, float z, out Matrix4 result) + { + result = Identity; + result.Row3 = new Vector4(x, y, z, 1); + } + + /// + /// Creates a translation matrix. + /// + /// The translation vector. + /// The resulting Matrix4 instance. + public static void CreateTranslation(ref Vector3 vector, out Matrix4 result) + { + result = Identity; + result.Row3 = new Vector4(vector.X, vector.Y, vector.Z, 1); + } + + /// + /// Creates a translation matrix. + /// + /// X translation. + /// Y translation. + /// Z translation. + /// The resulting Matrix4 instance. + public static Matrix4 CreateTranslation(float x, float y, float z) + { + Matrix4 result; + CreateTranslation(x, y, z, out result); + return result; + } + + /// + /// Creates a translation matrix. + /// + /// The translation vector. + /// The resulting Matrix4 instance. + public static Matrix4 CreateTranslation(Vector3 vector) + { + Matrix4 result; + CreateTranslation(vector.X, vector.Y, vector.Z, out result); + return result; + } + + #endregion + + #region CreateOrthographic + + /// + /// Creates an orthographic projection matrix. + /// + /// The width of the projection volume. + /// The height of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4 instance. + public static void CreateOrthographic(float width, float height, float zNear, float zFar, out Matrix4 result) + { + CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result); + } + + /// + /// Creates an orthographic projection matrix. + /// + /// The width of the projection volume. + /// The height of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4 instance. + public static Matrix4 CreateOrthographic(float width, float height, float zNear, float zFar) + { + Matrix4 result; + CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreateOrthographicOffCenter + + /// + /// Creates an orthographic projection matrix. + /// + /// The left edge of the projection volume. + /// The right edge of the projection volume. + /// The bottom edge of the projection volume. + /// The top edge of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4 instance. + public static void CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result) + { + result = new Matrix4(); + + float invRL = 1 / (right - left); + float invTB = 1 / (top - bottom); + float invFN = 1 / (zFar - zNear); + + result.M11 = 2 * invRL; + result.M22 = 2 * invTB; + result.M33 = -2 * invFN; + + result.M41 = -(right + left) * invRL; + result.M42 = -(top + bottom) * invTB; + result.M43 = -(zFar + zNear) * invFN; + result.M44 = 1; + } + + /// + /// Creates an orthographic projection matrix. + /// + /// The left edge of the projection volume. + /// The right edge of the projection volume. + /// The bottom edge of the projection volume. + /// The top edge of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4 instance. + public static Matrix4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar) + { + Matrix4 result; + CreateOrthographicOffCenter(left, right, bottom, top, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreatePerspectiveFieldOfView + + /// + /// Creates a perspective projection matrix. + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// fovy is zero, less than zero or larger than Math.PI + /// aspect is negative or zero + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static void CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar, out Matrix4 result) + { + if (fovy <= 0 || fovy > Math.PI) + throw new ArgumentOutOfRangeException("fovy"); + if (aspect <= 0) + throw new ArgumentOutOfRangeException("aspect"); + if (zNear <= 0) + throw new ArgumentOutOfRangeException("zNear"); + if (zFar <= 0) + throw new ArgumentOutOfRangeException("zFar"); + + float yMax = zNear * (float)System.Math.Tan(0.5f * fovy); + float yMin = -yMax; + float xMin = yMin * aspect; + float xMax = yMax * aspect; + + CreatePerspectiveOffCenter(xMin, xMax, yMin, yMax, zNear, zFar, out result); + } + + /// + /// Creates a perspective projection matrix. + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// fovy is zero, less than zero or larger than Math.PI + /// aspect is negative or zero + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static Matrix4 CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar) + { + Matrix4 result; + CreatePerspectiveFieldOfView(fovy, aspect, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreatePerspectiveOffCenter + + /// + /// Creates an perspective projection matrix. + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static void CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result) + { + if (zNear <= 0) + throw new ArgumentOutOfRangeException("zNear"); + if (zFar <= 0) + throw new ArgumentOutOfRangeException("zFar"); + if (zNear >= zFar) + throw new ArgumentOutOfRangeException("zNear"); + + float x = (2.0f * zNear) / (right - left); + float y = (2.0f * zNear) / (top - bottom); + float a = (right + left) / (right - left); + float b = (top + bottom) / (top - bottom); + float c = -(zFar + zNear) / (zFar - zNear); + float d = -(2.0f * zFar * zNear) / (zFar - zNear); + + result = new Matrix4(x, 0, 0, 0, + 0, y, 0, 0, + a, b, c, -1, + 0, 0, d, 0); + } + + /// + /// Creates an perspective projection matrix. + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static Matrix4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar) + { + Matrix4 result; + CreatePerspectiveOffCenter(left, right, bottom, top, zNear, zFar, out result); + return result; + } + + #endregion + + #region Obsolete Functions + + #region Translation Functions + + /// + /// Builds a translation matrix. + /// + /// The translation vector. + /// A new Matrix4 instance. + [Obsolete("Use CreateTranslation instead.")] + public static Matrix4 Translation(Vector3 trans) + { + return Translation(trans.X, trans.Y, trans.Z); + } + + /// + /// Build a translation matrix with the given translation + /// + /// X translation + /// Y translation + /// Z translation + /// A Translation matrix + [Obsolete("Use CreateTranslation instead.")] + public static Matrix4 Translation(float x, float y, float z) + { + Matrix4 result = Identity; + result.Row3 = new Vector4(x, y, z, 1.0f); + return result; + } + + #endregion + + #endregion + + #region Scale Functions + + /// + /// Build a scaling matrix + /// + /// Single scale factor for x,y and z axes + /// A scaling matrix + public static Matrix4 Scale(float scale) + { + return Scale(scale, scale, scale); + } + + /// + /// Build a scaling matrix + /// + /// Scale factors for x,y and z axes + /// A scaling matrix + public static Matrix4 Scale(Vector3 scale) + { + return Scale(scale.X, scale.Y, scale.Z); + } + + /// + /// Build a scaling matrix + /// + /// Scale factor for x-axis + /// Scale factor for y-axis + /// Scale factor for z-axis + /// A scaling matrix + public static Matrix4 Scale(float x, float y, float z) + { + Matrix4 result; + result.Row0 = Vector4.UnitX * x; + result.Row1 = Vector4.UnitY * y; + result.Row2 = Vector4.UnitZ * z; + result.Row3 = Vector4.UnitW; + return result; + } + + #endregion + + #region Rotation Functions + + /// + /// Build a rotation matrix that rotates about the x-axis + /// + /// angle in radians to rotate counter-clockwise around the x-axis + /// A rotation matrix + [Obsolete("Use CreateRotationX instead.")] + public static Matrix4 RotateX(float angle) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + Matrix4 result; + result.Row0 = Vector4.UnitX; + result.Row1 = new Vector4(0.0f, cos, sin, 0.0f); + result.Row2 = new Vector4(0.0f, -sin, cos, 0.0f); + result.Row3 = Vector4.UnitW; + return result; + } + + /// + /// Build a rotation matrix that rotates about the y-axis + /// + /// angle in radians to rotate counter-clockwise around the y-axis + /// A rotation matrix + [Obsolete("Use CreateRotationY instead.")] + public static Matrix4 RotateY(float angle) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + Matrix4 result; + result.Row0 = new Vector4(cos, 0.0f, -sin, 0.0f); + result.Row1 = Vector4.UnitY; + result.Row2 = new Vector4(sin, 0.0f, cos, 0.0f); + result.Row3 = Vector4.UnitW; + return result; + } + + /// + /// Build a rotation matrix that rotates about the z-axis + /// + /// angle in radians to rotate counter-clockwise around the z-axis + /// A rotation matrix + [Obsolete("Use CreateRotationZ instead.")] + public static Matrix4 RotateZ(float angle) + { + float cos = (float)System.Math.Cos(angle); + float sin = (float)System.Math.Sin(angle); + + Matrix4 result; + result.Row0 = new Vector4(cos, sin, 0.0f, 0.0f); + result.Row1 = new Vector4(-sin, cos, 0.0f, 0.0f); + result.Row2 = Vector4.UnitZ; + result.Row3 = Vector4.UnitW; + return result; + } + + /// + /// Build a rotation matrix to rotate about the given axis + /// + /// the axis to rotate about + /// angle in radians to rotate counter-clockwise (looking in the direction of the given axis) + /// A rotation matrix + [Obsolete("Use CreateFromAxisAngle instead.")] + public static Matrix4 Rotate(Vector3 axis, float angle) + { + float cos = (float)System.Math.Cos(-angle); + float sin = (float)System.Math.Sin(-angle); + float t = 1.0f - cos; + + axis.Normalize(); + + Matrix4 result; + result.Row0 = new Vector4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f); + result.Row1 = new Vector4(t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f); + result.Row2 = new Vector4(t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f); + result.Row3 = Vector4.UnitW; + return result; + } + + /// + /// Build a rotation matrix from a quaternion + /// + /// the quaternion + /// A rotation matrix + public static Matrix4 Rotate(Quaternion q) + { + Vector3 axis; + float angle; + q.ToAxisAngle(out axis, out angle); + return CreateFromAxisAngle(axis, angle); + } + + #endregion + + #region Camera Helper Functions + + /// + /// Build a world space to camera space matrix + /// + /// Eye (camera) position in world space + /// Target position in world space + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// A Matrix4 that transforms world space to camera space + public static Matrix4 LookAt(Vector3 eye, Vector3 target, Vector3 up) + { + Vector3 z = Vector3.Normalize(eye - target); + Vector3 x = Vector3.Normalize(Vector3.Cross(up, z)); + Vector3 y = Vector3.Normalize(Vector3.Cross(z, x)); + + Matrix4 rot = new Matrix4(new Vector4(x.X, y.X, z.X, 0.0f), + new Vector4(x.Y, y.Y, z.Y, 0.0f), + new Vector4(x.Z, y.Z, z.Z, 0.0f), + Vector4.UnitW); + + Matrix4 trans = Matrix4.CreateTranslation(-eye); + + return trans * rot; + } + + /// + /// Build a world space to camera space matrix + /// + /// Eye (camera) position in world space + /// Eye (camera) position in world space + /// Eye (camera) position in world space + /// Target position in world space + /// Target position in world space + /// Target position in world space + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// A Matrix4 that transforms world space to camera space + public static Matrix4 LookAt(float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ, float upX, float upY, float upZ) + { + return LookAt(new Vector3(eyeX, eyeY, eyeZ), new Vector3(targetX, targetY, targetZ), new Vector3(upX, upY, upZ)); + } + + /// + /// Build a projection matrix + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + [Obsolete("Use CreatePerspectiveOffCenter instead.")] + public static Matrix4 Frustum(float left, float right, float bottom, float top, float near, float far) + { + float invRL = 1.0f / (right - left); + float invTB = 1.0f / (top - bottom); + float invFN = 1.0f / (far - near); + return new Matrix4(new Vector4(2.0f * near * invRL, 0.0f, 0.0f, 0.0f), + new Vector4(0.0f, 2.0f * near * invTB, 0.0f, 0.0f), + new Vector4((right + left) * invRL, (top + bottom) * invTB, -(far + near) * invFN, -1.0f), + new Vector4(0.0f, 0.0f, -2.0f * far * near * invFN, 0.0f)); + } + + /// + /// Build a projection matrix + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + [Obsolete("Use CreatePerspectiveFieldOfView instead.")] + public static Matrix4 Perspective(float fovy, float aspect, float near, float far) + { + float yMax = near * (float)System.Math.Tan(0.5f * fovy); + float yMin = -yMax; + float xMin = yMin * aspect; + float xMax = yMax * aspect; + + return Frustum(xMin, xMax, yMin, yMax, near, far); + } + + #endregion + + #region Multiply Functions + + /// + /// Multiplies two instances. + /// + /// The left operand of the multiplication. + /// The right operand of the multiplication. + /// A new instance that is the result of the multiplication + public static Matrix4 Mult(Matrix4 left, Matrix4 right) + { + Matrix4 result; + Mult(ref left, ref right, out result); + return result; + } + + /// + /// Multiplies two instances. + /// + /// The left operand of the multiplication. + /// The right operand of the multiplication. + /// A new instance that is the result of the multiplication + public static void Mult(ref Matrix4 left, ref Matrix4 right, out Matrix4 result) + { + float lM11 = left.Row0.X, lM12 = left.Row0.Y, lM13 = left.Row0.Z, lM14 = left.Row0.W, + lM21 = left.Row1.X, lM22 = left.Row1.Y, lM23 = left.Row1.Z, lM24 = left.Row1.W, + lM31 = left.Row2.X, lM32 = left.Row2.Y, lM33 = left.Row2.Z, lM34 = left.Row2.W, + lM41 = left.Row3.X, lM42 = left.Row3.Y, lM43 = left.Row3.Z, lM44 = left.Row3.W, + rM11 = right.Row0.X, rM12 = right.Row0.Y, rM13 = right.Row0.Z, rM14 = right.Row0.W, + rM21 = right.Row1.X, rM22 = right.Row1.Y, rM23 = right.Row1.Z, rM24 = right.Row1.W, + rM31 = right.Row2.X, rM32 = right.Row2.Y, rM33 = right.Row2.Z, rM34 = right.Row2.W, + rM41 = right.Row3.X, rM42 = right.Row3.Y, rM43 = right.Row3.Z, rM44 = right.Row3.W; + + result.Row0.X = (((lM11 * rM11) + (lM12 * rM21)) + (lM13 * rM31)) + (lM14 * rM41); + result.Row0.Y = (((lM11 * rM12) + (lM12 * rM22)) + (lM13 * rM32)) + (lM14 * rM42); + result.Row0.Z = (((lM11 * rM13) + (lM12 * rM23)) + (lM13 * rM33)) + (lM14 * rM43); + result.Row0.W = (((lM11 * rM14) + (lM12 * rM24)) + (lM13 * rM34)) + (lM14 * rM44); + result.Row1.X = (((lM21 * rM11) + (lM22 * rM21)) + (lM23 * rM31)) + (lM24 * rM41); + result.Row1.Y = (((lM21 * rM12) + (lM22 * rM22)) + (lM23 * rM32)) + (lM24 * rM42); + result.Row1.Z = (((lM21 * rM13) + (lM22 * rM23)) + (lM23 * rM33)) + (lM24 * rM43); + result.Row1.W = (((lM21 * rM14) + (lM22 * rM24)) + (lM23 * rM34)) + (lM24 * rM44); + result.Row2.X = (((lM31 * rM11) + (lM32 * rM21)) + (lM33 * rM31)) + (lM34 * rM41); + result.Row2.Y = (((lM31 * rM12) + (lM32 * rM22)) + (lM33 * rM32)) + (lM34 * rM42); + result.Row2.Z = (((lM31 * rM13) + (lM32 * rM23)) + (lM33 * rM33)) + (lM34 * rM43); + result.Row2.W = (((lM31 * rM14) + (lM32 * rM24)) + (lM33 * rM34)) + (lM34 * rM44); + result.Row3.X = (((lM41 * rM11) + (lM42 * rM21)) + (lM43 * rM31)) + (lM44 * rM41); + result.Row3.Y = (((lM41 * rM12) + (lM42 * rM22)) + (lM43 * rM32)) + (lM44 * rM42); + result.Row3.Z = (((lM41 * rM13) + (lM42 * rM23)) + (lM43 * rM33)) + (lM44 * rM43); + result.Row3.W = (((lM41 * rM14) + (lM42 * rM24)) + (lM43 * rM34)) + (lM44 * rM44); + } + + #endregion + + #region Invert Functions + + /// + /// Calculate the inverse of the given matrix + /// + /// The matrix to invert + /// The inverse of the given matrix if it has one, or the input if it is singular + /// Thrown if the Matrix4 is singular. + public static Matrix4 Invert(Matrix4 mat) + { + int[] colIdx = { 0, 0, 0, 0 }; + int[] rowIdx = { 0, 0, 0, 0 }; + int[] pivotIdx = { -1, -1, -1, -1 }; + + // convert the matrix to an array for easy looping + float[,] inverse = {{mat.Row0.X, mat.Row0.Y, mat.Row0.Z, mat.Row0.W}, + {mat.Row1.X, mat.Row1.Y, mat.Row1.Z, mat.Row1.W}, + {mat.Row2.X, mat.Row2.Y, mat.Row2.Z, mat.Row2.W}, + {mat.Row3.X, mat.Row3.Y, mat.Row3.Z, mat.Row3.W} }; + int icol = 0; + int irow = 0; + for (int i = 0; i < 4; i++) + { + // Find the largest pivot value + float maxPivot = 0.0f; + for (int j = 0; j < 4; j++) + { + if (pivotIdx[j] != 0) + { + for (int k = 0; k < 4; ++k) + { + if (pivotIdx[k] == -1) + { + float absVal = System.Math.Abs(inverse[j, k]); + if (absVal > maxPivot) + { + maxPivot = absVal; + irow = j; + icol = k; + } + } + else if (pivotIdx[k] > 0) + { + return mat; + } + } + } + } + + ++(pivotIdx[icol]); + + // Swap rows over so pivot is on diagonal + if (irow != icol) + { + for (int k = 0; k < 4; ++k) + { + float f = inverse[irow, k]; + inverse[irow, k] = inverse[icol, k]; + inverse[icol, k] = f; + } + } + + rowIdx[i] = irow; + colIdx[i] = icol; + + float pivot = inverse[icol, icol]; + // check for singular matrix + if (pivot == 0.0f) + { + throw new InvalidOperationException("Matrix is singular and cannot be inverted."); + //return mat; + } + + // Scale row so it has a unit diagonal + float oneOverPivot = 1.0f / pivot; + inverse[icol, icol] = 1.0f; + for (int k = 0; k < 4; ++k) + inverse[icol, k] *= oneOverPivot; + + // Do elimination of non-diagonal elements + for (int j = 0; j < 4; ++j) + { + // check this isn't on the diagonal + if (icol != j) + { + float f = inverse[j, icol]; + inverse[j, icol] = 0.0f; + for (int k = 0; k < 4; ++k) + inverse[j, k] -= inverse[icol, k] * f; + } + } + } + + for (int j = 3; j >= 0; --j) + { + int ir = rowIdx[j]; + int ic = colIdx[j]; + for (int k = 0; k < 4; ++k) + { + float f = inverse[k, ir]; + inverse[k, ir] = inverse[k, ic]; + inverse[k, ic] = f; + } + } + + mat.Row0 = new Vector4(inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3]); + mat.Row1 = new Vector4(inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3]); + mat.Row2 = new Vector4(inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3]); + mat.Row3 = new Vector4(inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]); + return mat; + } + + #endregion + + #region Transpose + + /// + /// Calculate the transpose of the given matrix + /// + /// The matrix to transpose + /// The transpose of the given matrix + public static Matrix4 Transpose(Matrix4 mat) + { + return new Matrix4(mat.Column0, mat.Column1, mat.Column2, mat.Column3); + } + + + /// + /// Calculate the transpose of the given matrix + /// + /// The matrix to transpose + /// The result of the calculation + public static void Transpose(ref Matrix4 mat, out Matrix4 result) + { + result.Row0 = mat.Column0; + result.Row1 = mat.Column1; + result.Row2 = mat.Column2; + result.Row3 = mat.Column3; + } + + #endregion + + #endregion + + #region Operators + + /// + /// Matrix multiplication + /// + /// left-hand operand + /// right-hand operand + /// A new Matrix44 which holds the result of the multiplication + public static Matrix4 operator *(Matrix4 left, Matrix4 right) + { + return Matrix4.Mult(left, right); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Matrix4 left, Matrix4 right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equal right; false otherwise. + public static bool operator !=(Matrix4 left, Matrix4 right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Matrix44. + /// + /// + public override string ToString() + { + return String.Format("{0}\n{1}\n{2}\n{3}", Row0, Row1, Row2, Row3); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode() ^ Row3.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare tresult. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Matrix4)) + return false; + + return this.Equals((Matrix4)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current matrix is equal to another matrix. + /// An matrix to compare with this matrix. + /// true if the current matrix is equal to the matrix parameter; otherwise, false. + public bool Equals(Matrix4 other) + { + return + Row0 == other.Row0 && + Row1 == other.Row1 && + Row2 == other.Row2 && + Row3 == other.Row3; + } + + #endregion + } +} diff --git a/src/MiniTK/Math/Matrix4d.cs b/src/MiniTK/Math/Matrix4d.cs new file mode 100644 index 0000000..3a0b7d3 --- /dev/null +++ b/src/MiniTK/Math/Matrix4d.cs @@ -0,0 +1,1223 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; + +namespace OpenTK +{ + /// + /// Represents a 4x4 Matrix with double-precision components. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Matrix4d : IEquatable + { + #region Fields + + /// + /// Top row of the matrix + /// + public Vector4d Row0; + /// + /// 2nd row of the matrix + /// + public Vector4d Row1; + /// + /// 3rd row of the matrix + /// + public Vector4d Row2; + /// + /// Bottom row of the matrix + /// + public Vector4d Row3; + + /// + /// The identity matrix + /// + public static Matrix4d Identity = new Matrix4d(Vector4d .UnitX, Vector4d .UnitY, Vector4d .UnitZ, Vector4d .UnitW); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// Top row of the matrix + /// Second row of the matrix + /// Third row of the matrix + /// Bottom row of the matrix + public Matrix4d(Vector4d row0, Vector4d row1, Vector4d row2, Vector4d row3) + { + Row0 = row0; + Row1 = row1; + Row2 = row2; + Row3 = row3; + } + + /// + /// Constructs a new instance. + /// + /// First item of the first row. + /// Second item of the first row. + /// Third item of the first row. + /// Fourth item of the first row. + /// First item of the second row. + /// Second item of the second row. + /// Third item of the second row. + /// Fourth item of the second row. + /// First item of the third row. + /// Second item of the third row. + /// Third item of the third row. + /// First item of the third row. + /// Fourth item of the fourth row. + /// Second item of the fourth row. + /// Third item of the fourth row. + /// Fourth item of the fourth row. + public Matrix4d( + double m00, double m01, double m02, double m03, + double m10, double m11, double m12, double m13, + double m20, double m21, double m22, double m23, + double m30, double m31, double m32, double m33) + { + Row0 = new Vector4d(m00, m01, m02, m03); + Row1 = new Vector4d(m10, m11, m12, m13); + Row2 = new Vector4d(m20, m21, m22, m23); + Row3 = new Vector4d(m30, m31, m32, m33); + } + + #endregion + + #region Public Members + + #region Properties + + /// + /// The determinant of this matrix + /// + public double Determinant + { + get + { + return + Row0.X * Row1.Y * Row2.Z * Row3.W - Row0.X * Row1.Y * Row2.W * Row3.Z + Row0.X * Row1.Z * Row2.W * Row3.Y - Row0.X * Row1.Z * Row2.Y * Row3.W + + Row0.X * Row1.W * Row2.Y * Row3.Z - Row0.X * Row1.W * Row2.Z * Row3.Y - Row0.Y * Row1.Z * Row2.W * Row3.X + Row0.Y * Row1.Z * Row2.X * Row3.W + - Row0.Y * Row1.W * Row2.X * Row3.Z + Row0.Y * Row1.W * Row2.Z * Row3.X - Row0.Y * Row1.X * Row2.Z * Row3.W + Row0.Y * Row1.X * Row2.W * Row3.Z + + Row0.Z * Row1.W * Row2.X * Row3.Y - Row0.Z * Row1.W * Row2.Y * Row3.X + Row0.Z * Row1.X * Row2.Y * Row3.W - Row0.Z * Row1.X * Row2.W * Row3.Y + + Row0.Z * Row1.Y * Row2.W * Row3.X - Row0.Z * Row1.Y * Row2.X * Row3.W - Row0.W * Row1.X * Row2.Y * Row3.Z + Row0.W * Row1.X * Row2.Z * Row3.Y + - Row0.W * Row1.Y * Row2.Z * Row3.X + Row0.W * Row1.Y * Row2.X * Row3.Z - Row0.W * Row1.Z * Row2.X * Row3.Y + Row0.W * Row1.Z * Row2.Y * Row3.X; + } + } + + /// + /// The first column of this matrix + /// + public Vector4d Column0 + { + get { return new Vector4d (Row0.X, Row1.X, Row2.X, Row3.X); } + } + + /// + /// The second column of this matrix + /// + public Vector4d Column1 + { + get { return new Vector4d (Row0.Y, Row1.Y, Row2.Y, Row3.Y); } + } + + /// + /// The third column of this matrix + /// + public Vector4d Column2 + { + get { return new Vector4d (Row0.Z, Row1.Z, Row2.Z, Row3.Z); } + } + + /// + /// The fourth column of this matrix + /// + public Vector4d Column3 + { + get { return new Vector4d (Row0.W, Row1.W, Row2.W, Row3.W); } + } + + /// + /// Gets or sets the value at row 1, column 1 of this instance. + /// + public double M11 { get { return Row0.X; } set { Row0.X = value; } } + + /// + /// Gets or sets the value at row 1, column 2 of this instance. + /// + public double M12 { get { return Row0.Y; } set { Row0.Y = value; } } + + /// + /// Gets or sets the value at row 1, column 3 of this instance. + /// + public double M13 { get { return Row0.Z; } set { Row0.Z = value; } } + + /// + /// Gets or sets the value at row 1, column 4 of this instance. + /// + public double M14 { get { return Row0.W; } set { Row0.W = value; } } + + /// + /// Gets or sets the value at row 2, column 1 of this instance. + /// + public double M21 { get { return Row1.X; } set { Row1.X = value; } } + + /// + /// Gets or sets the value at row 2, column 2 of this instance. + /// + public double M22 { get { return Row1.Y; } set { Row1.Y = value; } } + + /// + /// Gets or sets the value at row 2, column 3 of this instance. + /// + public double M23 { get { return Row1.Z; } set { Row1.Z = value; } } + + /// + /// Gets or sets the value at row 2, column 4 of this instance. + /// + public double M24 { get { return Row1.W; } set { Row1.W = value; } } + + /// + /// Gets or sets the value at row 3, column 1 of this instance. + /// + public double M31 { get { return Row2.X; } set { Row2.X = value; } } + + /// + /// Gets or sets the value at row 3, column 2 of this instance. + /// + public double M32 { get { return Row2.Y; } set { Row2.Y = value; } } + + /// + /// Gets or sets the value at row 3, column 3 of this instance. + /// + public double M33 { get { return Row2.Z; } set { Row2.Z = value; } } + + /// + /// Gets or sets the value at row 3, column 4 of this instance. + /// + public double M34 { get { return Row2.W; } set { Row2.W = value; } } + + /// + /// Gets or sets the value at row 4, column 1 of this instance. + /// + public double M41 { get { return Row3.X; } set { Row3.X = value; } } + + /// + /// Gets or sets the value at row 4, column 2 of this instance. + /// + public double M42 { get { return Row3.Y; } set { Row3.Y = value; } } + + /// + /// Gets or sets the value at row 4, column 3 of this instance. + /// + public double M43 { get { return Row3.Z; } set { Row3.Z = value; } } + + /// + /// Gets or sets the value at row 4, column 4 of this instance. + /// + public double M44 { get { return Row3.W; } set { Row3.W = value; } } + + #endregion + + #region Instance + + #region public void Invert() + + /// + /// Converts this instance into its inverse. + /// + public void Invert() + { + this = Matrix4d.Invert(this); + } + + #endregion + + #region public void Transpose() + + /// + /// Converts this instance into its transpose. + /// + public void Transpose() + { + this = Matrix4d.Transpose(this); + } + + #endregion + + #endregion + + #region Static + + #region CreateFromAxisAngle + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + public static void CreateFromAxisAngle(Vector3d axis, double angle, out Matrix4d result) + { + double cos = System.Math.Cos(-angle); + double sin = System.Math.Sin(-angle); + double t = 1.0 - cos; + + axis.Normalize(); + + result = new Matrix4d(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0, + t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0, + t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0, + 0, 0, 0, 1); + } + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + public static Matrix4d CreateFromAxisAngle(Vector3d axis, double angle) + { + Matrix4d result; + CreateFromAxisAngle(axis, angle, out result); + return result; + } + + #endregion + + #region CreateRotation[XYZ] + + /// + /// Builds a rotation matrix for a rotation around the x-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationX(double angle, out Matrix4d result) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + result.Row0 = Vector4d.UnitX; + result.Row1 = new Vector4d(0, cos, sin, 0); + result.Row2 = new Vector4d(0, -sin, cos, 0); + result.Row3 = Vector4d.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the x-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4d CreateRotationX(double angle) + { + Matrix4d result; + CreateRotationX(angle, out result); + return result; + } + + /// + /// Builds a rotation matrix for a rotation around the y-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationY(double angle, out Matrix4d result) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + result.Row0 = new Vector4d(cos, 0, -sin, 0); + result.Row1 = Vector4d.UnitY; + result.Row2 = new Vector4d(sin, 0, cos, 0); + result.Row3 = Vector4d.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the y-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4d CreateRotationY(double angle) + { + Matrix4d result; + CreateRotationY(angle, out result); + return result; + } + + /// + /// Builds a rotation matrix for a rotation around the z-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static void CreateRotationZ(double angle, out Matrix4d result) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + result.Row0 = new Vector4d(cos, sin, 0, 0); + result.Row1 = new Vector4d(-sin, cos, 0, 0); + result.Row2 = Vector4d.UnitZ; + result.Row3 = Vector4d.UnitW; + } + + /// + /// Builds a rotation matrix for a rotation around the z-axis. + /// + /// The counter-clockwise angle in radians. + /// The resulting Matrix4 instance. + public static Matrix4d CreateRotationZ(double angle) + { + Matrix4d result; + CreateRotationZ(angle, out result); + return result; + } + + #endregion + + #region CreateTranslation + + /// + /// Creates a translation matrix. + /// + /// X translation. + /// Y translation. + /// Z translation. + /// The resulting Matrix4d instance. + public static void CreateTranslation(double x, double y, double z, out Matrix4d result) + { + result = Identity; + result.Row3 = new Vector4d(x, y, z, 1); + } + + /// + /// Creates a translation matrix. + /// + /// The translation vector. + /// The resulting Matrix4d instance. + public static void CreateTranslation(ref Vector3d vector, out Matrix4d result) + { + result = Identity; + result.Row3 = new Vector4d(vector.X, vector.Y, vector.Z, 1); + } + + /// + /// Creates a translation matrix. + /// + /// X translation. + /// Y translation. + /// Z translation. + /// The resulting Matrix4d instance. + public static Matrix4d CreateTranslation(double x, double y, double z) + { + Matrix4d result; + CreateTranslation(x, y, z, out result); + return result; + } + + /// + /// Creates a translation matrix. + /// + /// The translation vector. + /// The resulting Matrix4d instance. + public static Matrix4d CreateTranslation(Vector3d vector) + { + Matrix4d result; + CreateTranslation(vector.X, vector.Y, vector.Z, out result); + return result; + } + + #endregion + + #region CreateOrthographic + + /// + /// Creates an orthographic projection matrix. + /// + /// The width of the projection volume. + /// The height of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4d instance. + public static void CreateOrthographic(double width, double height, double zNear, double zFar, out Matrix4d result) + { + CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result); + } + + /// + /// Creates an orthographic projection matrix. + /// + /// The width of the projection volume. + /// The height of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4d instance. + public static Matrix4d CreateOrthographic(double width, double height, double zNear, double zFar) + { + Matrix4d result; + CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreateOrthographicOffCenter + + /// + /// Creates an orthographic projection matrix. + /// + /// The left edge of the projection volume. + /// The right edge of the projection volume. + /// The bottom edge of the projection volume. + /// The top edge of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4d instance. + public static void CreateOrthographicOffCenter(double left, double right, double bottom, double top, double zNear, double zFar, out Matrix4d result) + { + result = new Matrix4d(); + + double invRL = 1 / (right - left); + double invTB = 1 / (top - bottom); + double invFN = 1 / (zFar - zNear); + + result.M11 = 2 * invRL; + result.M22 = 2 * invTB; + result.M33 = -2 * invFN; + + result.M41 = -(right + left) * invRL; + result.M42 = -(top + bottom) * invTB; + result.M43 = -(zFar + zNear) * invFN; + result.M44 = 1; + } + + /// + /// Creates an orthographic projection matrix. + /// + /// The left edge of the projection volume. + /// The right edge of the projection volume. + /// The bottom edge of the projection volume. + /// The top edge of the projection volume. + /// The near edge of the projection volume. + /// The far edge of the projection volume. + /// The resulting Matrix4d instance. + public static Matrix4d CreateOrthographicOffCenter(double left, double right, double bottom, double top, double zNear, double zFar) + { + Matrix4d result; + CreateOrthographicOffCenter(left, right, bottom, top, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreatePerspectiveFieldOfView + + /// + /// Creates a perspective projection matrix. + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// fovy is zero, less than zero or larger than Math.PI + /// aspect is negative or zero + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static void CreatePerspectiveFieldOfView(double fovy, double aspect, double zNear, double zFar, out Matrix4d result) + { + if (fovy <= 0 || fovy > Math.PI) + throw new ArgumentOutOfRangeException("fovy"); + if (aspect <= 0) + throw new ArgumentOutOfRangeException("aspect"); + if (zNear <= 0) + throw new ArgumentOutOfRangeException("zNear"); + if (zFar <= 0) + throw new ArgumentOutOfRangeException("zFar"); + + double yMax = zNear * System.Math.Tan(0.5 * fovy); + double yMin = -yMax; + double xMin = yMin * aspect; + double xMax = yMax * aspect; + + CreatePerspectiveOffCenter(xMin, xMax, yMin, yMax, zNear, zFar, out result); + } + + /// + /// Creates a perspective projection matrix. + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// fovy is zero, less than zero or larger than Math.PI + /// aspect is negative or zero + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static Matrix4d CreatePerspectiveFieldOfView(double fovy, double aspect, double zNear, double zFar) + { + Matrix4d result; + CreatePerspectiveFieldOfView(fovy, aspect, zNear, zFar, out result); + return result; + } + + #endregion + + #region CreatePerspectiveOffCenter + + /// + /// Creates an perspective projection matrix. + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static void CreatePerspectiveOffCenter(double left, double right, double bottom, double top, double zNear, double zFar, out Matrix4d result) + { + if (zNear <= 0) + throw new ArgumentOutOfRangeException("zNear"); + if (zFar <= 0) + throw new ArgumentOutOfRangeException("zFar"); + if (zNear >= zFar) + throw new ArgumentOutOfRangeException("zNear"); + + double x = (2.0 * zNear) / (right - left); + double y = (2.0 * zNear) / (top - bottom); + double a = (right + left) / (right - left); + double b = (top + bottom) / (top - bottom); + double c = -(zFar + zNear) / (zFar - zNear); + double d = -(2.0 * zFar * zNear) / (zFar - zNear); + + result = new Matrix4d(x, 0, 0, 0, + 0, y, 0, 0, + a, b, c, -1, + 0, 0, d, 0); + } + + /// + /// Creates an perspective projection matrix. + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + /// + /// Thrown under the following conditions: + /// + /// zNear is negative or zero + /// zFar is negative or zero + /// zNear is larger than zFar + /// + /// + public static Matrix4d CreatePerspectiveOffCenter(double left, double right, double bottom, double top, double zNear, double zFar) + { + Matrix4d result; + CreatePerspectiveOffCenter(left, right, bottom, top, zNear, zFar, out result); + return result; + } + + #endregion + + #region Obsolete Functions + + #region Translation Functions + + /// + /// Build a translation matrix with the given translation + /// + /// The vector to translate along + /// A Translation matrix + [Obsolete("Use CreateTranslation instead.")] + public static Matrix4d Translation(Vector3d trans) + { + return Translation(trans.X, trans.Y, trans.Z); + } + + /// + /// Build a translation matrix with the given translation + /// + /// X translation + /// Y translation + /// Z translation + /// A Translation matrix + [Obsolete("Use CreateTranslation instead.")] + public static Matrix4d Translation(double x, double y, double z) + { + Matrix4d result = Identity; + result.Row3 = new Vector4d(x, y, z, 1.0); + return result; + } + + #endregion + + #endregion + + #region Scale Functions + + /// + /// Build a scaling matrix + /// + /// Single scale factor for x,y and z axes + /// A scaling matrix + public static Matrix4d Scale(double scale) + { + return Scale(scale, scale, scale); + } + + /// + /// Build a scaling matrix + /// + /// Scale factors for x,y and z axes + /// A scaling matrix + public static Matrix4d Scale(Vector3d scale) + { + return Scale(scale.X, scale.Y, scale.Z); + } + + /// + /// Build a scaling matrix + /// + /// Scale factor for x-axis + /// Scale factor for y-axis + /// Scale factor for z-axis + /// A scaling matrix + public static Matrix4d Scale(double x, double y, double z) + { + Matrix4d result; + result.Row0 = Vector4d .UnitX * x; + result.Row1 = Vector4d .UnitY * y; + result.Row2 = Vector4d .UnitZ * z; + result.Row3 = Vector4d .UnitW; + return result; + } + + #endregion + + #region Rotation Functions + + /// + /// Build a rotation matrix that rotates about the x-axis + /// + /// angle in radians to rotate counter-clockwise around the x-axis + /// A rotation matrix + public static Matrix4d RotateX(double angle) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + Matrix4d result; + result.Row0 = Vector4d .UnitX; + result.Row1 = new Vector4d (0.0, cos, sin, 0.0); + result.Row2 = new Vector4d (0.0, -sin, cos, 0.0); + result.Row3 = Vector4d .UnitW; + return result; + } + + /// + /// Build a rotation matrix that rotates about the y-axis + /// + /// angle in radians to rotate counter-clockwise around the y-axis + /// A rotation matrix + public static Matrix4d RotateY(double angle) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + Matrix4d result; + result.Row0 = new Vector4d (cos, 0.0, -sin, 0.0); + result.Row1 = Vector4d .UnitY; + result.Row2 = new Vector4d (sin, 0.0, cos, 0.0); + result.Row3 = Vector4d .UnitW; + return result; + } + + /// + /// Build a rotation matrix that rotates about the z-axis + /// + /// angle in radians to rotate counter-clockwise around the z-axis + /// A rotation matrix + public static Matrix4d RotateZ(double angle) + { + double cos = System.Math.Cos(angle); + double sin = System.Math.Sin(angle); + + Matrix4d result; + result.Row0 = new Vector4d (cos, sin, 0.0, 0.0); + result.Row1 = new Vector4d (-sin, cos, 0.0, 0.0); + result.Row2 = Vector4d .UnitZ; + result.Row3 = Vector4d .UnitW; + return result; + } + + /// + /// Build a rotation matrix to rotate about the given axis + /// + /// the axis to rotate about + /// angle in radians to rotate counter-clockwise (looking in the direction of the given axis) + /// A rotation matrix + public static Matrix4d Rotate(Vector3d axis, double angle) + { + double cos = System.Math.Cos(-angle); + double sin = System.Math.Sin(-angle); + double t = 1.0 - cos; + + axis.Normalize(); + + Matrix4d result; + result.Row0 = new Vector4d (t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0); + result.Row1 = new Vector4d (t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0); + result.Row2 = new Vector4d (t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0); + result.Row3 = Vector4d .UnitW; + return result; + } + + /// + /// Build a rotation matrix from a quaternion + /// + /// the quaternion + /// A rotation matrix + public static Matrix4d Rotate(Quaterniond q) + { + Vector3d axis; + double angle; + q.ToAxisAngle(out axis, out angle); + return Rotate(axis, angle); + } + + #endregion + + #region Camera Helper Functions + + /// + /// Build a world space to camera space matrix + /// + /// Eye (camera) position in world space + /// Target position in world space + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// A Matrix that transforms world space to camera space + public static Matrix4d LookAt(Vector3d eye, Vector3d target, Vector3d up) + { + Vector3d z = Vector3d.Normalize(eye - target); + Vector3d x = Vector3d.Normalize(Vector3d.Cross(up, z)); + Vector3d y = Vector3d.Normalize(Vector3d.Cross(z, x)); + + Matrix4d rot = new Matrix4d(new Vector4d (x.X, y.X, z.X, 0.0), + new Vector4d (x.Y, y.Y, z.Y, 0.0), + new Vector4d (x.Z, y.Z, z.Z, 0.0), + Vector4d .UnitW); + + Matrix4d trans = Matrix4d.CreateTranslation(-eye); + + return trans * rot; + } + + /// + /// Build a world space to camera space matrix + /// + /// Eye (camera) position in world space + /// Eye (camera) position in world space + /// Eye (camera) position in world space + /// Target position in world space + /// Target position in world space + /// Target position in world space + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// Up vector in world space (should not be parallel to the camera direction, that is target - eye) + /// A Matrix4 that transforms world space to camera space + public static Matrix4d LookAt(double eyeX, double eyeY, double eyeZ, double targetX, double targetY, double targetZ, double upX, double upY, double upZ) + { + return LookAt(new Vector3d(eyeX, eyeY, eyeZ), new Vector3d(targetX, targetY, targetZ), new Vector3d(upX, upY, upZ)); + } + + /// + /// Build a projection matrix + /// + /// Left edge of the view frustum + /// Right edge of the view frustum + /// Bottom edge of the view frustum + /// Top edge of the view frustum + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + public static Matrix4d Frustum(double left, double right, double bottom, double top, double near, double far) + { + double invRL = 1.0 / (right - left); + double invTB = 1.0 / (top - bottom); + double invFN = 1.0 / (far - near); + return new Matrix4d(new Vector4d (2.0 * near * invRL, 0.0, 0.0, 0.0), + new Vector4d (0.0, 2.0 * near * invTB, 0.0, 0.0), + new Vector4d ((right + left) * invRL, (top + bottom) * invTB, -(far + near) * invFN, -1.0), + new Vector4d (0.0, 0.0, -2.0 * far * near * invFN, 0.0)); + } + + /// + /// Build a projection matrix + /// + /// Angle of the field of view in the y direction (in radians) + /// Aspect ratio of the view (width / height) + /// Distance to the near clip plane + /// Distance to the far clip plane + /// A projection matrix that transforms camera space to raster space + public static Matrix4d Perspective(double fovy, double aspect, double near, double far) + { + double yMax = near * System.Math.Tan(0.5f * fovy); + double yMin = -yMax; + double xMin = yMin * aspect; + double xMax = yMax * aspect; + + return Frustum(xMin, xMax, yMin, yMax, near, far); + } + + #endregion + + #region Multiply Functions + + /// + /// Multiplies two instances. + /// + /// The left operand of the multiplication. + /// The right operand of the multiplication. + /// A new instance that is the result of the multiplication + public static Matrix4d Mult(Matrix4d left, Matrix4d right) + { + Matrix4d result; + Mult(ref left, ref right, out result); + return result; + } + + /// + /// Multiplies two instances. + /// + /// The left operand of the multiplication. + /// The right operand of the multiplication. + /// A new instance that is the result of the multiplication + public static void Mult(ref Matrix4d left, ref Matrix4d right, out Matrix4d result) + { + double lM11 = left.Row0.X, lM12 = left.Row0.Y, lM13 = left.Row0.Z, lM14 = left.Row0.W, + lM21 = left.Row1.X, lM22 = left.Row1.Y, lM23 = left.Row1.Z, lM24 = left.Row1.W, + lM31 = left.Row2.X, lM32 = left.Row2.Y, lM33 = left.Row2.Z, lM34 = left.Row2.W, + lM41 = left.Row3.X, lM42 = left.Row3.Y, lM43 = left.Row3.Z, lM44 = left.Row3.W, + rM11 = right.Row0.X, rM12 = right.Row0.Y, rM13 = right.Row0.Z, rM14 = right.Row0.W, + rM21 = right.Row1.X, rM22 = right.Row1.Y, rM23 = right.Row1.Z, rM24 = right.Row1.W, + rM31 = right.Row2.X, rM32 = right.Row2.Y, rM33 = right.Row2.Z, rM34 = right.Row2.W, + rM41 = right.Row3.X, rM42 = right.Row3.Y, rM43 = right.Row3.Z, rM44 = right.Row3.W; + + result.Row0.X = (((lM11 * rM11) + (lM12 * rM21)) + (lM13 * rM31)) + (lM14 * rM41); + result.Row0.Y = (((lM11 * rM12) + (lM12 * rM22)) + (lM13 * rM32)) + (lM14 * rM42); + result.Row0.Z = (((lM11 * rM13) + (lM12 * rM23)) + (lM13 * rM33)) + (lM14 * rM43); + result.Row0.W = (((lM11 * rM14) + (lM12 * rM24)) + (lM13 * rM34)) + (lM14 * rM44); + result.Row1.X = (((lM21 * rM11) + (lM22 * rM21)) + (lM23 * rM31)) + (lM24 * rM41); + result.Row1.Y = (((lM21 * rM12) + (lM22 * rM22)) + (lM23 * rM32)) + (lM24 * rM42); + result.Row1.Z = (((lM21 * rM13) + (lM22 * rM23)) + (lM23 * rM33)) + (lM24 * rM43); + result.Row1.W = (((lM21 * rM14) + (lM22 * rM24)) + (lM23 * rM34)) + (lM24 * rM44); + result.Row2.X = (((lM31 * rM11) + (lM32 * rM21)) + (lM33 * rM31)) + (lM34 * rM41); + result.Row2.Y = (((lM31 * rM12) + (lM32 * rM22)) + (lM33 * rM32)) + (lM34 * rM42); + result.Row2.Z = (((lM31 * rM13) + (lM32 * rM23)) + (lM33 * rM33)) + (lM34 * rM43); + result.Row2.W = (((lM31 * rM14) + (lM32 * rM24)) + (lM33 * rM34)) + (lM34 * rM44); + result.Row3.X = (((lM41 * rM11) + (lM42 * rM21)) + (lM43 * rM31)) + (lM44 * rM41); + result.Row3.Y = (((lM41 * rM12) + (lM42 * rM22)) + (lM43 * rM32)) + (lM44 * rM42); + result.Row3.Z = (((lM41 * rM13) + (lM42 * rM23)) + (lM43 * rM33)) + (lM44 * rM43); + result.Row3.W = (((lM41 * rM14) + (lM42 * rM24)) + (lM43 * rM34)) + (lM44 * rM44); + } + + #endregion + + #region Invert Functions + + /// + /// Calculate the inverse of the given matrix + /// + /// The matrix to invert + /// The inverse of the given matrix if it has one, or the input if it is singular + /// Thrown if the Matrix4d is singular. + public static Matrix4d Invert(Matrix4d mat) + { + int[] colIdx = { 0, 0, 0, 0 }; + int[] rowIdx = { 0, 0, 0, 0 }; + int[] pivotIdx = { -1, -1, -1, -1 }; + + // convert the matrix to an array for easy looping + double[,] inverse = {{mat.Row0.X, mat.Row0.Y, mat.Row0.Z, mat.Row0.W}, + {mat.Row1.X, mat.Row1.Y, mat.Row1.Z, mat.Row1.W}, + {mat.Row2.X, mat.Row2.Y, mat.Row2.Z, mat.Row2.W}, + {mat.Row3.X, mat.Row3.Y, mat.Row3.Z, mat.Row3.W} }; + int icol = 0; + int irow = 0; + for (int i = 0; i < 4; i++) + { + // Find the largest pivot value + double maxPivot = 0.0; + for (int j = 0; j < 4; j++) + { + if (pivotIdx[j] != 0) + { + for (int k = 0; k < 4; ++k) + { + if (pivotIdx[k] == -1) + { + double absVal = System.Math.Abs(inverse[j, k]); + if (absVal > maxPivot) + { + maxPivot = absVal; + irow = j; + icol = k; + } + } + else if (pivotIdx[k] > 0) + { + return mat; + } + } + } + } + + ++(pivotIdx[icol]); + + // Swap rows over so pivot is on diagonal + if (irow != icol) + { + for (int k = 0; k < 4; ++k) + { + double f = inverse[irow, k]; + inverse[irow, k] = inverse[icol, k]; + inverse[icol, k] = f; + } + } + + rowIdx[i] = irow; + colIdx[i] = icol; + + double pivot = inverse[icol, icol]; + // check for singular matrix + if (pivot == 0.0) + { + throw new InvalidOperationException("Matrix is singular and cannot be inverted."); + //return mat; + } + + // Scale row so it has a unit diagonal + double oneOverPivot = 1.0 / pivot; + inverse[icol, icol] = 1.0; + for (int k = 0; k < 4; ++k) + inverse[icol, k] *= oneOverPivot; + + // Do elimination of non-diagonal elements + for (int j = 0; j < 4; ++j) + { + // check this isn't on the diagonal + if (icol != j) + { + double f = inverse[j, icol]; + inverse[j, icol] = 0.0; + for (int k = 0; k < 4; ++k) + inverse[j, k] -= inverse[icol, k] * f; + } + } + } + + for (int j = 3; j >= 0; --j) + { + int ir = rowIdx[j]; + int ic = colIdx[j]; + for (int k = 0; k < 4; ++k) + { + double f = inverse[k, ir]; + inverse[k, ir] = inverse[k, ic]; + inverse[k, ic] = f; + } + } + + mat.Row0 = new Vector4d (inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3]); + mat.Row1 = new Vector4d (inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3]); + mat.Row2 = new Vector4d (inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3]); + mat.Row3 = new Vector4d (inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]); + return mat; + } + + #endregion + + #region Transpose + + /// + /// Calculate the transpose of the given matrix + /// + /// The matrix to transpose + /// The transpose of the given matrix + public static Matrix4d Transpose(Matrix4d mat) + { + return new Matrix4d(mat.Column0, mat.Column1, mat.Column2, mat.Column3); + } + + + /// + /// Calculate the transpose of the given matrix + /// + /// The matrix to transpose + /// The result of the calculation + public static void Transpose(ref Matrix4d mat, out Matrix4d result) + { + result.Row0 = mat.Column0; + result.Row1 = mat.Column1; + result.Row2 = mat.Column2; + result.Row3 = mat.Column3; + } + + #endregion + + #endregion + + #region Operators + + /// + /// Matrix multiplication + /// + /// left-hand operand + /// right-hand operand + /// A new Matrix44 which holds the result of the multiplication + public static Matrix4d operator *(Matrix4d left, Matrix4d right) + { + return Matrix4d.Mult(left, right); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Matrix4d left, Matrix4d right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equal right; false otherwise. + public static bool operator !=(Matrix4d left, Matrix4d right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Matrix44. + /// + /// + public override string ToString() + { + return String.Format("{0}\n{1}\n{2}\n{3}", Row0, Row1, Row2, Row3); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode() ^ Row3.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Matrix4d)) + return false; + + return this.Equals((Matrix4d)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current matrix is equal to another matrix. + /// An matrix to compare with this matrix. + /// true if the current matrix is equal to the matrix parameter; otherwise, false. + public bool Equals(Matrix4d other) + { + return + Row0 == other.Row0 && + Row1 == other.Row1 && + Row2 == other.Row2 && + Row3 == other.Row3; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/MiniTK/Math/Point.cs b/src/MiniTK/Math/Point.cs new file mode 100644 index 0000000..e54bb09 --- /dev/null +++ b/src/MiniTK/Math/Point.cs @@ -0,0 +1,235 @@ +#region License + // + // The Open Toolkit Library License + // + // Copyright (c) 2006 - 2009 the Open Toolkit library. + // + // 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. + // + #endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ +#if NO_SYSDRAWING + /// + /// Defines a point on a two-dimensional plane. + /// + public struct Point : IEquatable + { + #region Fields + + int x, y; + + #endregion + + #region Constructors + + /// + /// Constructs a new Point instance. + /// + /// The X coordinate of this instance. + /// The Y coordinate of this instance. + public Point(int x, int y) + : this() + { + X = x; + Y = y; + } + + #endregion + + #region Public Members + + /// + /// Gets a that indicates whether this instance is empty or zero. + /// + public bool IsEmpty { get { return X == 0 && Y == 0; } } + + /// + /// Gets or sets the X coordinate of this instance. + /// + public int X { get { return x; } set { x = value; } } + + /// + /// Gets or sets the Y coordinate of this instance. + /// + public int Y { get { return y; } set { y = value; } } + + /// + /// Returns the Point (0, 0). + /// + public static readonly Point Zero = new Point(); + + /// + /// Returns the Point (0, 0). + /// + public static readonly Point Empty = new Point(); + + /// + /// Translates the specified Point by the specified Size. + /// + /// + /// The instance to translate. + /// + /// + /// The instance to translate point with. + /// + /// + /// A new instance translated by size. + /// + public static Point operator +(Point point, Size size) + { + return new Point(point.X + size.Width, point.Y + size.Height); + } + + /// + /// Translates the specified Point by the negative of the specified Size. + /// + /// + /// The instance to translate. + /// + /// + /// The instance to translate point with. + /// + /// + /// A new instance translated by size. + /// + public static Point operator -(Point point, Size size) + { + return new Point(point.X - size.Width, point.Y - size.Height); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left is equal to right; false otherwise. + public static bool operator ==(Point left, Point right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left is not equal to right; false otherwise. + public static bool operator !=(Point left, Point right) + { + return !left.Equals(right); + } + + /// + /// Converts an OpenTK.Point instance to a System.Drawing.Point. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to point. + /// + public static implicit operator System.Drawing.Point(Point point) + { + return new System.Drawing.Point(point.X, point.Y); + } + + /// + /// Converts a System.Drawing.Point instance to an OpenTK.Point. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to point. + /// + public static implicit operator Point(System.Drawing.Point point) + { + return new Point(point.X, point.Y); + } + + /// + /// Converts an OpenTK.Point instance to a System.Drawing.PointF. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to point. + /// + public static implicit operator System.Drawing.PointF(Point point) + { + return new System.Drawing.PointF(point.X, point.Y); + } + + /// + /// Indicates whether this instance is equal to the specified object. + /// + /// The object instance to compare to. + /// True, if both instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (obj is Point) + return Equals((Point)obj); + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// A that represents the hash code for this instance./> + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + /// + /// Returns a that describes this instance. + /// + /// A that describes this instance. + public override string ToString() + { + return String.Format("{{{0}, {1}}}", X, Y); + } + + #endregion + + #region IEquatable Members + + /// + /// Indicates whether this instance is equal to the specified Point. + /// + /// The instance to compare to. + /// True, if both instances are equal; false otherwise. + public bool Equals(Point other) + { + return X == other.X && Y == other.Y; + } + + #endregion + } +#endif +} diff --git a/src/MiniTK/Math/Quaternion.cs b/src/MiniTK/Math/Quaternion.cs new file mode 100644 index 0000000..ec9aef5 --- /dev/null +++ b/src/MiniTK/Math/Quaternion.cs @@ -0,0 +1,705 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// Represents a Quaternion. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Quaternion : IEquatable + { + #region Fields + + Vector3 xyz; + float w; + + #endregion + + #region Constructors + + /// + /// Construct a new Quaternion from vector and w components + /// + /// The vector part + /// The w part + public Quaternion(Vector3 v, float w) + { + this.xyz = v; + this.w = w; + } + + /// + /// Construct a new Quaternion + /// + /// The x component + /// The y component + /// The z component + /// The w component + public Quaternion(float x, float y, float z, float w) + : this(new Vector3(x, y, z), w) + { } + + #endregion + + #region Public Members + + #region Properties + + /// + /// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance. + /// + [Obsolete("Use Xyz property instead.")] + [CLSCompliant(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + [XmlIgnore] + public Vector3 XYZ { get { return Xyz; } set { Xyz = value; } } + + /// + /// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance. + /// + public Vector3 Xyz { get { return xyz; } set { xyz = value; } } + + /// + /// Gets or sets the X component of this instance. + /// + [XmlIgnore] + public float X { get { return xyz.X; } set { xyz.X = value; } } + + /// + /// Gets or sets the Y component of this instance. + /// + [XmlIgnore] + public float Y { get { return xyz.Y; } set { xyz.Y = value; } } + + /// + /// Gets or sets the Z component of this instance. + /// + [XmlIgnore] + public float Z { get { return xyz.Z; } set { xyz.Z = value; } } + + /// + /// Gets or sets the W component of this instance. + /// + public float W { get { return w; } set { w = value; } } + + #endregion + + #region Instance + + #region ToAxisAngle + + /// + /// Convert the current quaternion to axis angle representation + /// + /// The resultant axis + /// The resultant angle + public void ToAxisAngle(out Vector3 axis, out float angle) + { + Vector4 result = ToAxisAngle(); + axis = result.Xyz; + angle = result.W; + } + + /// + /// Convert this instance to an axis-angle representation. + /// + /// A Vector4 that is the axis-angle representation of this quaternion. + public Vector4 ToAxisAngle() + { + Quaternion q = this; + if (Math.Abs(q.W) > 1.0f) + q.Normalize(); + + Vector4 result = new Vector4(); + + result.W = 2.0f * (float)System.Math.Acos(q.W); // angle + float den = (float)System.Math.Sqrt(1.0 - q.W * q.W); + if (den > 0.0001f) + { + result.Xyz = q.Xyz / den; + } + else + { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + result.Xyz = Vector3.UnitX; + } + + return result; + } + + #endregion + + #region public float Length + + /// + /// Gets the length (magnitude) of the quaternion. + /// + /// + public float Length + { + get + { + return (float)System.Math.Sqrt(W * W + Xyz.LengthSquared); + } + } + + #endregion + + #region public float LengthSquared + + /// + /// Gets the square of the quaternion length (magnitude). + /// + public float LengthSquared + { + get + { + return W * W + Xyz.LengthSquared; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Quaternion to unit length. + /// + public void Normalize() + { + float scale = 1.0f / this.Length; + Xyz *= scale; + W *= scale; + } + + #endregion + + #region public void Conjugate() + + /// + /// Convert this quaternion to its conjugate + /// + public void Conjugate() + { + Xyz = -Xyz; + } + + #endregion + + #endregion + + #region Static + + #region Fields + + /// + /// Defines the identity quaternion. + /// + public static Quaternion Identity = new Quaternion(0, 0, 0, 1); + + #endregion + + #region Add + + /// + /// Add two quaternions + /// + /// The first operand + /// The second operand + /// The result of the addition + public static Quaternion Add(Quaternion left, Quaternion right) + { + return new Quaternion( + left.Xyz + right.Xyz, + left.W + right.W); + } + + /// + /// Add two quaternions + /// + /// The first operand + /// The second operand + /// The result of the addition + public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result) + { + result = new Quaternion( + left.Xyz + right.Xyz, + left.W + right.W); + } + + #endregion + + #region Sub + + /// + /// Subtracts two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static Quaternion Sub(Quaternion left, Quaternion right) + { + return new Quaternion( + left.Xyz - right.Xyz, + left.W - right.W); + } + + /// + /// Subtracts two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result) + { + result = new Quaternion( + left.Xyz - right.Xyz, + left.W - right.W); + } + + #endregion + + #region Mult + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + [Obsolete("Use Multiply instead.")] + public static Quaternion Mult(Quaternion left, Quaternion right) + { + return new Quaternion( + right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + [Obsolete("Use Multiply instead.")] + public static void Mult(ref Quaternion left, ref Quaternion right, out Quaternion result) + { + result = new Quaternion( + right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + public static Quaternion Multiply(Quaternion left, Quaternion right) + { + Quaternion result; + Multiply(ref left, ref right, out result); + return result; + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result) + { + result = new Quaternion( + right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static void Multiply(ref Quaternion quaternion, float scale, out Quaternion result) + { + result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaternion Multiply(Quaternion quaternion, float scale) + { + return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + #endregion + + #region Conjugate + + /// + /// Get the conjugate of the given quaternion + /// + /// The quaternion + /// The conjugate of the given quaternion + public static Quaternion Conjugate(Quaternion q) + { + return new Quaternion(-q.Xyz, q.W); + } + + /// + /// Get the conjugate of the given quaternion + /// + /// The quaternion + /// The conjugate of the given quaternion + public static void Conjugate(ref Quaternion q, out Quaternion result) + { + result = new Quaternion(-q.Xyz, q.W); + } + + #endregion + + #region Invert + + /// + /// Get the inverse of the given quaternion + /// + /// The quaternion to invert + /// The inverse of the given quaternion + public static Quaternion Invert(Quaternion q) + { + Quaternion result; + Invert(ref q, out result); + return result; + } + + /// + /// Get the inverse of the given quaternion + /// + /// The quaternion to invert + /// The inverse of the given quaternion + public static void Invert(ref Quaternion q, out Quaternion result) + { + float lengthSq = q.LengthSquared; + if (lengthSq != 0.0) + { + float i = 1.0f / lengthSq; + result = new Quaternion(q.Xyz * -i, q.W * i); + } + else + { + result = q; + } + } + + #endregion + + #region Normalize + + /// + /// Scale the given quaternion to unit length + /// + /// The quaternion to normalize + /// The normalized quaternion + public static Quaternion Normalize(Quaternion q) + { + Quaternion result; + Normalize(ref q, out result); + return result; + } + + /// + /// Scale the given quaternion to unit length + /// + /// The quaternion to normalize + /// The normalized quaternion + public static void Normalize(ref Quaternion q, out Quaternion result) + { + float scale = 1.0f / q.Length; + result = new Quaternion(q.Xyz * scale, q.W * scale); + } + + #endregion + + #region FromAxisAngle + + /// + /// Build a quaternion from the given axis and angle + /// + /// The axis to rotate about + /// The rotation angle in radians + /// + public static Quaternion FromAxisAngle(Vector3 axis, float angle) + { + if (axis.LengthSquared == 0.0f) + return Identity; + + Quaternion result = Identity; + + angle *= 0.5f; + axis.Normalize(); + result.Xyz = axis * (float)System.Math.Sin(angle); + result.W = (float)System.Math.Cos(angle); + + return Normalize(result); + } + + #endregion + + #region Slerp + + /// + /// Do Spherical linear interpolation between two quaternions + /// + /// The first quaternion + /// The second quaternion + /// The blend factor + /// A smooth blend between the given quaternions + public static Quaternion Slerp(Quaternion q1, Quaternion q2, float blend) + { + // if either input is zero, return the other. + if (q1.LengthSquared == 0.0f) + { + if (q2.LengthSquared == 0.0f) + { + return Identity; + } + return q2; + } + else if (q2.LengthSquared == 0.0f) + { + return q1; + } + + + float cosHalfAngle = q1.W * q2.W + Vector3.Dot(q1.Xyz, q2.Xyz); + + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) + { + // angle = 0.0f, so just return one input. + return q1; + } + else if (cosHalfAngle < 0.0f) + { + q2.Xyz = -q2.Xyz; + q2.W = -q2.W; + cosHalfAngle = -cosHalfAngle; + } + + float blendA; + float blendB; + if (cosHalfAngle < 0.99f) + { + // do proper slerp for big angles + float halfAngle = (float)System.Math.Acos(cosHalfAngle); + float sinHalfAngle = (float)System.Math.Sin(halfAngle); + float oneOverSinHalfAngle = 1.0f / sinHalfAngle; + blendA = (float)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle; + blendB = (float)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle; + } + else + { + // do lerp if angle is really small. + blendA = 1.0f - blend; + blendB = blend; + } + + Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W); + if (result.LengthSquared > 0.0f) + return Normalize(result); + else + return Identity; + } + + #endregion + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaternion operator +(Quaternion left, Quaternion right) + { + left.Xyz += right.Xyz; + left.W += right.W; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaternion operator -(Quaternion left, Quaternion right) + { + left.Xyz -= right.Xyz; + left.W -= right.W; + return left; + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaternion operator *(Quaternion left, Quaternion right) + { + Multiply(ref left, ref right, out left); + return left; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaternion operator *(Quaternion quaternion, float scale) + { + Multiply(ref quaternion, scale, out quaternion); + return quaternion; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaternion operator *(float scale, Quaternion quaternion) + { + return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Quaternion left, Quaternion right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equal right; false otherwise. + public static bool operator !=(Quaternion left, Quaternion right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Quaternion. + /// + /// + public override string ToString() + { + return String.Format("V: {0}, W: {1}", Xyz, W); + } + + #endregion + + #region public override bool Equals (object o) + + /// + /// Compares this object instance to another object for equality. + /// + /// The other object to be used in the comparison. + /// True if both objects are Quaternions of equal value. Otherwise it returns false. + public override bool Equals(object other) + { + if (other is Quaternion == false) return false; + return this == (Quaternion)other; + } + + #endregion + + #region public override int GetHashCode () + + /// + /// Provides the hash code for this object. + /// + /// A hash code formed from the bitwise XOR of this objects members. + public override int GetHashCode() + { + return Xyz.GetHashCode() ^ W.GetHashCode(); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// + /// Compares this Quaternion instance to another Quaternion for equality. + /// + /// The other Quaternion to be used in the comparison. + /// True if both instances are equal; false otherwise. + public bool Equals(Quaternion other) + { + return Xyz == other.Xyz && W == other.W; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Quaterniond.cs b/src/MiniTK/Math/Quaterniond.cs new file mode 100644 index 0000000..7be8168 --- /dev/null +++ b/src/MiniTK/Math/Quaterniond.cs @@ -0,0 +1,1330 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. +*/ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// Represents a double-precision Quaternion. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Quaterniond : IEquatable + { + #region Fields + + Vector3d xyz; + double w; + + #endregion + + #region Constructors + + /// + /// Construct a new Quaterniond from vector and w components + /// + /// The vector part + /// The w part + public Quaterniond(Vector3d v, double w) + { + this.xyz = v; + this.w = w; + } + + /// + /// Construct a new Quaterniond + /// + /// The x component + /// The y component + /// The z component + /// The w component + public Quaterniond(double x, double y, double z, double w) + : this(new Vector3d(x, y, z), w) + { } + + #endregion + + #region Public Members + + #region Properties + + /// + /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance. + /// + [Obsolete("Use Xyz property instead.")] + [CLSCompliant(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + [XmlIgnore] + public Vector3d XYZ { get { return Xyz; } set { Xyz = value; } } + + /// + /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance. + /// + public Vector3d Xyz { get { return xyz; } set { xyz = value; } } + + /// + /// Gets or sets the X component of this instance. + /// + [XmlIgnore] + public double X { get { return xyz.X; } set { xyz.X = value; } } + + /// + /// Gets or sets the Y component of this instance. + /// + [XmlIgnore] + public double Y { get { return xyz.Y; } set { xyz.Y = value; } } + + /// + /// Gets or sets the Z component of this instance. + /// + [XmlIgnore] + public double Z { get { return xyz.Z; } set { xyz.Z = value; } } + + /// + /// Gets or sets the W component of this instance. + /// + public double W { get { return w; } set { w = value; } } + + #endregion + + #region Instance + + #region ToAxisAngle + + /// + /// Convert the current quaternion to axis angle representation + /// + /// The resultant axis + /// The resultant angle + public void ToAxisAngle(out Vector3d axis, out double angle) + { + Vector4d result = ToAxisAngle(); + axis = result.Xyz; + angle = result.W; + } + + /// + /// Convert this instance to an axis-angle representation. + /// + /// A Vector4 that is the axis-angle representation of this quaternion. + public Vector4d ToAxisAngle() + { + Quaterniond q = this; + if (Math.Abs(q.W) > 1.0f) + q.Normalize(); + + Vector4d result = new Vector4d(); + + result.W = 2.0f * (float)System.Math.Acos(q.W); // angle + float den = (float)System.Math.Sqrt(1.0 - q.W * q.W); + if (den > 0.0001f) + { + result.Xyz = q.Xyz / den; + } + else + { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + result.Xyz = Vector3d.UnitX; + } + + return result; + } + + #endregion + + #region public double Length + + /// + /// Gets the length (magnitude) of the Quaterniond. + /// + /// + public double Length + { + get + { + return (double)System.Math.Sqrt(W * W + Xyz.LengthSquared); + } + } + + #endregion + + #region public double LengthSquared + + /// + /// Gets the square of the Quaterniond length (magnitude). + /// + public double LengthSquared + { + get + { + return W * W + Xyz.LengthSquared; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Quaterniond to unit length. + /// + public void Normalize() + { + double scale = 1.0f / this.Length; + Xyz *= scale; + W *= scale; + } + + #endregion + + #region public void Conjugate() + + /// + /// Convert this Quaterniond to its conjugate + /// + public void Conjugate() + { + Xyz = -Xyz; + } + + #endregion + + #endregion + + #region Static + + #region Fields + + /// + /// Defines the identity quaternion. + /// + public readonly static Quaterniond Identity = new Quaterniond(0, 0, 0, 1); + + #endregion + + #region Add + + /// + /// Add two quaternions + /// + /// The first operand + /// The second operand + /// The result of the addition + public static Quaterniond Add(Quaterniond left, Quaterniond right) + { + return new Quaterniond( + left.Xyz + right.Xyz, + left.W + right.W); + } + + /// + /// Add two quaternions + /// + /// The first operand + /// The second operand + /// The result of the addition + public static void Add(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result = new Quaterniond( + left.Xyz + right.Xyz, + left.W + right.W); + } + + #endregion + + #region Sub + + /// + /// Subtracts two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static Quaterniond Sub(Quaterniond left, Quaterniond right) + { + return new Quaterniond( + left.Xyz - right.Xyz, + left.W - right.W); + } + + /// + /// Subtracts two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static void Sub(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result = new Quaterniond( + left.Xyz - right.Xyz, + left.W - right.W); + } + + #endregion + + #region Mult + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + [Obsolete("Use Multiply instead.")] + public static Quaterniond Mult(Quaterniond left, Quaterniond right) + { + return new Quaterniond( + right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + [Obsolete("Use Multiply instead.")] + public static void Mult(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result = new Quaterniond( + right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + public static Quaterniond Multiply(Quaterniond left, Quaterniond right) + { + Quaterniond result; + Multiply(ref left, ref right, out result); + return result; + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// A new instance containing the result of the calculation. + public static void Multiply(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result = new Quaterniond( + right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), + left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static void Multiply(ref Quaterniond quaternion, double scale, out Quaterniond result) + { + result = new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaterniond Multiply(Quaterniond quaternion, double scale) + { + return new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + #endregion + + #region Conjugate + + /// + /// Get the conjugate of the given Quaterniond + /// + /// The Quaterniond + /// The conjugate of the given Quaterniond + public static Quaterniond Conjugate(Quaterniond q) + { + return new Quaterniond(-q.Xyz, q.W); + } + + /// + /// Get the conjugate of the given Quaterniond + /// + /// The Quaterniond + /// The conjugate of the given Quaterniond + public static void Conjugate(ref Quaterniond q, out Quaterniond result) + { + result = new Quaterniond(-q.Xyz, q.W); + } + + #endregion + + #region Invert + + /// + /// Get the inverse of the given Quaterniond + /// + /// The Quaterniond to invert + /// The inverse of the given Quaterniond + public static Quaterniond Invert(Quaterniond q) + { + Quaterniond result; + Invert(ref q, out result); + return result; + } + + /// + /// Get the inverse of the given Quaterniond + /// + /// The Quaterniond to invert + /// The inverse of the given Quaterniond + public static void Invert(ref Quaterniond q, out Quaterniond result) + { + double lengthSq = q.LengthSquared; + if (lengthSq != 0.0) + { + double i = 1.0f / lengthSq; + result = new Quaterniond(q.Xyz * -i, q.W * i); + } + else + { + result = q; + } + } + + #endregion + + #region Normalize + + /// + /// Scale the given Quaterniond to unit length + /// + /// The Quaterniond to normalize + /// The normalized Quaterniond + public static Quaterniond Normalize(Quaterniond q) + { + Quaterniond result; + Normalize(ref q, out result); + return result; + } + + /// + /// Scale the given Quaterniond to unit length + /// + /// The Quaterniond to normalize + /// The normalized Quaterniond + public static void Normalize(ref Quaterniond q, out Quaterniond result) + { + double scale = 1.0f / q.Length; + result = new Quaterniond(q.Xyz * scale, q.W * scale); + } + + #endregion + + #region FromAxisAngle + + /// + /// Build a Quaterniond from the given axis and angle + /// + /// The axis to rotate about + /// The rotation angle in radians + /// + public static Quaterniond FromAxisAngle(Vector3d axis, double angle) + { + if (axis.LengthSquared == 0.0f) + return Identity; + + Quaterniond result = Identity; + + angle *= 0.5f; + axis.Normalize(); + result.Xyz = axis * (double)System.Math.Sin(angle); + result.W = (double)System.Math.Cos(angle); + + return Normalize(result); + } + + #endregion + + #region Slerp + + /// + /// Do Spherical linear interpolation between two quaternions + /// + /// The first Quaterniond + /// The second Quaterniond + /// The blend factor + /// A smooth blend between the given quaternions + public static Quaterniond Slerp(Quaterniond q1, Quaterniond q2, double blend) + { + // if either input is zero, return the other. + if (q1.LengthSquared == 0.0f) + { + if (q2.LengthSquared == 0.0f) + { + return Identity; + } + return q2; + } + else if (q2.LengthSquared == 0.0f) + { + return q1; + } + + + double cosHalfAngle = q1.W * q2.W + Vector3d.Dot(q1.Xyz, q2.Xyz); + + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) + { + // angle = 0.0f, so just return one input. + return q1; + } + else if (cosHalfAngle < 0.0f) + { + q2.Xyz = -q2.Xyz; + q2.W = -q2.W; + cosHalfAngle = -cosHalfAngle; + } + + double blendA; + double blendB; + if (cosHalfAngle < 0.99f) + { + // do proper slerp for big angles + double halfAngle = (double)System.Math.Acos(cosHalfAngle); + double sinHalfAngle = (double)System.Math.Sin(halfAngle); + double oneOverSinHalfAngle = 1.0f / sinHalfAngle; + blendA = (double)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle; + blendB = (double)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle; + } + else + { + // do lerp if angle is really small. + blendA = 1.0f - blend; + blendB = blend; + } + + Quaterniond result = new Quaterniond(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W); + if (result.LengthSquared > 0.0f) + return Normalize(result); + else + return Identity; + } + + #endregion + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaterniond operator +(Quaterniond left, Quaterniond right) + { + left.Xyz += right.Xyz; + left.W += right.W; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaterniond operator -(Quaterniond left, Quaterniond right) + { + left.Xyz -= right.Xyz; + left.W -= right.W; + return left; + } + + /// + /// Multiplies two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Quaterniond operator *(Quaterniond left, Quaterniond right) + { + Multiply(ref left, ref right, out left); + return left; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaterniond operator *(Quaterniond quaternion, double scale) + { + Multiply(ref quaternion, scale, out quaternion); + return quaternion; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// A new instance containing the result of the calculation. + public static Quaterniond operator *(double scale, Quaterniond quaternion) + { + return new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Quaterniond left, Quaterniond right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equal right; false otherwise. + public static bool operator !=(Quaterniond left, Quaterniond right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Quaterniond. + /// + /// + public override string ToString() + { + return String.Format("V: {0}, W: {1}", Xyz, W); + } + + #endregion + + #region public override bool Equals (object o) + + /// + /// Compares this object instance to another object for equality. + /// + /// The other object to be used in the comparison. + /// True if both objects are Quaternions of equal value. Otherwise it returns false. + public override bool Equals(object other) + { + if (other is Quaterniond == false) return false; + return this == (Quaterniond)other; + } + + #endregion + + #region public override int GetHashCode () + + /// + /// Provides the hash code for this object. + /// + /// A hash code formed from the bitwise XOR of this objects members. + public override int GetHashCode() + { + return Xyz.GetHashCode() ^ W.GetHashCode(); + } + + #endregion + + #endregion + + #endregion + +#if false + + #region Fields + + /// The W component of the Quaterniond. + public double W; + + /// The X component of the Quaterniond. + public double X; + + /// The Y component of the Quaterniond. + public double Y; + + /// The Z component of the Quaterniond. + public double Z; + + #endregion + + #region Constructors + + /// Constructs left Quaterniond that is left copy of the given Quaterniond. + /// The Quaterniond to copy. + public Quaterniond(ref Quaterniond Quaterniond) : this(Quaterniond.W, Quaterniond.X, Quaterniond.Y, Quaterniond.Z) { } + + /// Constructs left Quaterniond from the given components. + /// The W component for the Quaterniond. + /// A Vector representing the X, Y, and Z componets for the quaterion. + public Quaterniond(double w, ref Vector3d vector3d) : this(w, vector3d.X, vector3d.Y, vector3d.Z) { } + + /// Constructs left Quaterniond from the given axis and angle. + /// The axis for the Quaterniond. + /// The angle for the quaternione. + public Quaterniond(ref Vector3d axis, double angle) + { + double halfAngle = Functions.DTOR * angle / 2; + + this.W = System.Math.Cos(halfAngle); + + double sin = System.Math.Sin(halfAngle); + Vector3d axisNormalized; + Vector3d.Normalize(ref axis, out axisNormalized); + this.X = axisNormalized.X * sin; + this.Y = axisNormalized.Y * sin; + this.Z = axisNormalized.Z * sin; + } + + /// Constructs left Quaterniond from the given components. + /// The W component for the Quaterniond. + /// The X component for the Quaterniond. + /// The Y component for the Quaterniond. + /// The Z component for the Quaterniond. + public Quaterniond(double w, double x, double y, double z) + { + this.W = w; + this.X = x; + this.Y = y; + this.Z = z; + } + + /// Constructs left Quaterniond from the given array of double-precision floating-point numbers. + /// The array of doubles for the components of the Quaterniond. + public Quaterniond(double[] doubleArray) + { + if (doubleArray == null || doubleArray.GetLength(0) < 4) throw new MissingFieldException(); + + this.W = doubleArray[0]; + this.X = doubleArray[1]; + this.Y = doubleArray[2]; + this.Z = doubleArray[3]; + } + + /// Constructs left Quaterniond from the given matrix. Only contains rotation information. + /// The matrix for the components of the Quaterniond. + public Quaterniond(ref Matrix4d matrix) + { + double scale = System.Math.Pow(matrix.Determinant, 1.0d/3.0d); + + W = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2; + X = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])) / 2; + Y = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] + matrix[1, 1] - matrix[2, 2])) / 2; + Z = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] - matrix[1, 1] + matrix[2, 2])) / 2; + if( matrix[2,1] - matrix[1,2] < 0 ) X = -X; + if( matrix[0,2] - matrix[2,0] < 0 ) Y = -Y; + if( matrix[1,0] - matrix[0,1] < 0 ) Z = -Z; + } + + public Quaterniond(ref Matrix3d matrix) + { + double scale = System.Math.Pow(matrix.Determinant, 1.0d / 3.0d); + + W = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2; + X = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])) / 2; + Y = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] + matrix[1, 1] - matrix[2, 2])) / 2; + Z = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] - matrix[1, 1] + matrix[2, 2])) / 2; + if (matrix[2, 1] - matrix[1, 2] < 0) X = -X; + if (matrix[0, 2] - matrix[2, 0] < 0) Y = -Y; + if (matrix[1, 0] - matrix[0, 1] < 0) Z = -Z; + } + + #endregion + + #region Arithmetic Operators + + public void Add(ref Quaterniond Quaterniond) + { + W = W + Quaterniond.W; + X = X + Quaterniond.X; + Y = Y + Quaterniond.Y; + Z = Z + Quaterniond.Z; + } + public void Add(ref Quaterniond Quaterniond, out Quaterniond result) + { + result.W = W + Quaterniond.W; + result.X = X + Quaterniond.X; + result.Y = Y + Quaterniond.Y; + result.Z = Z + Quaterniond.Z; + } + public static void Add(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result.W = left.W + right.W; + result.X = left.X + right.X; + result.Y = left.Y + right.Y; + result.Z = left.Z + right.Z; + } + + public void Subtract(ref Quaterniond Quaterniond) + { + W = W - Quaterniond.W; + X = X - Quaterniond.X; + Y = Y - Quaterniond.Y; + Z = Z - Quaterniond.Z; + } + public void Subtract(ref Quaterniond Quaterniond, out Quaterniond result) + { + result.W = W - Quaterniond.W; + result.X = X - Quaterniond.X; + result.Y = Y - Quaterniond.Y; + result.Z = Z - Quaterniond.Z; + } + public static void Subtract(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result.W = left.W - right.W; + result.X = left.X - right.X; + result.Y = left.Y - right.Y; + result.Z = left.Z - right.Z; + } + + public void Multiply(ref Quaterniond Quaterniond) + { + double w = W * Quaterniond.W - X * Quaterniond.X - Y * Quaterniond.Y - Z * Quaterniond.Z; + double x = W * Quaterniond.X + X * Quaterniond.W + Y * Quaterniond.Z - Z * Quaterniond.Y; + double y = W * Quaterniond.Y + Y * Quaterniond.W + Z * Quaterniond.X - X * Quaterniond.Z; + Z = W * Quaterniond.Z + Z * Quaterniond.W + X * Quaterniond.Y - Y * Quaterniond.X; + W = w; + X = x; + Y = y; + } + public void Multiply(ref Quaterniond Quaterniond, out Quaterniond result) + { + result.W = W * Quaterniond.W - X * Quaterniond.X - Y * Quaterniond.Y - Z * Quaterniond.Z; + result.X = W * Quaterniond.X + X * Quaterniond.W + Y * Quaterniond.Z - Z * Quaterniond.Y; + result.Y = W * Quaterniond.Y + Y * Quaterniond.W + Z * Quaterniond.X - X * Quaterniond.Z; + result.Z = W * Quaterniond.Z + Z * Quaterniond.W + X * Quaterniond.Y - Y * Quaterniond.X; + } + public static void Multiply(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) + { + result.W = left.W * right.W - left.X * right.X - left.Y * right.Y - left.Z * right.Z; + result.X = left.W * right.X + left.X * right.W + left.Y * right.Z - left.Z * right.Y; + result.Y = left.W * right.Y + left.Y * right.W + left.Z * right.X - left.X * right.Z; + result.Z = left.W * right.Z + left.Z * right.W + left.X * right.Y - left.Y * right.X; + } + + public void Multiply(double scalar) + { + W = W * scalar; + X = X * scalar; + Y = Y * scalar; + Z = Z * scalar; + } + public void Multiply(double scalar, out Quaterniond result) + { + result.W = W * scalar; + result.X = X * scalar; + result.Y = Y * scalar; + result.Z = Z * scalar; + } + public static void Multiply(ref Quaterniond Quaterniond, double scalar, out Quaterniond result) + { + result.W = Quaterniond.W * scalar; + result.X = Quaterniond.X * scalar; + result.Y = Quaterniond.Y * scalar; + result.Z = Quaterniond.Z * scalar; + } + + public void Divide(double scalar) + { + if (scalar == 0) throw new DivideByZeroException(); + W = W / scalar; + X = X / scalar; + Y = Y / scalar; + Z = Z / scalar; + } + public void Divide(double scalar, out Quaterniond result) + { + if (scalar == 0) throw new DivideByZeroException(); + result.W = W / scalar; + result.X = X / scalar; + result.Y = Y / scalar; + result.Z = Z / scalar; + } + public static void Divide(ref Quaterniond Quaterniond, double scalar, out Quaterniond result) + { + if (scalar == 0) throw new DivideByZeroException(); + result.W = Quaterniond.W / scalar; + result.X = Quaterniond.X / scalar; + result.Y = Quaterniond.Y / scalar; + result.Z = Quaterniond.Z / scalar; + } + + #endregion + + #region Functions + + public double Modulus + { + get + { + return System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); + } + } + public double ModulusSquared + { + get + { + return W * W + X * X + Y * Y + Z * Z; + } + } + + public static double DotProduct(Quaterniond left, Quaterniond right) + { + return left.W * right.W + left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + public void Normalize() + { + double modulus = System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); + if (modulus == 0) throw new DivideByZeroException(); + W = W / modulus; + X = X / modulus; + Y = Y / modulus; + Z = Z / modulus; + } + public void Normalize( out Quaterniond result ) + { + double modulus = System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); + if (modulus == 0) throw new DivideByZeroException(); + result.W = W / modulus; + result.X = X / modulus; + result.Y = Y / modulus; + result.Z = Z / modulus; + } + public static void Normalize(ref Quaterniond Quaterniond, out Quaterniond result) + { + double modulus = System.Math.Sqrt(Quaterniond.W * Quaterniond.W + Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z); + if (modulus == 0) throw new DivideByZeroException(); + result.W = Quaterniond.W / modulus; + result.X = Quaterniond.X / modulus; + result.Y = Quaterniond.Y / modulus; + result.Z = Quaterniond.Z / modulus; + } + + public void Conjugate() + { + X = -X; + Y = -Y; + Z = -Z; + } + public void Conjugate( out Quaterniond result ) + { + result.W = W; + result.X = -X; + result.Y = -Y; + result.Z = -Z; + } + public static void Conjugate(ref Quaterniond Quaterniond, out Quaterniond result) + { + result.W = Quaterniond.W; + result.X = -Quaterniond.X; + result.Y = -Quaterniond.Y; + result.Z = -Quaterniond.Z; + } + + public void Inverse() + { + double modulusSquared = W * W + X * X + Y * Y + Z * Z; + if (modulusSquared <= 0) throw new InvalidOperationException(); + double inverseModulusSquared = 1.0 / modulusSquared; + W = W * inverseModulusSquared; + X = X * -inverseModulusSquared; + Y = Y * -inverseModulusSquared; + Z = Z * -inverseModulusSquared; + } + public void Inverse( out Quaterniond result ) + { + double modulusSquared = W * W + X * X + Y * Y + Z * Z; + if (modulusSquared <= 0) throw new InvalidOperationException(); + double inverseModulusSquared = 1.0 / modulusSquared; + result.W = W * inverseModulusSquared; + result.X = X * -inverseModulusSquared; + result.Y = Y * -inverseModulusSquared; + result.Z = Z * -inverseModulusSquared; + } + public static void Inverse(ref Quaterniond Quaterniond, out Quaterniond result) + { + double modulusSquared = Quaterniond.W * Quaterniond.W + Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z; + if (modulusSquared <= 0) throw new InvalidOperationException(); + double inverseModulusSquared = 1.0 / modulusSquared; + result.W = Quaterniond.W * inverseModulusSquared; + result.X = Quaterniond.X * -inverseModulusSquared; + result.Y = Quaterniond.Y * -inverseModulusSquared; + result.Z = Quaterniond.Z * -inverseModulusSquared; + } + + public void Log() + { + if (System.Math.Abs(W) < 1.0) + { + double angle = System.Math.Acos(W); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) >= 0) + { + double coefficient = angle / sin; + X = X * coefficient; + Y = Y * coefficient; + Z = Z * coefficient; + } + } + else + { + X = 0; + Y = 0; + Z = 0; + } + + W = 0; + } + public void Log( out Quaterniond result ) + { + if (System.Math.Abs(W) < 1.0) + { + double angle = System.Math.Acos(W); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) >= 0) + { + double coefficient = angle / sin; + result.X = X * coefficient; + result.Y = Y * coefficient; + result.Z = Z * coefficient; + } + else + { + result.X = X; + result.Y = Y; + result.Z = Z; + } + } + else + { + result.X = 0; + result.Y = 0; + result.Z = 0; + } + + result.W = 0; + } + public static void Log(ref Quaterniond Quaterniond, out Quaterniond result) + { + if (System.Math.Abs(Quaterniond.W) < 1.0) + { + double angle = System.Math.Acos(Quaterniond.W); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) >= 0) + { + double coefficient = angle / sin; + result.X = Quaterniond.X * coefficient; + result.Y = Quaterniond.Y * coefficient; + result.Z = Quaterniond.Z * coefficient; + } + else + { + result.X = Quaterniond.X; + result.Y = Quaterniond.Y; + result.Z = Quaterniond.Z; + } + } + else + { + result.X = 0; + result.Y = 0; + result.Z = 0; + } + + result.W = 0; + } + + public void Exp() + { + double angle = System.Math.Sqrt(X * X + Y * Y + Z * Z); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) > 0) + { + double coefficient = angle / sin; + W = 0; + X = X * coefficient; + Y = Y * coefficient; + Z = Z * coefficient; + } + else + { + W = 0; + } + } + public void Exp(out Quaterniond result) + { + double angle = System.Math.Sqrt(X * X + Y * Y + Z * Z); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) > 0) + { + double coefficient = angle / sin; + result.W = 0; + result.X = X * coefficient; + result.Y = Y * coefficient; + result.Z = Z * coefficient; + } + else + { + result.W = 0; + result.X = X; + result.Y = Y; + result.Z = Z; + } + } + public static void Exp(ref Quaterniond Quaterniond, out Quaterniond result) + { + double angle = System.Math.Sqrt(Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z); + double sin = System.Math.Sin(angle); + + if (System.Math.Abs(sin) > 0) + { + double coefficient = angle / sin; + result.W = 0; + result.X = Quaterniond.X * coefficient; + result.Y = Quaterniond.Y * coefficient; + result.Z = Quaterniond.Z * coefficient; + } + else + { + result.W = 0; + result.X = Quaterniond.X; + result.Y = Quaterniond.Y; + result.Z = Quaterniond.Z; + } + } + + /// Returns left matrix for this Quaterniond. + public void Matrix4d(out Matrix4d result) + { + // TODO Expand + result = new Matrix4d(ref this); + } + + public void GetAxisAndAngle(out Vector3d axis, out double angle) + { + Quaterniond Quaterniond; + Normalize(out Quaterniond); + double cos = Quaterniond.W; + angle = System.Math.Acos(cos) * 2 * Functions.RTOD; + double sin = System.Math.Sqrt( 1.0d - cos * cos ); + if ( System.Math.Abs( sin ) < 0.0001 ) sin = 1; + axis = new Vector3d(X / sin, Y / sin, Z / sin); + } + + public static void Slerp(ref Quaterniond start, ref Quaterniond end, double blend, out Quaterniond result) + { + if (start.W == 0 && start.X == 0 && start.Y == 0 && start.Z == 0) + { + if (end.W == 0 && end.X == 0 && end.Y == 0 && end.Z == 0) + { + result.W = 1; + result.X = 0; + result.Y = 0; + result.Z = 0; + } + else + { + result = end; + } + } + else if (end.W == 0 && end.X == 0 && end.Y == 0 && end.Z == 0) + { + result = start; + } + + Vector3d startVector = new Vector3d(start.X, start.Y, start.Z); + Vector3d endVector = new Vector3d(end.X, end.Y, end.Z); + double cosHalfAngle = start.W * end.W + Vector3d.Dot(startVector, endVector); + + if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) + { + // angle = 0.0f, so just return one input. + result = start; + } + else if (cosHalfAngle < 0.0f) + { + end.W = -end.W; + end.X = -end.X; + end.Y = -end.Y; + end.Z = -end.Z; + cosHalfAngle = -cosHalfAngle; + } + + double blendA; + double blendB; + if (cosHalfAngle < 0.99f) + { + // do proper slerp for big angles + double halfAngle = (double)System.Math.Acos(cosHalfAngle); + double sinHalfAngle = (double)System.Math.Sin(halfAngle); + double oneOverSinHalfAngle = 1.0f / sinHalfAngle; + blendA = (double)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle; + blendB = (double)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle; + } + else + { + // do lerp if angle is really small. + blendA = 1.0f - blend; + blendB = blend; + } + + result.W = blendA * start.W + blendB * end.W; + result.X = blendA * start.X + blendB * end.X; + result.Y = blendA * start.Y + blendB * end.Y; + result.Z = blendA * start.Z + blendB * end.Z; + + if (result.W != 0 || result.X != 0 || result.Y != 0 || result.Z != 0) + { + result.Normalize(); + } + else + { + result.W = 1; + result.X = 0; + result.Y = 0; + result.Z = 0; + } + } + + #endregion + + #region HashCode + + /// Returns the hash code for this instance. + /// A 32-bit signed integer that is the hash code for this instance. + public override int GetHashCode() + { + base.GetHashCode(); + return W.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + #endregion + + #region String and Parse + + /// Returns the fully qualified type name of this instance. + /// A System.String containing left fully qualified type name. + public override string ToString() + { + return string.Format("({0}, {1}, {2}, {3})", W, X, Y, Z); + } + + /// Parses left string, converting it to left Quaterniond. + /// The string to parse. + /// The Quaterniond represented by the string. + public static void Parse(string str, out Quaterniond result) + { + Match match = new Regex(@"\((?.*),(?.*),(?.*),(?.*)\)", RegexOptions.None).Match(str); + if (!match.Success) throw new Exception("Parse failed!"); + + result.W = double.Parse(match.Result("${w}")); + result.X = double.Parse(match.Result("${x}")); + result.Y = double.Parse(match.Result("${y}")); + result.Z = double.Parse(match.Result("${z}")); + } + + #endregion + + #region Constants + + /// A quaterion with all zero components. + public static readonly Quaterniond Zero = new Quaterniond(0, 0, 0, 0); + + /// A quaterion representing an identity. + public static readonly Quaterniond Identity = new Quaterniond(1, 0, 0, 0); + + /// A quaterion representing the W axis. + public static readonly Quaterniond WAxis = new Quaterniond(1, 0, 0, 0); + + /// A quaterion representing the X axis. + public static readonly Quaterniond XAxis = new Quaterniond(0, 1, 0, 0); + + /// A quaterion representing the Y axis. + public static readonly Quaterniond YAxis = new Quaterniond(0, 0, 1, 0); + + /// A quaterion representing the Z axis. + public static readonly Quaterniond ZAxis = new Quaterniond(0, 0, 0, 1); + + #endregion + +#endif + + #region IEquatable Members + + /// + /// Compares this Quaterniond instance to another Quaterniond for equality. + /// + /// The other Quaterniond to be used in the comparison. + /// True if both instances are equal; false otherwise. + public bool Equals(Quaterniond other) + { + return Xyz == other.Xyz && W == other.W; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Rectangle.cs b/src/MiniTK/Math/Rectangle.cs new file mode 100644 index 0000000..700dbbf --- /dev/null +++ b/src/MiniTK/Math/Rectangle.cs @@ -0,0 +1,323 @@ +#region License + // + // The Open Toolkit Library License + // + // Copyright (c) 2006 - 2009 the Open Toolkit library. + // + // 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. + // + #endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ +#if NO_SYSDRAWING + /// + /// Represents a rectangular region on a two-dimensional plane. + /// + public struct Rectangle : IEquatable + { + #region Fields + + Point location; + Size size; + + #endregion + + #region Constructors + + /// + /// Constructs a new Rectangle instance. + /// + /// The top-left corner of the Rectangle. + /// The width and height of the Rectangle. + public Rectangle(Point location, Size size) + : this() + { + Location = location; + Size = size; + } + + /// + /// Constructs a new Rectangle instance. + /// + /// The x coordinate of the Rectangle. + /// The y coordinate of the Rectangle. + /// The width coordinate of the Rectangle. + /// The height coordinate of the Rectangle. + public Rectangle(int x, int y, int width, int height) + : this(new Point(x, y), new Size(width, height)) + { } + + #endregion + + #region Public Members + + /// + /// Gets or sets the x coordinate of the Rectangle. + /// + public int X + { + get { return Location.X; } + set { Location = new Point (value, Y); } + } + + /// + /// Gets or sets the y coordinate of the Rectangle. + /// + public int Y + { + get { return Location.Y; } + set { Location = new Point (X, value); } + } + + /// + /// Gets or sets the width of the Rectangle. + /// + public int Width + { + get { return Size.Width; } + set { Size = new Size (value, Height); } + } + + /// + /// Gets or sets the height of the Rectangle. + /// + public int Height + { + get { return Size.Height; } + set { Size = new Size(Width, value); } + } + + /// + /// Gets or sets a representing the x and y coordinates + /// of the Rectangle. + /// + public Point Location + { + get { return location; } + set { location = value; } + } + + /// + /// Gets or sets a representing the width and height + /// of the Rectangle. + /// + public Size Size + { + get { return size; } + set { size = value; } + } + + /// + /// Gets the y coordinate of the top edge of this Rectangle. + /// + public int Top { get { return Y; } } + + /// + /// Gets the x coordinate of the right edge of this Rectangle. + /// + public int Right { get { return X + Width; } } + + /// + /// Gets the y coordinate of the bottom edge of this Rectangle. + /// + public int Bottom { get { return Y + Height; } } + + /// + /// Gets the x coordinate of the left edge of this Rectangle. + /// + public int Left { get { return X; } } + + /// + /// Gets a that indicates whether this + /// Rectangle is equal to the empty Rectangle. + /// + public bool IsEmpty + { + get { return Location.IsEmpty && Size.IsEmpty; } + } + + /// + /// Defines the empty Rectangle. + /// + public static readonly Rectangle Zero = new Rectangle(); + + /// + /// Defines the empty Rectangle. + /// + public static readonly Rectangle Empty = new Rectangle(); + + /// + /// Constructs a new instance with the specified edges. + /// + /// The left edge of the Rectangle. + /// The top edge of the Rectangle. + /// The right edge of the Rectangle. + /// The bottom edge of the Rectangle. + /// A new Rectangle instance with the specified edges. + public static Rectangle FromLTRB(int left, int top, int right, int bottom) + { + return new Rectangle(new Point(left, top), new Size(right - left, bottom - top)); + } + + /// + /// Tests whether this instance contains the specified Point. + /// + /// The to test. + /// True if this instance contains point; false otherwise. + /// The left and top edges are inclusive. The right and bottom edges + /// are exclusive. + public bool Contains(Point point) + { + return point.X >= Left && point.X < Right && + point.Y >= Top && point.Y < Bottom; + } + + /// + /// Tests whether this instance contains the specified Rectangle. + /// + /// The to test. + /// True if this instance contains rect; false otherwise. + /// The left and top edges are inclusive. The right and bottom edges + /// are exclusive. + public bool Contains(Rectangle rect) + { + return Contains(rect.Location) && Contains(rect.Location + rect.Size); + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left is equal to right; false otherwise. + public static bool operator ==(Rectangle left, Rectangle right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left is not equal to right; false otherwise. + public static bool operator !=(Rectangle left, Rectangle right) + { + return !left.Equals(right); + } + + /// + /// Converts an OpenTK.Rectangle instance to a System.Drawing.Rectangle. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to rect. + /// + public static implicit operator System.Drawing.Rectangle(Rectangle rect) + { + return new System.Drawing.Rectangle(rect.Location, rect.Size); + } + + /// + /// Converts a System.Drawing.Rectangle instance to an OpenTK.Rectangle. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to point. + /// + public static implicit operator Rectangle(System.Drawing.Rectangle rect) + { + return new Rectangle(rect.Location, rect.Size); + } + + /// + /// Converts an OpenTK.Rectangle instance to a System.Drawing.RectangleF. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to rect. + /// + public static implicit operator System.Drawing.RectangleF(Rectangle rect) + { + return new System.Drawing.RectangleF(rect.Location, rect.Size); + } + + /// + /// Indicates whether this instance is equal to the specified object. + /// + /// The object instance to compare to. + /// True, if both instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (obj is Rectangle) + return Equals((Rectangle)obj); + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// A that represents the hash code for this instance./> + public override int GetHashCode() + { + return Location.GetHashCode() & Size.GetHashCode(); + } + + /// + /// Returns a that describes this instance. + /// + /// A that describes this instance. + public override string ToString() + { + return String.Format("{{{0}-{1}}}", Location, Location + Size); + } + + + #endregion + + #region IEquatable Members + + /// + /// Indicates whether this instance is equal to the specified Rectangle. + /// + /// The instance to compare to. + /// True, if both instances are equal; false otherwise. + public bool Equals(Rectangle other) + { + return Location.Equals(other.Location) && + Size.Equals(other.Size); + } + + #endregion + } +#endif +} diff --git a/src/MiniTK/Math/Size.cs b/src/MiniTK/Math/Size.cs new file mode 100644 index 0000000..04e556a --- /dev/null +++ b/src/MiniTK/Math/Size.cs @@ -0,0 +1,222 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2009 the Open Toolkit library. +// +// 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. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK +{ +#if NO_SYSDRAWING + /// + /// Stores the width and height of a rectangle. + /// + public struct Size : IEquatable + { + #region Fields + + int width, height; + + #endregion + + #region Constructors + + /// + /// Constructs a new Size instance. + /// + /// The width of this instance. + /// The height of this instance. + public Size(int width, int height) + : this() + { + Width = width; + Height = height; + } + + #endregion + + #region Public Members + + /// + /// Gets or sets the width of this instance. + /// + public int Width + { + get { return width; } + set + { + if (width < 0) + throw new ArgumentOutOfRangeException(); + width = value; + } + } + + /// + /// Gets or sets the height of this instance. + /// + public int Height + { + get { return height; } + set + { + if (height < 0) + throw new ArgumentOutOfRangeException(); + height = value; + } + } + + /// + /// Gets a that indicates whether this instance is empty or zero. + /// + public bool IsEmpty + { + get { return Width == 0 && Height == 0; } + } + + /// + /// Returns a Size instance equal to (0, 0). + /// + public static readonly Size Empty = new Size(); + + /// + /// Returns a Size instance equal to (0, 0). + /// + public static readonly Size Zero = new Size(); + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left is equal to right; false otherwise. + public static bool operator ==(Size left, Size right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left is not equal to right; false otherwise. + public static bool operator !=(Size left, Size right) + { + return !left.Equals(right); + } + + /// + /// Converts an OpenTK.Size instance to a System.Drawing.Size. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to size. + /// + public static implicit operator System.Drawing.Size(Size size) +{ + return new System.Drawing.Size(size.Width, size.Height); + } + + /// + /// Converts a System.Drawing.Size instance to an OpenTK.Size. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to size. + /// + public static implicit operator Size(System.Drawing.Size size) + { + return new Size(size.Width, size.Height); + } + + /// + /// Converts an OpenTK.Point instance to a System.Drawing.SizeF. + /// + /// + /// The instance to convert. + /// + /// + /// A instance equivalent to size. + /// + public static implicit operator System.Drawing.SizeF(Size size) + { + return new System.Drawing.SizeF(size.Width, size.Height); + } + + /// + /// Indicates whether this instance is equal to the specified object. + /// + /// The object instance to compare to. + /// True, if both instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (obj is Size) + return Equals((Size)obj); + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// A that represents the hash code for this instance./> + public override int GetHashCode() + { + return Width.GetHashCode() ^ Height.GetHashCode(); + } + + /// + /// Returns a that describes this instance. + /// + /// A that describes this instance. + public override string ToString() + { + return String.Format("{{{0}, {1}}}", Width, Height); + } + + #endregion + + #region IEquatable Members + + /// + /// Indicates whether this instance is equal to the specified Size. + /// + /// The instance to compare to. + /// True, if both instances are equal; false otherwise. + public bool Equals(Size other) + { + return Width == other.Width && Height == other.Height; + } + + #endregion + } +#endif +} diff --git a/src/MiniTK/Math/Vector2.cs b/src/MiniTK/Math/Vector2.cs new file mode 100644 index 0000000..56cfeae --- /dev/null +++ b/src/MiniTK/Math/Vector2.cs @@ -0,0 +1,1107 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + + +// flibit Added This!!! +#pragma warning disable 3021 + +using System; +using System.Runtime.InteropServices; +namespace OpenTK +{ + /// Represents a 2D vector using two single-precision floating-point numbers. + /// + /// The Vector2 structure is suitable for interoperation with unmanaged code requiring two consecutive floats. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector2 : IEquatable + { + #region Fields + + /// + /// The X component of the Vector2. + /// + public float X; + + /// + /// The Y component of the Vector2. + /// + public float Y; + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector2(float value) + { + X = value; + Y = value; + } + + /// + /// Constructs a new Vector2. + /// + /// The x coordinate of the net Vector2. + /// The y coordinate of the net Vector2. + public Vector2(float x, float y) + { + X = x; + Y = y; + } + + /// + /// Constructs a new Vector2 from the given Vector2. + /// + /// The Vector2 to copy components from. + [Obsolete] + public Vector2(Vector2 v) + { + X = v.X; + Y = v.Y; + } + + /// + /// Constructs a new Vector2 from the given Vector3. + /// + /// The Vector3 to copy components from. Z is discarded. + [Obsolete] + public Vector2(Vector3 v) + { + X = v.X; + Y = v.Y; + } + + /// + /// Constructs a new Vector2 from the given Vector4. + /// + /// The Vector4 to copy components from. Z and W are discarded. + [Obsolete] + public Vector2(Vector4 v) + { + X = v.X; + Y = v.Y; + } + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector2 right) + { + this.X += right.X; + this.Y += right.Y; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector2 right) + { + this.X += right.X; + this.Y += right.Y; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector2 right) + { + this.X -= right.X; + this.Y -= right.Y; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector2 right) + { + this.X -= right.X; + this.Y -= right.Y; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(float f) + { + this.X *= f; + this.Y *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(float f) + { + float mult = 1.0f / f; + this.X *= mult; + this.Y *= mult; + } + + #endregion public void Div() + + #region public float Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + /// + public float Length + { + get + { + return (float)System.Math.Sqrt(X * X + Y * Y); + } + } + + #endregion + + #region public float LengthFast + + /// + /// Gets an approximation of the vector length (magnitude). + /// + /// + /// This property uses an approximation of the square root function to calculate vector magnitude, with + /// an upper error bound of 0.001. + /// + /// + /// + public float LengthFast + { + get + { + return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y); + } + } + + #endregion + + #region public float LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + /// + public float LengthSquared + { + get + { + return X * X + Y * Y; + } + } + + #endregion + + #region public Vector2 PerpendicularRight + + /// + /// Gets the perpendicular vector on the right side of this vector. + /// + public Vector2 PerpendicularRight + { + get + { + return new Vector2(Y, -X); + } + } + + #endregion + + #region public Vector2 PerpendicularLeft + + /// + /// Gets the perpendicular vector on the left side of this vector. + /// + public Vector2 PerpendicularLeft + { + get + { + return new Vector2(-Y, X); + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector2 to unit length. + /// + public void Normalize() + { + float scale = 1.0f / this.Length; + X *= scale; + Y *= scale; + } + + #endregion + + #region public void NormalizeFast() + + /// + /// Scales the Vector2 to approximately unit length. + /// + public void NormalizeFast() + { + float scale = MathHelper.InverseSqrtFast(X * X + Y * Y); + X *= scale; + Y *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector2 by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(float sx, float sy) + { + this.X = X * sx; + this.Y = Y * sy; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector2 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector2 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Fields + + /// + /// Defines a unit-length Vector2 that points towards the X-axis. + /// + public static readonly Vector2 UnitX = new Vector2(1, 0); + + /// + /// Defines a unit-length Vector2 that points towards the Y-axis. + /// + public static readonly Vector2 UnitY = new Vector2(0, 1); + + /// + /// Defines a zero-length Vector2. + /// + public static readonly Vector2 Zero = new Vector2(0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector2 One = new Vector2(1, 1); + + /// + /// Defines the size of the Vector2 struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2()); + + #endregion + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static Vector2 Sub(Vector2 a, Vector2 b) + { + a.X -= b.X; + a.Y -= b.Y; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static void Sub(ref Vector2 a, ref Vector2 b, out Vector2 result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static Vector2 Mult(Vector2 a, float f) + { + a.X *= f; + a.Y *= f; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static void Mult(ref Vector2 a, float f, out Vector2 result) + { + result.X = a.X * f; + result.Y = a.Y * f; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static Vector2 Div(Vector2 a, float f) + { + float mult = 1.0f / f; + a.X *= mult; + a.Y *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static void Div(ref Vector2 a, float f, out Vector2 result) + { + float mult = 1.0f / f; + result.X = a.X * mult; + result.Y = a.Y * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector2 Add(Vector2 a, Vector2 b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result) + { + result = new Vector2(a.X + b.X, a.Y + b.Y); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector2 Subtract(Vector2 a, Vector2 b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector2 a, ref Vector2 b, out Vector2 result) + { + result = new Vector2(a.X - b.X, a.Y - b.Y); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2 Multiply(Vector2 vector, float scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector2 vector, float scale, out Vector2 result) + { + result = new Vector2(vector.X * scale, vector.Y * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2 Multiply(Vector2 vector, Vector2 scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector2 vector, ref Vector2 scale, out Vector2 result) + { + result = new Vector2(vector.X * scale.X, vector.Y * scale.Y); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2 Divide(Vector2 vector, float scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector2 vector, float scale, out Vector2 result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2 Divide(Vector2 vector, Vector2 scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector2 vector, ref Vector2 scale, out Vector2 result) + { + result = new Vector2(vector.X / scale.X, vector.Y / scale.Y); + } + + #endregion + + #region ComponentMin + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector2 ComponentMin(Vector2 a, Vector2 b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector2 a, ref Vector2 b, out Vector2 result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + } + + #endregion + + #region ComponentMax + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector2 ComponentMax(Vector2 a, Vector2 b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector2 a, ref Vector2 b, out Vector2 result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + } + + #endregion + + #region Min + + /// + /// Returns the Vector3 with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector2 Min(Vector2 left, Vector2 right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region Max + + /// + /// Returns the Vector3 with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector2 Max(Vector2 left, Vector2 right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector2 Clamp(Vector2 vec, Vector2 min, Vector2 max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector2 vec, ref Vector2 min, ref Vector2 max, out Vector2 result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector2 Normalize(Vector2 vec) + { + float scale = 1.0f / vec.Length; + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector2 vec, out Vector2 result) + { + float scale = 1.0f / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector2 NormalizeFast(Vector2 vec) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y); + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector2 vec, out Vector2 result) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static float Dot(Vector2 left, Vector2 right) + { + return left.X * right.X + left.Y * right.Y; + } + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector2 left, ref Vector2 right, out float result) + { + result = left.X * right.X + left.Y * right.Y; + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector2 Lerp(Vector2 a, Vector2 b, float blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector2 a, ref Vector2 b, float blend, out Vector2 result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector2 BaryCentric(Vector2 a, Vector2 b, Vector2 c, float u, float v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector2 a, ref Vector2 b, ref Vector2 c, float u, float v, out Vector2 result) + { + result = a; // copy + + Vector2 temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector2 Transform(Vector2 vec, Quaternion quat) + { + Vector2 result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector2 vec, ref Quaternion quat, out Vector2 result) + { + Quaternion v = new Quaternion(vec.X, vec.Y, 0, 0), i, t; + Quaternion.Invert(ref quat, out i); + Quaternion.Multiply(ref quat, ref v, out t); + Quaternion.Multiply(ref t, ref i, out v); + + result = new Vector2(v.X, v.Y); + } + + #endregion + + #endregion + + #region Operators + + /// + /// Adds the specified instances. + /// + /// Left operand. + /// Right operand. + /// Result of addition. + public static Vector2 operator +(Vector2 left, Vector2 right) + { + left.X += right.X; + left.Y += right.Y; + return left; + } + + /// + /// Subtracts the specified instances. + /// + /// Left operand. + /// Right operand. + /// Result of subtraction. + public static Vector2 operator -(Vector2 left, Vector2 right) + { + left.X -= right.X; + left.Y -= right.Y; + return left; + } + + /// + /// Negates the specified instance. + /// + /// Operand. + /// Result of negation. + public static Vector2 operator -(Vector2 vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + return vec; + } + + /// + /// Multiplies the specified instance by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of multiplication. + public static Vector2 operator *(Vector2 vec, float scale) + { + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Multiplies the specified instance by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of multiplication. + public static Vector2 operator *(float scale, Vector2 vec) + { + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Divides the specified instance by a scalar. + /// + /// Left operand + /// Right operand + /// Result of the division. + public static Vector2 operator /(Vector2 vec, float scale) + { + float mult = 1.0f / scale; + vec.X *= mult; + vec.Y *= mult; + return vec; + } + + /// + /// Compares the specified instances for equality. + /// + /// Left operand. + /// Right operand. + /// True if both instances are equal; false otherwise. + public static bool operator ==(Vector2 left, Vector2 right) + { + return left.Equals(right); + } + + /// + /// Compares the specified instances for inequality. + /// + /// Left operand. + /// Right operand. + /// True if both instances are not equal; false otherwise. + public static bool operator !=(Vector2 left, Vector2 right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Vector2. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1})", X, Y); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector2)) + return false; + + return this.Equals((Vector2)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector2 other) + { + return + X == other.X && + Y == other.Y; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector2d.cs b/src/MiniTK/Math/Vector2d.cs new file mode 100644 index 0000000..b631a63 --- /dev/null +++ b/src/MiniTK/Math/Vector2d.cs @@ -0,0 +1,1010 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. +*/ +#endregion + +using System; +using System.Runtime.InteropServices; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// Represents a 2D vector using two double-precision floating-point numbers. + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector2d : IEquatable + { + #region Fields + + /// The X coordinate of this instance. + public double X; + + /// The Y coordinate of this instance. + public double Y; + + /// + /// Defines a unit-length Vector2d that points towards the X-axis. + /// + public static Vector2d UnitX = new Vector2d(1, 0); + + /// + /// Defines a unit-length Vector2d that points towards the Y-axis. + /// + public static Vector2d UnitY = new Vector2d(0, 1); + + /// + /// Defines a zero-length Vector2d. + /// + public static Vector2d Zero = new Vector2d(0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector2d One = new Vector2d(1, 1); + + /// + /// Defines the size of the Vector2d struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2d()); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector2d(double value) + { + X = value; + Y = value; + } + + /// Constructs left vector with the given coordinates. + /// The X coordinate. + /// The Y coordinate. + public Vector2d(double x, double y) + { + this.X = x; + this.Y = y; + } + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector2d right) + { + this.X += right.X; + this.Y += right.Y; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector2d right) + { + this.X += right.X; + this.Y += right.Y; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector2d right) + { + this.X -= right.X; + this.Y -= right.Y; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector2d right) + { + this.X -= right.X; + this.Y -= right.Y; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(double f) + { + this.X *= f; + this.Y *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(double f) + { + double mult = 1.0 / f; + this.X *= mult; + this.Y *= mult; + } + + #endregion public void Div() + + #region public double Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + public double Length + { + get + { + return System.Math.Sqrt(X * X + Y * Y); + } + } + + #endregion + + #region public double LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + public double LengthSquared + { + get + { + return X * X + Y * Y; + } + } + + #endregion + + #region public Vector2d PerpendicularRight + + /// + /// Gets the perpendicular vector on the right side of this vector. + /// + public Vector2d PerpendicularRight + { + get + { + return new Vector2d(Y, -X); + } + } + + #endregion + + #region public Vector2d PerpendicularLeft + + /// + /// Gets the perpendicular vector on the left side of this vector. + /// + public Vector2d PerpendicularLeft + { + get + { + return new Vector2d(-Y, X); + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector2 to unit length. + /// + public void Normalize() + { + double scale = 1.0 / Length; + X *= scale; + Y *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector2 by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(double sx, double sy) + { + X *= sx; + Y *= sy; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector2d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector2d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static Vector2d Sub(Vector2d a, Vector2d b) + { + a.X -= b.X; + a.Y -= b.Y; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static void Sub(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static Vector2d Mult(Vector2d a, double d) + { + a.X *= d; + a.Y *= d; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static void Mult(ref Vector2d a, double d, out Vector2d result) + { + result.X = a.X * d; + result.Y = a.Y * d; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static Vector2d Div(Vector2d a, double d) + { + double mult = 1.0 / d; + a.X *= mult; + a.Y *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static void Div(ref Vector2d a, double d, out Vector2d result) + { + double mult = 1.0 / d; + result.X = a.X * mult; + result.Y = a.Y * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector2d Add(Vector2d a, Vector2d b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result = new Vector2d(a.X + b.X, a.Y + b.Y); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector2d Subtract(Vector2d a, Vector2d b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result = new Vector2d(a.X - b.X, a.Y - b.Y); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2d Multiply(Vector2d vector, double scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector2d vector, double scale, out Vector2d result) + { + result = new Vector2d(vector.X * scale, vector.Y * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2d Multiply(Vector2d vector, Vector2d scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector2d vector, ref Vector2d scale, out Vector2d result) + { + result = new Vector2d(vector.X * scale.X, vector.Y * scale.Y); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2d Divide(Vector2d vector, double scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector2d vector, double scale, out Vector2d result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector2d Divide(Vector2d vector, Vector2d scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector2d vector, ref Vector2d scale, out Vector2d result) + { + result = new Vector2d(vector.X / scale.X, vector.Y / scale.Y); + } + + #endregion + + #region Min + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector2d Min(Vector2d a, Vector2d b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void Min(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + } + + #endregion + + #region Max + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector2d Max(Vector2d a, Vector2d b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void Max(ref Vector2d a, ref Vector2d b, out Vector2d result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector2d Clamp(Vector2d vec, Vector2d min, Vector2d max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector2d vec, ref Vector2d min, ref Vector2d max, out Vector2d result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector2d Normalize(Vector2d vec) + { + double scale = 1.0 / vec.Length; + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector2d vec, out Vector2d result) + { + double scale = 1.0 / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector2d NormalizeFast(Vector2d vec) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y); + vec.X *= scale; + vec.Y *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector2d vec, out Vector2d result) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static double Dot(Vector2d left, Vector2d right) + { + return left.X * right.X + left.Y * right.Y; + } + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector2d left, ref Vector2d right, out double result) + { + result = left.X * right.X + left.Y * right.Y; + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector2d Lerp(Vector2d a, Vector2d b, double blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector2d a, ref Vector2d b, double blend, out Vector2d result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector2d BaryCentric(Vector2d a, Vector2d b, Vector2d c, double u, double v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector2d a, ref Vector2d b, ref Vector2d c, double u, double v, out Vector2d result) + { + result = a; // copy + + Vector2d temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector2d Transform(Vector2d vec, Quaterniond quat) + { + Vector2d result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector2d vec, ref Quaterniond quat, out Vector2d result) + { + Quaterniond v = new Quaterniond(vec.X, vec.Y, 0, 0), i, t; + Quaterniond.Invert(ref quat, out i); + Quaterniond.Multiply(ref quat, ref v, out t); + Quaterniond.Multiply(ref t, ref i, out v); + + result = new Vector2d(v.X, v.Y); + } + + #endregion + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static Vector2d operator +(Vector2d left, Vector2d right) + { + left.X += right.X; + left.Y += right.Y; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The left instance. + /// The right instance. + /// The result of the operation. + public static Vector2d operator -(Vector2d left, Vector2d right) + { + left.X -= right.X; + left.Y -= right.Y; + return left; + } + + /// + /// Negates an instance. + /// + /// The instance. + /// The result of the operation. + public static Vector2d operator -(Vector2d vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the operation. + public static Vector2d operator *(Vector2d vec, double f) + { + vec.X *= f; + vec.Y *= f; + return vec; + } + + /// + /// Multiply an instance by a scalar. + /// + /// The scalar. + /// The instance. + /// The result of the operation. + public static Vector2d operator *(double f, Vector2d vec) + { + vec.X *= f; + vec.Y *= f; + return vec; + } + + /// + /// Divides an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the operation. + public static Vector2d operator /(Vector2d vec, double f) + { + double mult = 1.0 / f; + vec.X *= mult; + vec.Y *= mult; + return vec; + } + + /// + /// Compares two instances for equality. + /// + /// The left instance. + /// The right instance. + /// True, if both instances are equal; false otherwise. + public static bool operator ==(Vector2d left, Vector2d right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for ienquality. + /// + /// The left instance. + /// The right instance. + /// True, if the instances are not equal; false otherwise. + public static bool operator !=(Vector2d left, Vector2d right) + { + return !left.Equals(right); + } + + /// Converts OpenTK.Vector2 to OpenTK.Vector2d. + /// The Vector2 to convert. + /// The resulting Vector2d. + public static explicit operator Vector2d(Vector2 v2) + { + return new Vector2d(v2.X, v2.Y); + } + + /// Converts OpenTK.Vector2d to OpenTK.Vector2. + /// The Vector2d to convert. + /// The resulting Vector2. + public static explicit operator Vector2(Vector2d v2d) + { + return new Vector2((float)v2d.X, (float)v2d.Y); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current instance. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1})", X, Y); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector2d)) + return false; + + return this.Equals((Vector2d)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector2d other) + { + return + X == other.X && + Y == other.Y; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector2h.cs b/src/MiniTK/Math/Vector2h.cs new file mode 100644 index 0000000..58c2775 --- /dev/null +++ b/src/MiniTK/Math/Vector2h.cs @@ -0,0 +1,362 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + + /// 2-component Vector of the Half type. Occupies 4 Byte total. + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct Vector2h : ISerializable, IEquatable + { + #region Fields + + /// The X component of the Half2. + public Half X; + + /// The Y component of the Half2. + public Half Y; + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector2h(Half value) + { + X = value; + Y = value; + } + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector2h(Single value) + { + X = new Half(value); + Y = new Half(value); + } + + /// + /// The new Half2 instance will avoid conversion and copy directly from the Half parameters. + /// + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + public Vector2h(Half x, Half y) + { + X = x; + Y = y; + } + + /// + /// The new Half2 instance will convert the 2 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + public Vector2h(Single x, Single y) + { + X = new Half(x); + Y = new Half(y); + } + + /// + /// The new Half2 instance will convert the 2 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector2h(Single x, Single y, bool throwOnError) + { + X = new Half(x, throwOnError); + Y = new Half(y, throwOnError); + } + + /// + /// The new Half2 instance will convert the Vector2 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2 + [CLSCompliant(false)] + public Vector2h(Vector2 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + } + + /// + /// The new Half2 instance will convert the Vector2 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2 + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector2h(Vector2 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + } + + /// + /// The new Half2 instance will convert the Vector2 into 16-bit half-precision floating-point. + /// This is the fastest constructor. + /// + /// OpenTK.Vector2 + public Vector2h(ref Vector2 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + } + + /// + /// The new Half2 instance will convert the Vector2 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2 + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector2h(ref Vector2 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + } + + /// + /// The new Half2 instance will convert the Vector2d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2d + public Vector2h(Vector2d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + } + + /// + /// The new Half2 instance will convert the Vector2d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2d + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector2h(Vector2d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + } + + /// + /// The new Half2 instance will convert the Vector2d into 16-bit half-precision floating-point. + /// This is the faster constructor. + /// + /// OpenTK.Vector2d + [CLSCompliant(false)] + public Vector2h(ref Vector2d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + } + + /// + /// The new Half2 instance will convert the Vector2d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector2d + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector2h(ref Vector2d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + } + + #endregion Constructors + + #region Half -> Single + + /// + /// Returns this Half2 instance's contents as Vector2. + /// + /// OpenTK.Vector2 + public Vector2 ToVector2() + { + return new Vector2(X, Y); + } + + /// + /// Returns this Half2 instance's contents as Vector2d. + /// + public Vector2d ToVector2d() + { + return new Vector2d(X, Y); + } + + #endregion Half -> Single + + #region Conversions + + /// Converts OpenTK.Vector2 to OpenTK.Half2. + /// The Vector2 to convert. + /// The resulting Half vector. + public static explicit operator Vector2h(Vector2 v) + { + return new Vector2h(v); + } + + /// Converts OpenTK.Vector2d to OpenTK.Half2. + /// The Vector2d to convert. + /// The resulting Half vector. + public static explicit operator Vector2h(Vector2d v) + { + return new Vector2h(v); + } + + /// Converts OpenTK.Half2 to OpenTK.Vector2. + /// The Half2 to convert. + /// The resulting Vector2. + public static explicit operator Vector2(Vector2h h) + { + return new Vector2(h.X, h.Y); + } + + /// Converts OpenTK.Half2 to OpenTK.Vector2d. + /// The Half2 to convert. + /// The resulting Vector2d. + public static explicit operator Vector2d(Vector2h h) + { + return new Vector2d(h.X, h.Y); + } + + #endregion Conversions + + #region Constants + + /// The size in bytes for an instance of the Half2 struct is 4. + public static readonly int SizeInBytes = 4; + + #endregion Constants + + #region ISerializable + + /// Constructor used by ISerializable to deserialize the object. + /// + /// + public Vector2h(SerializationInfo info, StreamingContext context) + { + this.X = (Half)info.GetValue("X", typeof(Half)); + this.Y = (Half)info.GetValue("Y", typeof(Half)); + } + + /// Used by ISerialize to serialize the object. + /// + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("X", this.X); + info.AddValue("Y", this.Y); + } + + #endregion ISerializable + + #region Binary dump + + /// Updates the X and Y components of this instance by reading from a Stream. + /// A BinaryReader instance associated with an open Stream. + public void FromBinaryStream(BinaryReader bin) + { + X.FromBinaryStream(bin); + Y.FromBinaryStream(bin); + } + + /// Writes the X and Y components of this instance into a Stream. + /// A BinaryWriter instance associated with an open Stream. + public void ToBinaryStream(BinaryWriter bin) + { + X.ToBinaryStream(bin); + Y.ToBinaryStream(bin); + } + + #endregion Binary dump + + #region IEquatable Members + + /// Returns a value indicating whether this instance is equal to a specified OpenTK.Half2 vector. + /// OpenTK.Half2 to compare to this instance.. + /// True, if other is equal to this instance; false otherwise. + public bool Equals(Vector2h other) + { + return (this.X.Equals(other.X) && this.Y.Equals(other.Y)); + } + + #endregion + + #region ToString() + + /// Returns a string that contains this Half2's numbers in human-legible form. + public override string ToString() + { + return String.Format("({0}, {1})", X.ToString(), Y.ToString()); + } + + #endregion ToString() + + #region BitConverter + + /// Returns the Half2 as an array of bytes. + /// The Half2 to convert. + /// The input as byte array. + public static byte[] GetBytes(Vector2h h) + { + byte[] result = new byte[SizeInBytes]; + + byte[] temp = Half.GetBytes(h.X); + result[0] = temp[0]; + result[1] = temp[1]; + temp = Half.GetBytes(h.Y); + result[2] = temp[0]; + result[3] = temp[1]; + + return result; + } + + /// Converts an array of bytes into Half2. + /// A Half2 in it's byte[] representation. + /// The starting position within value. + /// A new Half2 instance. + public static Vector2h FromBytes(byte[] value, int startIndex) + { + Vector2h h2 = new Vector2h(); + h2.X = Half.FromBytes(value, startIndex); + h2.Y = Half.FromBytes(value, startIndex + 2); + return h2; + } + + #endregion BitConverter + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector3.cs b/src/MiniTK/Math/Vector3.cs new file mode 100644 index 0000000..a856a4a --- /dev/null +++ b/src/MiniTK/Math/Vector3.cs @@ -0,0 +1,1387 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// Represents a 3D vector using three single-precision floating-point numbers. + /// + /// + /// The Vector3 structure is suitable for interoperation with unmanaged code requiring three consecutive floats. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector3 : IEquatable + { + #region Fields + + /// + /// The X component of the Vector3. + /// + public float X; + + /// + /// The Y component of the Vector3. + /// + public float Y; + + /// + /// The Z component of the Vector3. + /// + public float Z; + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector3(float value) + { + X = value; + Y = value; + Z = value; + } + + /// + /// Constructs a new Vector3. + /// + /// The x component of the Vector3. + /// The y component of the Vector3. + /// The z component of the Vector3. + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + /// + /// Constructs a new Vector3 from the given Vector2. + /// + /// The Vector2 to copy components from. + public Vector3(Vector2 v) + { + X = v.X; + Y = v.Y; + Z = 0.0f; + } + + /// + /// Constructs a new Vector3 from the given Vector3. + /// + /// The Vector3 to copy components from. + public Vector3(Vector3 v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + } + + /// + /// Constructs a new Vector3 from the given Vector4. + /// + /// The Vector4 to copy components from. + public Vector3(Vector4 v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + } + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector3 right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector3 right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector3 right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector3 right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(float f) + { + this.X *= f; + this.Y *= f; + this.Z *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(float f) + { + float mult = 1.0f / f; + this.X *= mult; + this.Y *= mult; + this.Z *= mult; + } + + #endregion public void Div() + + #region public float Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + /// + public float Length + { + get + { + return (float)System.Math.Sqrt(X * X + Y * Y + Z * Z); + } + } + + #endregion + + #region public float LengthFast + + /// + /// Gets an approximation of the vector length (magnitude). + /// + /// + /// This property uses an approximation of the square root function to calculate vector magnitude, with + /// an upper error bound of 0.001. + /// + /// + /// + public float LengthFast + { + get + { + return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); + } + } + + #endregion + + #region public float LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + /// + public float LengthSquared + { + get + { + return X * X + Y * Y + Z * Z; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector3 to unit length. + /// + public void Normalize() + { + float scale = 1.0f / this.Length; + X *= scale; + Y *= scale; + Z *= scale; + } + + #endregion + + #region public void NormalizeFast() + + /// + /// Scales the Vector3 to approximately unit length. + /// + public void NormalizeFast() + { + float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); + X *= scale; + Y *= scale; + Z *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector3 by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + /// The scale of the Z component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(float sx, float sy, float sz) + { + this.X = X * sx; + this.Y = Y * sy; + this.Z = Z * sz; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector3 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector3 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Fields + + /// + /// Defines a unit-length Vector3 that points towards the X-axis. + /// + public static readonly Vector3 UnitX = new Vector3(1, 0, 0); + + /// + /// Defines a unit-length Vector3 that points towards the Y-axis. + /// + public static readonly Vector3 UnitY = new Vector3(0, 1, 0); + + /// + /// /// Defines a unit-length Vector3 that points towards the Z-axis. + /// + public static readonly Vector3 UnitZ = new Vector3(0, 0, 1); + + /// + /// Defines a zero-length Vector3. + /// + public static readonly Vector3 Zero = new Vector3(0, 0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector3 One = new Vector3(1, 1, 1); + + /// + /// Defines the size of the Vector3 struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector3()); + + #endregion + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static Vector3 Sub(Vector3 a, Vector3 b) + { + a.X -= b.X; + a.Y -= b.Y; + a.Z -= b.Z; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static void Sub(ref Vector3 a, ref Vector3 b, out Vector3 result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static Vector3 Mult(Vector3 a, float f) + { + a.X *= f; + a.Y *= f; + a.Z *= f; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static void Mult(ref Vector3 a, float f, out Vector3 result) + { + result.X = a.X * f; + result.Y = a.Y * f; + result.Z = a.Z * f; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static Vector3 Div(Vector3 a, float f) + { + float mult = 1.0f / f; + a.X *= mult; + a.Y *= mult; + a.Z *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static void Div(ref Vector3 a, float f, out Vector3 result) + { + float mult = 1.0f / f; + result.X = a.X * mult; + result.Y = a.Y * mult; + result.Z = a.Z * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector3 Add(Vector3 a, Vector3 b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector3 a, ref Vector3 b, out Vector3 result) + { + result = new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector3 Subtract(Vector3 a, Vector3 b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector3 a, ref Vector3 b, out Vector3 result) + { + result = new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3 Multiply(Vector3 vector, float scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector3 vector, float scale, out Vector3 result) + { + result = new Vector3(vector.X * scale, vector.Y * scale, vector.Z * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3 Multiply(Vector3 vector, Vector3 scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector3 vector, ref Vector3 scale, out Vector3 result) + { + result = new Vector3(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3 Divide(Vector3 vector, float scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector3 vector, float scale, out Vector3 result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3 Divide(Vector3 vector, Vector3 scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector3 vector, ref Vector3 scale, out Vector3 result) + { + result = new Vector3(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z); + } + + #endregion + + #region ComponentMin + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector3 ComponentMin(Vector3 a, Vector3 b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector3 a, ref Vector3 b, out Vector3 result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + } + + #endregion + + #region ComponentMax + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector3 ComponentMax(Vector3 a, Vector3 b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector3 a, ref Vector3 b, out Vector3 result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + } + + #endregion + + #region Min + + /// + /// Returns the Vector3 with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector3 Min(Vector3 left, Vector3 right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region Max + + /// + /// Returns the Vector3 with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector3 Max(Vector3 left, Vector3 right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector3 Clamp(Vector3 vec, Vector3 min, Vector3 max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + vec.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector3 vec, ref Vector3 min, ref Vector3 max, out Vector3 result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + result.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector3 Normalize(Vector3 vec) + { + float scale = 1.0f / vec.Length; + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector3 vec, out Vector3 result) + { + float scale = 1.0f / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector3 NormalizeFast(Vector3 vec) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z); + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector3 vec, out Vector3 result) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static float Dot(Vector3 left, Vector3 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector3 left, ref Vector3 right, out float result) + { + result = left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + #endregion + + #region Cross + + /// + /// Caclulate the cross (vector) product of two vectors + /// + /// First operand + /// Second operand + /// The cross product of the two inputs + public static Vector3 Cross(Vector3 left, Vector3 right) + { + Vector3 result; + Cross(ref left, ref right, out result); + return result; + } + + /// + /// Caclulate the cross (vector) product of two vectors + /// + /// First operand + /// Second operand + /// The cross product of the two inputs + /// The cross product of the two inputs + public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result) + { + result = new Vector3(left.Y * right.Z - left.Z * right.Y, + left.Z * right.X - left.X * right.Z, + left.X * right.Y - left.Y * right.X); + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector3 Lerp(Vector3 a, Vector3 b, float blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + a.Z = blend * (b.Z - a.Z) + a.Z; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector3 a, ref Vector3 b, float blend, out Vector3 result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + result.Z = blend * (b.Z - a.Z) + a.Z; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector3 BaryCentric(Vector3 a, Vector3 b, Vector3 c, float u, float v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector3 a, ref Vector3 b, ref Vector3 c, float u, float v, out Vector3 result) + { + result = a; // copy + + Vector3 temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. + /// + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3 TransformVector(Vector3 vec, Matrix4 mat) + { + Vector3 v; + v.X = Vector3.Dot(vec, new Vector3(mat.Column0)); + v.Y = Vector3.Dot(vec, new Vector3(mat.Column1)); + v.Z = Vector3.Dot(vec, new Vector3(mat.Column2)); + return v; + } + + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. + /// + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void TransformVector(ref Vector3 vec, ref Matrix4 mat, out Vector3 result) + { + result.X = vec.X * mat.Row0.X + + vec.Y * mat.Row1.X + + vec.Z * mat.Row2.X; + + result.Y = vec.X * mat.Row0.Y + + vec.Y * mat.Row1.Y + + vec.Z * mat.Row2.Y; + + result.Z = vec.X * mat.Row0.Z + + vec.Y * mat.Row1.Z + + vec.Z * mat.Row2.Z; + } + + /// Transform a Normal by the given Matrix + /// + /// This calculates the inverse of the given matrix, use TransformNormalInverse if you + /// already have the inverse to avoid this extra calculation + /// + /// The normal to transform + /// The desired transformation + /// The transformed normal + public static Vector3 TransformNormal(Vector3 norm, Matrix4 mat) + { + mat.Invert(); + return TransformNormalInverse(norm, mat); + } + + /// Transform a Normal by the given Matrix + /// + /// This calculates the inverse of the given matrix, use TransformNormalInverse if you + /// already have the inverse to avoid this extra calculation + /// + /// The normal to transform + /// The desired transformation + /// The transformed normal + public static void TransformNormal(ref Vector3 norm, ref Matrix4 mat, out Vector3 result) + { + Matrix4 Inverse = Matrix4.Invert(mat); + Vector3.TransformNormalInverse(ref norm, ref Inverse, out result); + } + + /// Transform a Normal by the (transpose of the) given Matrix + /// + /// This version doesn't calculate the inverse matrix. + /// Use this version if you already have the inverse of the desired transform to hand + /// + /// The normal to transform + /// The inverse of the desired transformation + /// The transformed normal + public static Vector3 TransformNormalInverse(Vector3 norm, Matrix4 invMat) + { + Vector3 n; + n.X = Vector3.Dot(norm, new Vector3(invMat.Row0)); + n.Y = Vector3.Dot(norm, new Vector3(invMat.Row1)); + n.Z = Vector3.Dot(norm, new Vector3(invMat.Row2)); + return n; + } + + /// Transform a Normal by the (transpose of the) given Matrix + /// + /// This version doesn't calculate the inverse matrix. + /// Use this version if you already have the inverse of the desired transform to hand + /// + /// The normal to transform + /// The inverse of the desired transformation + /// The transformed normal + public static void TransformNormalInverse(ref Vector3 norm, ref Matrix4 invMat, out Vector3 result) + { + result.X = norm.X * invMat.Row0.X + + norm.Y * invMat.Row0.Y + + norm.Z * invMat.Row0.Z; + + result.Y = norm.X * invMat.Row1.X + + norm.Y * invMat.Row1.Y + + norm.Z * invMat.Row1.Z; + + result.Z = norm.X * invMat.Row2.X + + norm.Y * invMat.Row2.Y + + norm.Z * invMat.Row2.Z; + } + + /// Transform a Position by the given Matrix + /// The position to transform + /// The desired transformation + /// The transformed position + public static Vector3 TransformPosition(Vector3 pos, Matrix4 mat) + { + Vector3 p; + p.X = Vector3.Dot(pos, new Vector3(mat.Column0)) + mat.Row3.X; + p.Y = Vector3.Dot(pos, new Vector3(mat.Column1)) + mat.Row3.Y; + p.Z = Vector3.Dot(pos, new Vector3(mat.Column2)) + mat.Row3.Z; + return p; + } + + /// Transform a Position by the given Matrix + /// The position to transform + /// The desired transformation + /// The transformed position + public static void TransformPosition(ref Vector3 pos, ref Matrix4 mat, out Vector3 result) + { + result.X = pos.X * mat.Row0.X + + pos.Y * mat.Row1.X + + pos.Z * mat.Row2.X + + mat.Row3.X; + + result.Y = pos.X * mat.Row0.Y + + pos.Y * mat.Row1.Y + + pos.Z * mat.Row2.Y + + mat.Row3.Y; + + result.Z = pos.X * mat.Row0.Z + + pos.Y * mat.Row1.Z + + pos.Z * mat.Row2.Z + + mat.Row3.Z; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3 Transform(Vector3 vec, Matrix4 mat) + { + Vector3 result; + Transform(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void Transform(ref Vector3 vec, ref Matrix4 mat, out Vector3 result) + { + Vector4 v4 = new Vector4(vec.X, vec.Y, vec.Z, 1.0f); + Vector4.Transform(ref v4, ref mat, out v4); + result = v4.Xyz; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector3 Transform(Vector3 vec, Quaternion quat) + { + Vector3 result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector3 vec, ref Quaternion quat, out Vector3 result) + { + // Since vec.W == 0, we can optimize quat * vec * quat^-1 as follows: + // vec + 2.0 * cross(quat.xyz, cross(quat.xyz, vec) + quat.w * vec) + Vector3 xyz = quat.Xyz, temp, temp2; + Vector3.Cross(ref xyz, ref vec, out temp); + Vector3.Multiply(ref vec, quat.W, out temp2); + Vector3.Add(ref temp, ref temp2, out temp); + Vector3.Cross(ref xyz, ref temp, out temp); + Vector3.Multiply(ref temp, 2, out temp); + Vector3.Add(ref vec, ref temp, out result); + } + + /// Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3 + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3 TransformPerspective(Vector3 vec, Matrix4 mat) + { + Vector3 result; + TransformPerspective(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3 + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void TransformPerspective(ref Vector3 vec, ref Matrix4 mat, out Vector3 result) + { + Vector4 v = new Vector4(vec, 1); + Vector4.Transform(ref v, ref mat, out v); + result.X = v.X / v.W; + result.Y = v.Y / v.W; + result.Z = v.Z / v.W; + } + + #endregion + + #region CalculateAngle + + /// + /// Calculates the angle (in radians) between two vectors. + /// + /// The first vector. + /// The second vector. + /// Angle (in radians) between the vectors. + /// Note that the returned angle is never bigger than the constant Pi. + public static float CalculateAngle(Vector3 first, Vector3 second) + { + return (float)System.Math.Acos((Vector3.Dot(first, second)) / (first.Length * second.Length)); + } + + /// Calculates the angle (in radians) between two vectors. + /// The first vector. + /// The second vector. + /// Angle (in radians) between the vectors. + /// Note that the returned angle is never bigger than the constant Pi. + public static void CalculateAngle(ref Vector3 first, ref Vector3 second, out float result) + { + float temp; + Vector3.Dot(ref first, ref second, out temp); + result = (float)System.Math.Acos(temp / (first.Length * second.Length)); + } + + #endregion + + #endregion + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2 with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2 Xy { get { return new Vector2(X, Y); } set { X = value.X; Y = value.Y; } } + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector3 operator +(Vector3 left, Vector3 right) + { + left.X += right.X; + left.Y += right.Y; + left.Z += right.Z; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector3 operator -(Vector3 left, Vector3 right) + { + left.X -= right.X; + left.Y -= right.Y; + left.Z -= right.Z; + return left; + } + + /// + /// Negates an instance. + /// + /// The instance. + /// The result of the calculation. + public static Vector3 operator -(Vector3 vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + vec.Z = -vec.Z; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector3 operator *(Vector3 vec, float scale) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The scalar. + /// The instance. + /// The result of the calculation. + public static Vector3 operator *(float scale, Vector3 vec) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Divides an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector3 operator /(Vector3 vec, float scale) + { + float mult = 1.0f / scale; + vec.X *= mult; + vec.Y *= mult; + vec.Z *= mult; + return vec; + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Vector3 left, Vector3 right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equa lright; false otherwise. + public static bool operator !=(Vector3 left, Vector3 right) + { + return !left.Equals(right); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Vector3. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1}, {2})", X, Y, Z); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector3)) + return false; + + return this.Equals((Vector3)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector3 other) + { + return + X == other.X && + Y == other.Y && + Z == other.Z; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector3d.cs b/src/MiniTK/Math/Vector3d.cs new file mode 100644 index 0000000..41530ad --- /dev/null +++ b/src/MiniTK/Math/Vector3d.cs @@ -0,0 +1,1400 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. +*/ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// Represents a 3D vector using three double-precision floating-point numbers. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector3d : IEquatable + { + #region Fields + + /// + /// The X component of the Vector3. + /// + public double X; + + /// + /// The Y component of the Vector3. + /// + public double Y; + + /// + /// The Z component of the Vector3. + /// + public double Z; + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector3d(double value) + { + X = value; + Y = value; + Z = value; + } + + /// + /// Constructs a new Vector3. + /// + /// The x component of the Vector3. + /// The y component of the Vector3. + /// The z component of the Vector3. + public Vector3d(double x, double y, double z) + { + X = x; + Y = y; + Z = z; + } + + /// + /// Constructs a new instance from the given Vector2d. + /// + /// The Vector2d to copy components from. + public Vector3d(Vector2d v) + { + X = v.X; + Y = v.Y; + Z = 0.0f; + } + + /// + /// Constructs a new instance from the given Vector3d. + /// + /// The Vector3d to copy components from. + public Vector3d(Vector3d v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + } + + /// + /// Constructs a new instance from the given Vector4d. + /// + /// The Vector4d to copy components from. + public Vector3d(Vector4d v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + } + + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector3d right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector3d right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector3d right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector3d right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(double f) + { + this.X *= f; + this.Y *= f; + this.Z *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(double f) + { + double mult = 1.0 / f; + this.X *= mult; + this.Y *= mult; + this.Z *= mult; + } + + #endregion public void Div() + + #region public double Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + /// + public double Length + { + get + { + return System.Math.Sqrt(X * X + Y * Y + Z * Z); + } + } + + #endregion + + #region public double LengthFast + + /// + /// Gets an approximation of the vector length (magnitude). + /// + /// + /// This property uses an approximation of the square root function to calculate vector magnitude, with + /// an upper error bound of 0.001. + /// + /// + /// + public double LengthFast + { + get + { + return 1.0 / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); + } + } + + #endregion + + #region public double LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + /// + public double LengthSquared + { + get + { + return X * X + Y * Y + Z * Z; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector3d to unit length. + /// + public void Normalize() + { + double scale = 1.0 / this.Length; + X *= scale; + Y *= scale; + Z *= scale; + } + + #endregion + + #region public void NormalizeFast() + + /// + /// Scales the Vector3d to approximately unit length. + /// + public void NormalizeFast() + { + double scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z); + X *= scale; + Y *= scale; + Z *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector3d by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + /// The scale of the Z component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(double sx, double sy, double sz) + { + this.X = X * sx; + this.Y = Y * sy; + this.Z = Z * sz; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector3d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector3d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Fields + + /// + /// Defines a unit-length Vector3d that points towards the X-axis. + /// + public static readonly Vector3d UnitX = new Vector3d(1, 0, 0); + + /// + /// Defines a unit-length Vector3d that points towards the Y-axis. + /// + public static readonly Vector3d UnitY = new Vector3d(0, 1, 0); + + /// + /// /// Defines a unit-length Vector3d that points towards the Z-axis. + /// + public static readonly Vector3d UnitZ = new Vector3d(0, 0, 1); + + /// + /// Defines a zero-length Vector3. + /// + public static readonly Vector3d Zero = new Vector3d(0, 0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector3d One = new Vector3d(1, 1, 1); + + /// + /// Defines the size of the Vector3d struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector3d()); + + #endregion + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static Vector3d Sub(Vector3d a, Vector3d b) + { + a.X -= b.X; + a.Y -= b.Y; + a.Z -= b.Z; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static void Sub(ref Vector3d a, ref Vector3d b, out Vector3d result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static Vector3d Mult(Vector3d a, double f) + { + a.X *= f; + a.Y *= f; + a.Z *= f; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static void Mult(ref Vector3d a, double f, out Vector3d result) + { + result.X = a.X * f; + result.Y = a.Y * f; + result.Z = a.Z * f; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static Vector3d Div(Vector3d a, double f) + { + double mult = 1.0 / f; + a.X *= mult; + a.Y *= mult; + a.Z *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static void Div(ref Vector3d a, double f, out Vector3d result) + { + double mult = 1.0 / f; + result.X = a.X * mult; + result.Y = a.Y * mult; + result.Z = a.Z * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector3d Add(Vector3d a, Vector3d b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector3d a, ref Vector3d b, out Vector3d result) + { + result = new Vector3d(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector3d Subtract(Vector3d a, Vector3d b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector3d a, ref Vector3d b, out Vector3d result) + { + result = new Vector3d(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3d Multiply(Vector3d vector, double scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector3d vector, double scale, out Vector3d result) + { + result = new Vector3d(vector.X * scale, vector.Y * scale, vector.Z * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3d Multiply(Vector3d vector, Vector3d scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector3d vector, ref Vector3d scale, out Vector3d result) + { + result = new Vector3d(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3d Divide(Vector3d vector, double scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector3d vector, double scale, out Vector3d result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector3d Divide(Vector3d vector, Vector3d scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector3d vector, ref Vector3d scale, out Vector3d result) + { + result = new Vector3d(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z); + } + + #endregion + + #region ComponentMin + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector3d ComponentMin(Vector3d a, Vector3d b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void ComponentMin(ref Vector3d a, ref Vector3d b, out Vector3d result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + } + + #endregion + + #region ComponentMax + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector3d ComponentMax(Vector3d a, Vector3d b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void ComponentMax(ref Vector3d a, ref Vector3d b, out Vector3d result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + } + + #endregion + + #region Min + + /// + /// Returns the Vector3d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector3d Min(Vector3d left, Vector3d right) + { + return left.LengthSquared < right.LengthSquared ? left : right; + } + + #endregion + + #region Max + + /// + /// Returns the Vector3d with the minimum magnitude + /// + /// Left operand + /// Right operand + /// The minimum Vector3 + public static Vector3d Max(Vector3d left, Vector3d right) + { + return left.LengthSquared >= right.LengthSquared ? left : right; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector3d Clamp(Vector3d vec, Vector3d min, Vector3d max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + vec.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector3d vec, ref Vector3d min, ref Vector3d max, out Vector3d result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + result.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector3d Normalize(Vector3d vec) + { + double scale = 1.0 / vec.Length; + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector3d vec, out Vector3d result) + { + double scale = 1.0 / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector3d NormalizeFast(Vector3d vec) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z); + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector3d vec, out Vector3d result) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static double Dot(Vector3d left, Vector3d right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + /// + /// Calculate the dot (scalar) product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector3d left, ref Vector3d right, out double result) + { + result = left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + #endregion + + #region Cross + + /// + /// Caclulate the cross (vector) product of two vectors + /// + /// First operand + /// Second operand + /// The cross product of the two inputs + public static Vector3d Cross(Vector3d left, Vector3d right) + { + Vector3d result; + Cross(ref left, ref right, out result); + return result; + } + + /// + /// Caclulate the cross (vector) product of two vectors + /// + /// First operand + /// Second operand + /// The cross product of the two inputs + /// The cross product of the two inputs + public static void Cross(ref Vector3d left, ref Vector3d right, out Vector3d result) + { + result = new Vector3d(left.Y * right.Z - left.Z * right.Y, + left.Z * right.X - left.X * right.Z, + left.X * right.Y - left.Y * right.X); + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector3d Lerp(Vector3d a, Vector3d b, double blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + a.Z = blend * (b.Z - a.Z) + a.Z; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector3d a, ref Vector3d b, double blend, out Vector3d result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + result.Z = blend * (b.Z - a.Z) + a.Z; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector3d BaryCentric(Vector3d a, Vector3d b, Vector3d c, double u, double v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector3d a, ref Vector3d b, ref Vector3d c, double u, double v, out Vector3d result) + { + result = a; // copy + + Vector3d temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. + /// + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3d TransformVector(Vector3d vec, Matrix4d mat) + { + return new Vector3d( + Vector3d.Dot(vec, new Vector3d(mat.Column0)), + Vector3d.Dot(vec, new Vector3d(mat.Column1)), + Vector3d.Dot(vec, new Vector3d(mat.Column2))); + } + + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. + /// + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void TransformVector(ref Vector3d vec, ref Matrix4d mat, out Vector3d result) + { + result.X = vec.X * mat.Row0.X + + vec.Y * mat.Row1.X + + vec.Z * mat.Row2.X; + + result.Y = vec.X * mat.Row0.Y + + vec.Y * mat.Row1.Y + + vec.Z * mat.Row2.Y; + + result.Z = vec.X * mat.Row0.Z + + vec.Y * mat.Row1.Z + + vec.Z * mat.Row2.Z; + } + + /// Transform a Normal by the given Matrix + /// + /// This calculates the inverse of the given matrix, use TransformNormalInverse if you + /// already have the inverse to avoid this extra calculation + /// + /// The normal to transform + /// The desired transformation + /// The transformed normal + public static Vector3d TransformNormal(Vector3d norm, Matrix4d mat) + { + mat.Invert(); + return TransformNormalInverse(norm, mat); + } + + /// Transform a Normal by the given Matrix + /// + /// This calculates the inverse of the given matrix, use TransformNormalInverse if you + /// already have the inverse to avoid this extra calculation + /// + /// The normal to transform + /// The desired transformation + /// The transformed normal + public static void TransformNormal(ref Vector3d norm, ref Matrix4d mat, out Vector3d result) + { + Matrix4d Inverse = Matrix4d.Invert(mat); + Vector3d.TransformNormalInverse(ref norm, ref Inverse, out result); + } + + /// Transform a Normal by the (transpose of the) given Matrix + /// + /// This version doesn't calculate the inverse matrix. + /// Use this version if you already have the inverse of the desired transform to hand + /// + /// The normal to transform + /// The inverse of the desired transformation + /// The transformed normal + public static Vector3d TransformNormalInverse(Vector3d norm, Matrix4d invMat) + { + return new Vector3d( + Vector3d.Dot(norm, new Vector3d(invMat.Row0)), + Vector3d.Dot(norm, new Vector3d(invMat.Row1)), + Vector3d.Dot(norm, new Vector3d(invMat.Row2))); + } + + /// Transform a Normal by the (transpose of the) given Matrix + /// + /// This version doesn't calculate the inverse matrix. + /// Use this version if you already have the inverse of the desired transform to hand + /// + /// The normal to transform + /// The inverse of the desired transformation + /// The transformed normal + public static void TransformNormalInverse(ref Vector3d norm, ref Matrix4d invMat, out Vector3d result) + { + result.X = norm.X * invMat.Row0.X + + norm.Y * invMat.Row0.Y + + norm.Z * invMat.Row0.Z; + + result.Y = norm.X * invMat.Row1.X + + norm.Y * invMat.Row1.Y + + norm.Z * invMat.Row1.Z; + + result.Z = norm.X * invMat.Row2.X + + norm.Y * invMat.Row2.Y + + norm.Z * invMat.Row2.Z; + } + + /// Transform a Position by the given Matrix + /// The position to transform + /// The desired transformation + /// The transformed position + public static Vector3d TransformPosition(Vector3d pos, Matrix4d mat) + { + return new Vector3d( + Vector3d.Dot(pos, new Vector3d(mat.Column0)) + mat.Row3.X, + Vector3d.Dot(pos, new Vector3d(mat.Column1)) + mat.Row3.Y, + Vector3d.Dot(pos, new Vector3d(mat.Column2)) + mat.Row3.Z); + } + + /// Transform a Position by the given Matrix + /// The position to transform + /// The desired transformation + /// The transformed position + public static void TransformPosition(ref Vector3d pos, ref Matrix4d mat, out Vector3d result) + { + result.X = pos.X * mat.Row0.X + + pos.Y * mat.Row1.X + + pos.Z * mat.Row2.X + + mat.Row3.X; + + result.Y = pos.X * mat.Row0.Y + + pos.Y * mat.Row1.Y + + pos.Z * mat.Row2.Y + + mat.Row3.Y; + + result.Z = pos.X * mat.Row0.Z + + pos.Y * mat.Row1.Z + + pos.Z * mat.Row2.Z + + mat.Row3.Z; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3d Transform(Vector3d vec, Matrix4d mat) + { + Vector3d result; + Transform(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void Transform(ref Vector3d vec, ref Matrix4d mat, out Vector3d result) + { + Vector4d v4 = new Vector4d(vec.X, vec.Y, vec.Z, 1.0); + Vector4d.Transform(ref v4, ref mat, out v4); + result = v4.Xyz; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector3d Transform(Vector3d vec, Quaterniond quat) + { + Vector3d result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector3d vec, ref Quaterniond quat, out Vector3d result) + { + // Since vec.W == 0, we can optimize quat * vec * quat^-1 as follows: + // vec + 2.0 * cross(quat.xyz, cross(quat.xyz, vec) + quat.w * vec) + Vector3d xyz = quat.Xyz, temp, temp2; + Vector3d.Cross(ref xyz, ref vec, out temp); + Vector3d.Multiply(ref vec, quat.W, out temp2); + Vector3d.Add(ref temp, ref temp2, out temp); + Vector3d.Cross(ref xyz, ref temp, out temp); + Vector3d.Multiply(ref temp, 2, out temp); + Vector3d.Add(ref vec, ref temp, out result); + } + + /// + /// Transform a Vector3d by the given Matrix, and project the resulting Vector4 back to a Vector3 + /// + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector3d TransformPerspective(Vector3d vec, Matrix4d mat) + { + Vector3d result; + TransformPerspective(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector3d by the given Matrix, and project the resulting Vector4d back to a Vector3d + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void TransformPerspective(ref Vector3d vec, ref Matrix4d mat, out Vector3d result) + { + Vector4d v = new Vector4d(vec, 1); + Vector4d.Transform(ref v, ref mat, out v); + result.X = v.X / v.W; + result.Y = v.Y / v.W; + result.Z = v.Z / v.W; + } + + #endregion + + #region CalculateAngle + + /// + /// Calculates the angle (in radians) between two vectors. + /// + /// The first vector. + /// The second vector. + /// Angle (in radians) between the vectors. + /// Note that the returned angle is never bigger than the constant Pi. + public static double CalculateAngle(Vector3d first, Vector3d second) + { + return System.Math.Acos((Vector3d.Dot(first, second)) / (first.Length * second.Length)); + } + + /// Calculates the angle (in radians) between two vectors. + /// The first vector. + /// The second vector. + /// Angle (in radians) between the vectors. + /// Note that the returned angle is never bigger than the constant Pi. + public static void CalculateAngle(ref Vector3d first, ref Vector3d second, out double result) + { + double temp; + Vector3d.Dot(ref first, ref second, out temp); + result = System.Math.Acos(temp / (first.Length * second.Length)); + } + + #endregion + + #endregion + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2d with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2d Xy { get { return new Vector2d(X, Y); } set { X = value.X; Y = value.Y; } } + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector3d operator +(Vector3d left, Vector3d right) + { + left.X += right.X; + left.Y += right.Y; + left.Z += right.Z; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector3d operator -(Vector3d left, Vector3d right) + { + left.X -= right.X; + left.Y -= right.Y; + left.Z -= right.Z; + return left; + } + + /// + /// Negates an instance. + /// + /// The instance. + /// The result of the calculation. + public static Vector3d operator -(Vector3d vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + vec.Z = -vec.Z; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector3d operator *(Vector3d vec, double scale) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The scalar. + /// The instance. + /// The result of the calculation. + public static Vector3d operator *(double scale, Vector3d vec) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + return vec; + } + + /// + /// Divides an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector3d operator /(Vector3d vec, double scale) + { + double mult = 1 / scale; + vec.X *= mult; + vec.Y *= mult; + vec.Z *= mult; + return vec; + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Vector3d left, Vector3d right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equa lright; false otherwise. + public static bool operator !=(Vector3d left, Vector3d right) + { + return !left.Equals(right); + } + + /// Converts OpenTK.Vector3 to OpenTK.Vector3d. + /// The Vector3 to convert. + /// The resulting Vector3d. + public static explicit operator Vector3d(Vector3 v3) + { + return new Vector3d(v3.X, v3.Y, v3.Z); + } + + /// Converts OpenTK.Vector3d to OpenTK.Vector3. + /// The Vector3d to convert. + /// The resulting Vector3. + public static explicit operator Vector3(Vector3d v3d) + { + return new Vector3((float)v3d.X, (float)v3d.Y, (float)v3d.Z); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Vector3. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1}, {2})", X, Y, Z); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector3d)) + return false; + + return this.Equals((Vector3d)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector3d other) + { + return + X == other.X && + Y == other.Y && + Z == other.Z; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector3h.cs b/src/MiniTK/Math/Vector3h.cs new file mode 100644 index 0000000..08f4dd4 --- /dev/null +++ b/src/MiniTK/Math/Vector3h.cs @@ -0,0 +1,409 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// 3-component Vector of the Half type. Occupies 6 Byte total. + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct Vector3h : ISerializable, IEquatable + { + #region Public Fields + + /// The X component of the Half3. + public Half X; + + /// The Y component of the Half3. + public Half Y; + + /// The Z component of the Half3. + public Half Z; + + #endregion Public Fields + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector3h(Half value) + { + X = value; + Y = value; + Z = value; + } + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector3h(Single value) + { + X = new Half(value); + Y = new Half(value); + Z = new Half(value); + } + + /// + /// The new Half3 instance will avoid conversion and copy directly from the Half parameters. + /// + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + public Vector3h(Half x, Half y, Half z) + { + this.X = x; + this.Y = y; + this.Z = z; + } + + /// + /// The new Half3 instance will convert the 3 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + public Vector3h(Single x, Single y, Single z) + { + X = new Half(x); + Y = new Half(y); + Z = new Half(z); + } + + /// + /// The new Half3 instance will convert the 3 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector3h(Single x, Single y, Single z, bool throwOnError) + { + X = new Half(x, throwOnError); + Y = new Half(y, throwOnError); + Z = new Half(z, throwOnError); + } + + /// + /// The new Half3 instance will convert the Vector3 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3 + [CLSCompliant(false)] + public Vector3h(Vector3 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + } + + /// + /// The new Half3 instance will convert the Vector3 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3 + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector3h(Vector3 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + } + + /// + /// The new Half3 instance will convert the Vector3 into 16-bit half-precision floating-point. + /// This is the fastest constructor. + /// + /// OpenTK.Vector3 + public Vector3h(ref Vector3 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + } + + /// + /// The new Half3 instance will convert the Vector3 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3 + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector3h(ref Vector3 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + } + + /// + /// The new Half3 instance will convert the Vector3d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3d + public Vector3h(Vector3d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + } + + /// + /// The new Half3 instance will convert the Vector3d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3d + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector3h(Vector3d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + } + + /// + /// The new Half3 instance will convert the Vector3d into 16-bit half-precision floating-point. + /// This is the faster constructor. + /// + /// OpenTK.Vector3d + [CLSCompliant(false)] + public Vector3h(ref Vector3d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + } + + /// + /// The new Half3 instance will convert the Vector3d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector3d + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector3h(ref Vector3d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + } + + #endregion Constructors + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2h with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2h Xy { get { return new Vector2h(X, Y); } set { X = value.X; Y = value.Y; } } + + #endregion + + #region Half -> Single + + /// + /// Returns this Half3 instance's contents as Vector3. + /// + /// OpenTK.Vector3 + public Vector3 ToVector3() + { + return new Vector3(X, Y, Z); + } + + /// + /// Returns this Half3 instance's contents as Vector3d. + /// + public Vector3d ToVector3d() + { + return new Vector3d(X, Y, Z); + } + + #endregion Half -> Single + + #region Conversions + + /// Converts OpenTK.Vector3 to OpenTK.Half3. + /// The Vector3 to convert. + /// The resulting Half vector. + public static explicit operator Vector3h(Vector3 v3f) + { + return new Vector3h(v3f); + } + + /// Converts OpenTK.Vector3d to OpenTK.Half3. + /// The Vector3d to convert. + /// The resulting Half vector. + public static explicit operator Vector3h(Vector3d v3d) + { + return new Vector3h(v3d); + } + + /// Converts OpenTK.Half3 to OpenTK.Vector3. + /// The Half3 to convert. + /// The resulting Vector3. + public static explicit operator Vector3(Vector3h h3) + { + Vector3 result = new Vector3(); + result.X = h3.X.ToSingle(); + result.Y = h3.Y.ToSingle(); + result.Z = h3.Z.ToSingle(); + return result; + } + + /// Converts OpenTK.Half3 to OpenTK.Vector3d. + /// The Half3 to convert. + /// The resulting Vector3d. + public static explicit operator Vector3d(Vector3h h3) + { + Vector3d result = new Vector3d(); + result.X = h3.X.ToSingle(); + result.Y = h3.Y.ToSingle(); + result.Z = h3.Z.ToSingle(); + return result; + } + + #endregion Conversions + + #region Constants + + /// The size in bytes for an instance of the Half3 struct is 6. + public static readonly int SizeInBytes = 6; + + #endregion Constants + + #region ISerializable + + /// Constructor used by ISerializable to deserialize the object. + /// + /// + public Vector3h(SerializationInfo info, StreamingContext context) + { + this.X = (Half)info.GetValue("X", typeof(Half)); + this.Y = (Half)info.GetValue("Y", typeof(Half)); + this.Z = (Half)info.GetValue("Z", typeof(Half)); + } + + /// Used by ISerialize to serialize the object. + /// + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("X", this.X); + info.AddValue("Y", this.Y); + info.AddValue("Z", this.Z); + } + + #endregion ISerializable + + #region Binary dump + + /// Updates the X,Y and Z components of this instance by reading from a Stream. + /// A BinaryReader instance associated with an open Stream. + public void FromBinaryStream(BinaryReader bin) + { + X.FromBinaryStream(bin); + Y.FromBinaryStream(bin); + Z.FromBinaryStream(bin); + } + + /// Writes the X,Y and Z components of this instance into a Stream. + /// A BinaryWriter instance associated with an open Stream. + public void ToBinaryStream(BinaryWriter bin) + { + X.ToBinaryStream(bin); + Y.ToBinaryStream(bin); + Z.ToBinaryStream(bin); + } + + #endregion Binary dump + + #region IEquatable Members + + /// Returns a value indicating whether this instance is equal to a specified OpenTK.Half3 vector. + /// OpenTK.Half3 to compare to this instance.. + /// True, if other is equal to this instance; false otherwise. + public bool Equals(Vector3h other) + { + return (this.X.Equals(other.X) && this.Y.Equals(other.Y) && this.Z.Equals(other.Z)); + } + + #endregion + + #region ToString() + + /// Returns a string that contains this Half3's numbers in human-legible form. + public override string ToString() + { + return String.Format("({0}, {1}, {2})", X.ToString(), Y.ToString(), Z.ToString()); + } + + #endregion ToString() + + #region BitConverter + + /// Returns the Half3 as an array of bytes. + /// The Half3 to convert. + /// The input as byte array. + public static byte[] GetBytes(Vector3h h) + { + byte[] result = new byte[SizeInBytes]; + + byte[] temp = Half.GetBytes(h.X); + result[0] = temp[0]; + result[1] = temp[1]; + temp = Half.GetBytes(h.Y); + result[2] = temp[0]; + result[3] = temp[1]; + temp = Half.GetBytes(h.Z); + result[4] = temp[0]; + result[5] = temp[1]; + + return result; + } + + /// Converts an array of bytes into Half3. + /// A Half3 in it's byte[] representation. + /// The starting position within value. + /// A new Half3 instance. + public static Vector3h FromBytes(byte[] value, int startIndex) + { + Vector3h h3 = new Vector3h(); + h3.X = Half.FromBytes(value, startIndex); + h3.Y = Half.FromBytes(value, startIndex + 2); + h3.Z = Half.FromBytes(value, startIndex + 4); + return h3; + } + + #endregion BitConverter + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector4.cs b/src/MiniTK/Math/Vector4.cs new file mode 100644 index 0000000..564a36a --- /dev/null +++ b/src/MiniTK/Math/Vector4.cs @@ -0,0 +1,1220 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// Represents a 4D vector using four single-precision floating-point numbers. + /// + /// The Vector4 structure is suitable for interoperation with unmanaged code requiring four consecutive floats. + /// + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector4 : IEquatable + { + #region Fields + + /// + /// The X component of the Vector4. + /// + public float X; + + /// + /// The Y component of the Vector4. + /// + public float Y; + + /// + /// The Z component of the Vector4. + /// + public float Z; + + /// + /// The W component of the Vector4. + /// + public float W; + + /// + /// Defines a unit-length Vector4 that points towards the X-axis. + /// + public static Vector4 UnitX = new Vector4(1, 0, 0, 0); + + /// + /// Defines a unit-length Vector4 that points towards the Y-axis. + /// + public static Vector4 UnitY = new Vector4(0, 1, 0, 0); + + /// + /// Defines a unit-length Vector4 that points towards the Z-axis. + /// + public static Vector4 UnitZ = new Vector4(0, 0, 1, 0); + + /// + /// Defines a unit-length Vector4 that points towards the W-axis. + /// + public static Vector4 UnitW = new Vector4(0, 0, 0, 1); + + /// + /// Defines a zero-length Vector4. + /// + public static Vector4 Zero = new Vector4(0, 0, 0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector4 One = new Vector4(1, 1, 1, 1); + + /// + /// Defines the size of the Vector4 struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector4()); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector4(float value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + /// + /// Constructs a new Vector4. + /// + /// The x component of the Vector4. + /// The y component of the Vector4. + /// The z component of the Vector4. + /// The w component of the Vector4. + public Vector4(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + /// + /// Constructs a new Vector4 from the given Vector2. + /// + /// The Vector2 to copy components from. + public Vector4(Vector2 v) + { + X = v.X; + Y = v.Y; + Z = 0.0f; + W = 0.0f; + } + + /// + /// Constructs a new Vector4 from the given Vector3. + /// The w component is initialized to 0. + /// + /// The Vector3 to copy components from. + /// + public Vector4(Vector3 v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = 0.0f; + } + + /// + /// Constructs a new Vector4 from the specified Vector3 and w component. + /// + /// The Vector3 to copy components from. + /// The w component of the new Vector4. + public Vector4(Vector3 v, float w) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = w; + } + + /// + /// Constructs a new Vector4 from the given Vector4. + /// + /// The Vector4 to copy components from. + public Vector4(Vector4 v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = v.W; + } + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector4 right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + this.W += right.W; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector4 right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + this.W += right.W; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector4 right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + this.W -= right.W; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector4 right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + this.W -= right.W; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(float f) + { + this.X *= f; + this.Y *= f; + this.Z *= f; + this.W *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(float f) + { + float mult = 1.0f / f; + this.X *= mult; + this.Y *= mult; + this.Z *= mult; + this.W *= mult; + } + + #endregion public void Div() + + #region public float Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + /// + public float Length + { + get + { + return (float)System.Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + } + + #endregion + + #region public float LengthFast + + /// + /// Gets an approximation of the vector length (magnitude). + /// + /// + /// This property uses an approximation of the square root function to calculate vector magnitude, with + /// an upper error bound of 0.001. + /// + /// + /// + public float LengthFast + { + get + { + return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W); + } + } + + #endregion + + #region public float LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + /// + public float LengthSquared + { + get + { + return X * X + Y * Y + Z * Z + W * W; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector4 to unit length. + /// + public void Normalize() + { + float scale = 1.0f / this.Length; + X *= scale; + Y *= scale; + Z *= scale; + W *= scale; + } + + #endregion + + #region public void NormalizeFast() + + /// + /// Scales the Vector4 to approximately unit length. + /// + public void NormalizeFast() + { + float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W); + X *= scale; + Y *= scale; + Z *= scale; + W *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector4 by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + /// The scale of the Z component. + /// The scale of the Z component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(float sx, float sy, float sz, float sw) + { + this.X = X * sx; + this.Y = Y * sy; + this.Z = Z * sz; + this.W = W * sw; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector4 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + this.W *= scale.W; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector4 scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + this.W *= scale.W; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector4 Sub(Vector4 a, Vector4 b) + { + a.X -= b.X; + a.Y -= b.Y; + a.Z -= b.Z; + a.W -= b.W; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Sub(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + result.W = a.W - b.W; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + public static Vector4 Mult(Vector4 a, float f) + { + a.X *= f; + a.Y *= f; + a.Z *= f; + a.W *= f; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + public static void Mult(ref Vector4 a, float f, out Vector4 result) + { + result.X = a.X * f; + result.Y = a.Y * f; + result.Z = a.Z * f; + result.W = a.W * f; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + public static Vector4 Div(Vector4 a, float f) + { + float mult = 1.0f / f; + a.X *= mult; + a.Y *= mult; + a.Z *= mult; + a.W *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + public static void Div(ref Vector4 a, float f, out Vector4 result) + { + float mult = 1.0f / f; + result.X = a.X * mult; + result.Y = a.Y * mult; + result.Z = a.Z * mult; + result.W = a.W * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector4 Add(Vector4 a, Vector4 b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result = new Vector4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector4 Subtract(Vector4 a, Vector4 b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result = new Vector4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4 Multiply(Vector4 vector, float scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector4 vector, float scale, out Vector4 result) + { + result = new Vector4(vector.X * scale, vector.Y * scale, vector.Z * scale, vector.W * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4 Multiply(Vector4 vector, Vector4 scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector4 vector, ref Vector4 scale, out Vector4 result) + { + result = new Vector4(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z, vector.W * scale.W); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4 Divide(Vector4 vector, float scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector4 vector, float scale, out Vector4 result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4 Divide(Vector4 vector, Vector4 scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector4 vector, ref Vector4 scale, out Vector4 result) + { + result = new Vector4(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z, vector.W / scale.W); + } + + #endregion + + #region Min + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector4 Min(Vector4 a, Vector4 b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + a.W = a.W < b.W ? a.W : b.W; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void Min(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + result.W = a.W < b.W ? a.W : b.W; + } + + #endregion + + #region Max + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector4 Max(Vector4 a, Vector4 b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + a.W = a.W > b.W ? a.W : b.W; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void Max(ref Vector4 a, ref Vector4 b, out Vector4 result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + result.W = a.W > b.W ? a.W : b.W; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector4 Clamp(Vector4 vec, Vector4 min, Vector4 max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + vec.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + vec.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector4 vec, ref Vector4 min, ref Vector4 max, out Vector4 result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + result.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + result.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector4 Normalize(Vector4 vec) + { + float scale = 1.0f / vec.Length; + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector4 vec, out Vector4 result) + { + float scale = 1.0f / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + result.W = vec.W * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector4 NormalizeFast(Vector4 vec) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W); + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector4 vec, out Vector4 result) + { + float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + result.W = vec.W * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static float Dot(Vector4 left, Vector4 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + + /// + /// Calculate the dot product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector4 left, ref Vector4 right, out float result) + { + result = left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector4 Lerp(Vector4 a, Vector4 b, float blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + a.Z = blend * (b.Z - a.Z) + a.Z; + a.W = blend * (b.W - a.W) + a.W; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector4 a, ref Vector4 b, float blend, out Vector4 result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + result.Z = blend * (b.Z - a.Z) + a.Z; + result.W = blend * (b.W - a.W) + a.W; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector4 BaryCentric(Vector4 a, Vector4 b, Vector4 c, float u, float v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector4 a, ref Vector4 b, ref Vector4 c, float u, float v, out Vector4 result) + { + result = a; // copy + + Vector4 temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector4 Transform(Vector4 vec, Matrix4 mat) + { + Vector4 result; + Transform(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void Transform(ref Vector4 vec, ref Matrix4 mat, out Vector4 result) + { + result = new Vector4( + vec.X * mat.Row0.X + vec.Y * mat.Row1.X + vec.Z * mat.Row2.X + vec.W * mat.Row3.X, + vec.X * mat.Row0.Y + vec.Y * mat.Row1.Y + vec.Z * mat.Row2.Y + vec.W * mat.Row3.Y, + vec.X * mat.Row0.Z + vec.Y * mat.Row1.Z + vec.Z * mat.Row2.Z + vec.W * mat.Row3.Z, + vec.X * mat.Row0.W + vec.Y * mat.Row1.W + vec.Z * mat.Row2.W + vec.W * mat.Row3.W); + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector4 Transform(Vector4 vec, Quaternion quat) + { + Vector4 result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector4 vec, ref Quaternion quat, out Vector4 result) + { + Quaternion v = new Quaternion(vec.X, vec.Y, vec.Z, vec.W), i, t; + Quaternion.Invert(ref quat, out i); + Quaternion.Multiply(ref quat, ref v, out t); + Quaternion.Multiply(ref t, ref i, out v); + + result = new Vector4(v.X, v.Y, v.Z, v.W); + } + + #endregion + + #endregion + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2 with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2 Xy { get { return new Vector2(X, Y); } set { X = value.X; Y = value.Y; } } + + /// + /// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance. + /// + [XmlIgnore] + public Vector3 Xyz { get { return new Vector3(X, Y, Z); } set { X = value.X; Y = value.Y; Z = value.Z; } } + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector4 operator +(Vector4 left, Vector4 right) + { + left.X += right.X; + left.Y += right.Y; + left.Z += right.Z; + left.W += right.W; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector4 operator -(Vector4 left, Vector4 right) + { + left.X -= right.X; + left.Y -= right.Y; + left.Z -= right.Z; + left.W -= right.W; + return left; + } + + /// + /// Negates an instance. + /// + /// The instance. + /// The result of the calculation. + public static Vector4 operator -(Vector4 vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + vec.Z = -vec.Z; + vec.W = -vec.W; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector4 operator *(Vector4 vec, float scale) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The scalar. + /// The instance. + /// The result of the calculation. + public static Vector4 operator *(float scale, Vector4 vec) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Divides an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector4 operator /(Vector4 vec, float scale) + { + float mult = 1.0f / scale; + vec.X *= mult; + vec.Y *= mult; + vec.Z *= mult; + vec.W *= mult; + return vec; + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Vector4 left, Vector4 right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equa lright; false otherwise. + public static bool operator !=(Vector4 left, Vector4 right) + { + return !left.Equals(right); + } + + /// + /// Returns a pointer to the first element of the specified instance. + /// + /// The instance. + /// A pointer to the first element of v. + [CLSCompliant(false)] + unsafe public static explicit operator float*(Vector4 v) + { + return &v.X; + } + + /// + /// Returns a pointer to the first element of the specified instance. + /// + /// The instance. + /// A pointer to the first element of v. + public static explicit operator IntPtr(Vector4 v) + { + unsafe + { + return (IntPtr)(&v.X); + } + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Vector4. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1}, {2}, {3})", X, Y, Z, W); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector4)) + return false; + + return this.Equals((Vector4)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector4 other) + { + return + X == other.X && + Y == other.Y && + Z == other.Z && + W == other.W; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector4d.cs b/src/MiniTK/Math/Vector4d.cs new file mode 100644 index 0000000..ec06734 --- /dev/null +++ b/src/MiniTK/Math/Vector4d.cs @@ -0,0 +1,1238 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// Represents a 4D vector using four double-precision floating-point numbers. + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector4d : IEquatable + { + #region Fields + + /// + /// The X component of the Vector4d. + /// + public double X; + + /// + /// The Y component of the Vector4d. + /// + public double Y; + + /// + /// The Z component of the Vector4d. + /// + public double Z; + + /// + /// The W component of the Vector4d. + /// + public double W; + + /// + /// Defines a unit-length Vector4d that points towards the X-axis. + /// + public static Vector4d UnitX = new Vector4d(1, 0, 0, 0); + + /// + /// Defines a unit-length Vector4d that points towards the Y-axis. + /// + public static Vector4d UnitY = new Vector4d(0, 1, 0, 0); + + /// + /// Defines a unit-length Vector4d that points towards the Z-axis. + /// + public static Vector4d UnitZ = new Vector4d(0, 0, 1, 0); + + /// + /// Defines a unit-length Vector4d that points towards the W-axis. + /// + public static Vector4d UnitW = new Vector4d(0, 0, 0, 1); + + /// + /// Defines a zero-length Vector4d. + /// + public static Vector4d Zero = new Vector4d(0, 0, 0, 0); + + /// + /// Defines an instance with all components set to 1. + /// + public static readonly Vector4d One = new Vector4d(1, 1, 1, 1); + + /// + /// Defines the size of the Vector4d struct in bytes. + /// + public static readonly int SizeInBytes = Marshal.SizeOf(new Vector4d()); + + #endregion + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector4d(double value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + /// + /// Constructs a new Vector4d. + /// + /// The x component of the Vector4d. + /// The y component of the Vector4d. + /// The z component of the Vector4d. + /// The w component of the Vector4d. + public Vector4d(double x, double y, double z, double w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + /// + /// Constructs a new Vector4d from the given Vector2d. + /// + /// The Vector2d to copy components from. + public Vector4d(Vector2d v) + { + X = v.X; + Y = v.Y; + Z = 0.0f; + W = 0.0f; + } + + /// + /// Constructs a new Vector4d from the given Vector3d. + /// The w component is initialized to 0. + /// + /// The Vector3d to copy components from. + /// + public Vector4d(Vector3d v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = 0.0f; + } + + /// + /// Constructs a new Vector4d from the specified Vector3d and w component. + /// + /// The Vector3d to copy components from. + /// The w component of the new Vector4. + public Vector4d(Vector3d v, double w) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = w; + } + + /// + /// Constructs a new Vector4d from the given Vector4d. + /// + /// The Vector4d to copy components from. + public Vector4d(Vector4d v) + { + X = v.X; + Y = v.Y; + Z = v.Z; + W = v.W; + } + + #endregion + + #region Public Members + + #region Instance + + #region public void Add() + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Add() method instead.")] + public void Add(Vector4d right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + this.W += right.W; + } + + /// Add the Vector passed as parameter to this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Add() method instead.")] + public void Add(ref Vector4d right) + { + this.X += right.X; + this.Y += right.Y; + this.Z += right.Z; + this.W += right.W; + } + + #endregion public void Add() + + #region public void Sub() + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [Obsolete("Use static Subtract() method instead.")] + public void Sub(Vector4d right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + this.W -= right.W; + } + + /// Subtract the Vector passed as parameter from this instance. + /// Right operand. This parameter is only read from. + [CLSCompliant(false)] + [Obsolete("Use static Subtract() method instead.")] + public void Sub(ref Vector4d right) + { + this.X -= right.X; + this.Y -= right.Y; + this.Z -= right.Z; + this.W -= right.W; + } + + #endregion public void Sub() + + #region public void Mult() + + /// Multiply this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Multiply() method instead.")] + public void Mult(double f) + { + this.X *= f; + this.Y *= f; + this.Z *= f; + this.W *= f; + } + + #endregion public void Mult() + + #region public void Div() + + /// Divide this instance by a scalar. + /// Scalar operand. + [Obsolete("Use static Divide() method instead.")] + public void Div(double f) + { + double mult = 1.0 / f; + this.X *= mult; + this.Y *= mult; + this.Z *= mult; + this.W *= mult; + } + + #endregion public void Div() + + #region public double Length + + /// + /// Gets the length (magnitude) of the vector. + /// + /// + /// + public double Length + { + get + { + return System.Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + } + + #endregion + + #region public double LengthFast + + /// + /// Gets an approximation of the vector length (magnitude). + /// + /// + /// This property uses an approximation of the square root function to calculate vector magnitude, with + /// an upper error bound of 0.001. + /// + /// + /// + public double LengthFast + { + get + { + return 1.0 / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W); + } + } + + #endregion + + #region public double LengthSquared + + /// + /// Gets the square of the vector length (magnitude). + /// + /// + /// This property avoids the costly square root operation required by the Length property. This makes it more suitable + /// for comparisons. + /// + /// + public double LengthSquared + { + get + { + return X * X + Y * Y + Z * Z + W * W; + } + } + + #endregion + + #region public void Normalize() + + /// + /// Scales the Vector4d to unit length. + /// + public void Normalize() + { + double scale = 1.0 / this.Length; + X *= scale; + Y *= scale; + Z *= scale; + W *= scale; + } + + #endregion + + #region public void NormalizeFast() + + /// + /// Scales the Vector4d to approximately unit length. + /// + public void NormalizeFast() + { + double scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W); + X *= scale; + Y *= scale; + Z *= scale; + W *= scale; + } + + #endregion + + #region public void Scale() + + /// + /// Scales the current Vector4d by the given amounts. + /// + /// The scale of the X component. + /// The scale of the Y component. + /// The scale of the Z component. + /// The scale of the Z component. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(double sx, double sy, double sz, double sw) + { + this.X = X * sx; + this.Y = Y * sy; + this.Z = Z * sz; + this.W = W * sw; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [Obsolete("Use static Multiply() method instead.")] + public void Scale(Vector4d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + this.W *= scale.W; + } + + /// Scales this instance by the given parameter. + /// The scaling of the individual components. + [CLSCompliant(false)] + [Obsolete("Use static Multiply() method instead.")] + public void Scale(ref Vector4d scale) + { + this.X *= scale.X; + this.Y *= scale.Y; + this.Z *= scale.Z; + this.W *= scale.W; + } + + #endregion public void Scale() + + #endregion + + #region Static + + #region Obsolete + + #region Sub + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static Vector4d Sub(Vector4d a, Vector4d b) + { + a.X -= b.X; + a.Y -= b.Y; + a.Z -= b.Z; + a.W -= b.W; + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + [Obsolete("Use static Subtract() method instead.")] + public static void Sub(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + result.W = a.W - b.W; + } + + #endregion + + #region Mult + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static Vector4d Mult(Vector4d a, double f) + { + a.X *= f; + a.Y *= f; + a.Z *= f; + a.W *= f; + return a; + } + + /// + /// Multiply a vector and a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the multiplication + [Obsolete("Use static Multiply() method instead.")] + public static void Mult(ref Vector4d a, double f, out Vector4d result) + { + result.X = a.X * f; + result.Y = a.Y * f; + result.Z = a.Z * f; + result.W = a.W * f; + } + + #endregion + + #region Div + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static Vector4d Div(Vector4d a, double f) + { + double mult = 1.0 / f; + a.X *= mult; + a.Y *= mult; + a.Z *= mult; + a.W *= mult; + return a; + } + + /// + /// Divide a vector by a scalar + /// + /// Vector operand + /// Scalar operand + /// Result of the division + [Obsolete("Use static Divide() method instead.")] + public static void Div(ref Vector4d a, double f, out Vector4d result) + { + double mult = 1.0 / f; + result.X = a.X * mult; + result.Y = a.Y * mult; + result.Z = a.Z * mult; + result.W = a.W * mult; + } + + #endregion + + #endregion + + #region Add + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static Vector4d Add(Vector4d a, Vector4d b) + { + Add(ref a, ref b, out a); + return a; + } + + /// + /// Adds two vectors. + /// + /// Left operand. + /// Right operand. + /// Result of operation. + public static void Add(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result = new Vector4d(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W); + } + + #endregion + + #region Subtract + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static Vector4d Subtract(Vector4d a, Vector4d b) + { + Subtract(ref a, ref b, out a); + return a; + } + + /// + /// Subtract one Vector from another + /// + /// First operand + /// Second operand + /// Result of subtraction + public static void Subtract(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result = new Vector4d(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W); + } + + #endregion + + #region Multiply + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4d Multiply(Vector4d vector, double scale) + { + Multiply(ref vector, scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector4d vector, double scale, out Vector4d result) + { + result = new Vector4d(vector.X * scale, vector.Y * scale, vector.Z * scale, vector.W * scale); + } + + /// + /// Multiplies a vector by the components a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4d Multiply(Vector4d vector, Vector4d scale) + { + Multiply(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Multiplies a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Multiply(ref Vector4d vector, ref Vector4d scale, out Vector4d result) + { + result = new Vector4d(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z, vector.W * scale.W); + } + + #endregion + + #region Divide + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4d Divide(Vector4d vector, double scale) + { + Divide(ref vector, scale, out vector); + return vector; + } + + /// + /// Divides a vector by a scalar. + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector4d vector, double scale, out Vector4d result) + { + Multiply(ref vector, 1 / scale, out result); + } + + /// + /// Divides a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static Vector4d Divide(Vector4d vector, Vector4d scale) + { + Divide(ref vector, ref scale, out vector); + return vector; + } + + /// + /// Divide a vector by the components of a vector (scale). + /// + /// Left operand. + /// Right operand. + /// Result of the operation. + public static void Divide(ref Vector4d vector, ref Vector4d scale, out Vector4d result) + { + result = new Vector4d(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z, vector.W / scale.W); + } + + #endregion + + #region Min + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static Vector4d Min(Vector4d a, Vector4d b) + { + a.X = a.X < b.X ? a.X : b.X; + a.Y = a.Y < b.Y ? a.Y : b.Y; + a.Z = a.Z < b.Z ? a.Z : b.Z; + a.W = a.W < b.W ? a.W : b.W; + return a; + } + + /// + /// Calculate the component-wise minimum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise minimum + public static void Min(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result.X = a.X < b.X ? a.X : b.X; + result.Y = a.Y < b.Y ? a.Y : b.Y; + result.Z = a.Z < b.Z ? a.Z : b.Z; + result.W = a.W < b.W ? a.W : b.W; + } + + #endregion + + #region Max + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static Vector4d Max(Vector4d a, Vector4d b) + { + a.X = a.X > b.X ? a.X : b.X; + a.Y = a.Y > b.Y ? a.Y : b.Y; + a.Z = a.Z > b.Z ? a.Z : b.Z; + a.W = a.W > b.W ? a.W : b.W; + return a; + } + + /// + /// Calculate the component-wise maximum of two vectors + /// + /// First operand + /// Second operand + /// The component-wise maximum + public static void Max(ref Vector4d a, ref Vector4d b, out Vector4d result) + { + result.X = a.X > b.X ? a.X : b.X; + result.Y = a.Y > b.Y ? a.Y : b.Y; + result.Z = a.Z > b.Z ? a.Z : b.Z; + result.W = a.W > b.W ? a.W : b.W; + } + + #endregion + + #region Clamp + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static Vector4d Clamp(Vector4d vec, Vector4d min, Vector4d max) + { + vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + vec.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + vec.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + return vec; + } + + /// + /// Clamp a vector to the given minimum and maximum vectors + /// + /// Input vector + /// Minimum vector + /// Maximum vector + /// The clamped vector + public static void Clamp(ref Vector4d vec, ref Vector4d min, ref Vector4d max, out Vector4d result) + { + result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; + result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; + result.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z; + result.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W; + } + + #endregion + + #region Normalize + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static Vector4d Normalize(Vector4d vec) + { + double scale = 1.0 / vec.Length; + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Scale a vector to unit length + /// + /// The input vector + /// The normalized vector + public static void Normalize(ref Vector4d vec, out Vector4d result) + { + double scale = 1.0 / vec.Length; + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + result.W = vec.W * scale; + } + + #endregion + + #region NormalizeFast + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static Vector4d NormalizeFast(Vector4d vec) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W); + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Scale a vector to approximately unit length + /// + /// The input vector + /// The normalized vector + public static void NormalizeFast(ref Vector4d vec, out Vector4d result) + { + double scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W); + result.X = vec.X * scale; + result.Y = vec.Y * scale; + result.Z = vec.Z * scale; + result.W = vec.W * scale; + } + + #endregion + + #region Dot + + /// + /// Calculate the dot product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static double Dot(Vector4d left, Vector4d right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + + /// + /// Calculate the dot product of two vectors + /// + /// First operand + /// Second operand + /// The dot product of the two inputs + public static void Dot(ref Vector4d left, ref Vector4d right, out double result) + { + result = left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + + #endregion + + #region Lerp + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static Vector4d Lerp(Vector4d a, Vector4d b, double blend) + { + a.X = blend * (b.X - a.X) + a.X; + a.Y = blend * (b.Y - a.Y) + a.Y; + a.Z = blend * (b.Z - a.Z) + a.Z; + a.W = blend * (b.W - a.W) + a.W; + return a; + } + + /// + /// Returns a new Vector that is the linear blend of the 2 given Vectors + /// + /// First input vector + /// Second input vector + /// The blend factor. a when blend=0, b when blend=1. + /// a when blend=0, b when blend=1, and a linear combination otherwise + public static void Lerp(ref Vector4d a, ref Vector4d b, double blend, out Vector4d result) + { + result.X = blend * (b.X - a.X) + a.X; + result.Y = blend * (b.Y - a.Y) + a.Y; + result.Z = blend * (b.Z - a.Z) + a.Z; + result.W = blend * (b.W - a.W) + a.W; + } + + #endregion + + #region Barycentric + + /// + /// Interpolate 3 Vectors using Barycentric coordinates + /// + /// First input Vector + /// Second input Vector + /// Third input Vector + /// First Barycentric Coordinate + /// Second Barycentric Coordinate + /// a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static Vector4d BaryCentric(Vector4d a, Vector4d b, Vector4d c, double u, double v) + { + return a + u * (b - a) + v * (c - a); + } + + /// Interpolate 3 Vectors using Barycentric coordinates + /// First input Vector. + /// Second input Vector. + /// Third input Vector. + /// First Barycentric Coordinate. + /// Second Barycentric Coordinate. + /// Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise + public static void BaryCentric(ref Vector4d a, ref Vector4d b, ref Vector4d c, double u, double v, out Vector4d result) + { + result = a; // copy + + Vector4d temp = b; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, u, out temp); + Add(ref result, ref temp, out result); + + temp = c; // copy + Subtract(ref temp, ref a, out temp); + Multiply(ref temp, v, out temp); + Add(ref result, ref temp, out result); + } + + #endregion + + #region Transform + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static Vector4d Transform(Vector4d vec, Matrix4d mat) + { + Vector4d result; + Transform(ref vec, ref mat, out result); + return result; + } + + /// Transform a Vector by the given Matrix + /// The vector to transform + /// The desired transformation + /// The transformed vector + public static void Transform(ref Vector4d vec, ref Matrix4d mat, out Vector4d result) + { + result = new Vector4d( + vec.X * mat.Row0.X + vec.Y * mat.Row1.X + vec.Z * mat.Row2.X + vec.W * mat.Row3.X, + vec.X * mat.Row0.Y + vec.Y * mat.Row1.Y + vec.Z * mat.Row2.Y + vec.W * mat.Row3.Y, + vec.X * mat.Row0.Z + vec.Y * mat.Row1.Z + vec.Z * mat.Row2.Z + vec.W * mat.Row3.Z, + vec.X * mat.Row0.W + vec.Y * mat.Row1.W + vec.Z * mat.Row2.W + vec.W * mat.Row3.W); + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static Vector4d Transform(Vector4d vec, Quaterniond quat) + { + Vector4d result; + Transform(ref vec, ref quat, out result); + return result; + } + + /// + /// Transforms a vector by a quaternion rotation. + /// + /// The vector to transform. + /// The quaternion to rotate the vector by. + /// The result of the operation. + public static void Transform(ref Vector4d vec, ref Quaterniond quat, out Vector4d result) + { + Quaterniond v = new Quaterniond(vec.X, vec.Y, vec.Z, vec.W), i, t; + Quaterniond.Invert(ref quat, out i); + Quaterniond.Multiply(ref quat, ref v, out t); + Quaterniond.Multiply(ref t, ref i, out v); + + result = new Vector4d(v.X, v.Y, v.Z, v.W); + } + + #endregion + + #endregion + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2d with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2d Xy { get { return new Vector2d(X, Y); } set { X = value.X; Y = value.Y; } } + + /// + /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance. + /// + [XmlIgnore] + public Vector3d Xyz { get { return new Vector3d(X, Y, Z); } set { X = value.X; Y = value.Y; Z = value.Z; } } + + #endregion + + #region Operators + + /// + /// Adds two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector4d operator +(Vector4d left, Vector4d right) + { + left.X += right.X; + left.Y += right.Y; + left.Z += right.Z; + left.W += right.W; + return left; + } + + /// + /// Subtracts two instances. + /// + /// The first instance. + /// The second instance. + /// The result of the calculation. + public static Vector4d operator -(Vector4d left, Vector4d right) + { + left.X -= right.X; + left.Y -= right.Y; + left.Z -= right.Z; + left.W -= right.W; + return left; + } + + /// + /// Negates an instance. + /// + /// The instance. + /// The result of the calculation. + public static Vector4d operator -(Vector4d vec) + { + vec.X = -vec.X; + vec.Y = -vec.Y; + vec.Z = -vec.Z; + vec.W = -vec.W; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector4d operator *(Vector4d vec, double scale) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Multiplies an instance by a scalar. + /// + /// The scalar. + /// The instance. + /// The result of the calculation. + public static Vector4d operator *(double scale, Vector4d vec) + { + vec.X *= scale; + vec.Y *= scale; + vec.Z *= scale; + vec.W *= scale; + return vec; + } + + /// + /// Divides an instance by a scalar. + /// + /// The instance. + /// The scalar. + /// The result of the calculation. + public static Vector4d operator /(Vector4d vec, double scale) + { + double mult = 1 / scale; + vec.X *= mult; + vec.Y *= mult; + vec.Z *= mult; + vec.W *= mult; + return vec; + } + + /// + /// Compares two instances for equality. + /// + /// The first instance. + /// The second instance. + /// True, if left equals right; false otherwise. + public static bool operator ==(Vector4d left, Vector4d right) + { + return left.Equals(right); + } + + /// + /// Compares two instances for inequality. + /// + /// The first instance. + /// The second instance. + /// True, if left does not equa lright; false otherwise. + public static bool operator !=(Vector4d left, Vector4d right) + { + return !left.Equals(right); + } + + /// + /// Returns a pointer to the first element of the specified instance. + /// + /// The instance. + /// A pointer to the first element of v. + [CLSCompliant(false)] + unsafe public static explicit operator double*(Vector4d v) + { + return &v.X; + } + + /// + /// Returns a pointer to the first element of the specified instance. + /// + /// The instance. + /// A pointer to the first element of v. + public static explicit operator IntPtr(Vector4d v) + { + unsafe + { + return (IntPtr)(&v.X); + } + } + + /// Converts OpenTK.Vector4 to OpenTK.Vector4d. + /// The Vector4 to convert. + /// The resulting Vector4d. + public static explicit operator Vector4d(Vector4 v4) + { + return new Vector4d(v4.X, v4.Y, v4.Z, v4.W); + } + + /// Converts OpenTK.Vector4d to OpenTK.Vector4. + /// The Vector4d to convert. + /// The resulting Vector4. + public static explicit operator Vector4(Vector4d v4d) + { + return new Vector4((float)v4d.X, (float)v4d.Y, (float)v4d.Z, (float)v4d.W); + } + + #endregion + + #region Overrides + + #region public override string ToString() + + /// + /// Returns a System.String that represents the current Vector4d. + /// + /// + public override string ToString() + { + return String.Format("({0}, {1}, {2}, {3})", X, Y, Z, W); + } + + #endregion + + #region public override int GetHashCode() + + /// + /// Returns the hashcode for this instance. + /// + /// A System.Int32 containing the unique hashcode for this instance. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode(); + } + + #endregion + + #region public override bool Equals(object obj) + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// The object to compare to. + /// True if the instances are equal; false otherwise. + public override bool Equals(object obj) + { + if (!(obj is Vector4d)) + return false; + + return this.Equals((Vector4d)obj); + } + + #endregion + + #endregion + + #endregion + + #region IEquatable Members + + /// Indicates whether the current vector is equal to another vector. + /// A vector to compare with this vector. + /// true if the current vector is equal to the vector parameter; otherwise, false. + public bool Equals(Vector4d other) + { + return + X == other.X && + Y == other.Y && + Z == other.Z && + W == other.W; + } + + #endregion + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file diff --git a/src/MiniTK/Math/Vector4h.cs b/src/MiniTK/Math/Vector4h.cs new file mode 100644 index 0000000..e1ca8fc --- /dev/null +++ b/src/MiniTK/Math/Vector4h.cs @@ -0,0 +1,444 @@ +#region --- License --- +/* +Copyright (c) 2006 - 2008 The Open Toolkit library. + +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. + */ +#endregion + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +// flibit Added This!!! +#pragma warning disable 3021 + +namespace OpenTK +{ + /// + /// 4-component Vector of the Half type. Occupies 8 Byte total. + /// + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct Vector4h : ISerializable, IEquatable + { + #region Public Fields + + /// The X component of the Half4. + public Half X; + + /// The Y component of the Half4. + public Half Y; + + /// The Z component of the Half4. + public Half Z; + + /// The W component of the Half4. + public Half W; + + #endregion Public Fields + + #region Constructors + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector4h(Half value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + /// + /// Constructs a new instance. + /// + /// The value that will initialize this instance. + public Vector4h(Single value) + { + X = new Half(value); + Y = new Half(value); + Z = new Half(value); + W = new Half(value); + } + + /// + /// The new Half4 instance will avoid conversion and copy directly from the Half parameters. + /// + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + /// An Half instance of a 16-bit half-precision floating-point number. + public Vector4h(Half x, Half y, Half z, Half w) + { + this.X = x; + this.Y = y; + this.Z = z; + this.W = w; + } + + /// + /// The new Half4 instance will convert the 4 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + public Vector4h(Single x, Single y, Single z, Single w) + { + X = new Half(x); + Y = new Half(y); + Z = new Half(z); + W = new Half(w); + } + + /// + /// The new Half4 instance will convert the 4 parameters into 16-bit half-precision floating-point. + /// + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// 32-bit single-precision floating-point number. + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector4h(Single x, Single y, Single z, Single w, bool throwOnError) + { + X = new Half(x, throwOnError); + Y = new Half(y, throwOnError); + Z = new Half(z, throwOnError); + W = new Half(w, throwOnError); + } + + /// + /// The new Half4 instance will convert the Vector4 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4 + [CLSCompliant(false)] + public Vector4h(Vector4 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + W = new Half(v.W); + } + + /// + /// The new Half4 instance will convert the Vector4 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4 + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector4h(Vector4 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + W = new Half(v.W, throwOnError); + } + + /// + /// The new Half4 instance will convert the Vector4 into 16-bit half-precision floating-point. + /// This is the fastest constructor. + /// + /// OpenTK.Vector4 + public Vector4h(ref Vector4 v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + W = new Half(v.W); + } + + /// + /// The new Half4 instance will convert the Vector4 into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4 + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector4h(ref Vector4 v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + W = new Half(v.W, throwOnError); + } + + /// + /// The new Half4 instance will convert the Vector4d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4d + public Vector4h(Vector4d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + W = new Half(v.W); + } + + /// + /// The new Half4 instance will convert the Vector4d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4d + /// Enable checks that will throw if the conversion result is not meaningful. + public Vector4h(Vector4d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + W = new Half(v.W, throwOnError); + } + + /// + /// The new Half4 instance will convert the Vector4d into 16-bit half-precision floating-point. + /// This is the faster constructor. + /// + /// OpenTK.Vector4d + [CLSCompliant(false)] + public Vector4h(ref Vector4d v) + { + X = new Half(v.X); + Y = new Half(v.Y); + Z = new Half(v.Z); + W = new Half(v.W); + } + + /// + /// The new Half4 instance will convert the Vector4d into 16-bit half-precision floating-point. + /// + /// OpenTK.Vector4d + /// Enable checks that will throw if the conversion result is not meaningful. + [CLSCompliant(false)] + public Vector4h(ref Vector4d v, bool throwOnError) + { + X = new Half(v.X, throwOnError); + Y = new Half(v.Y, throwOnError); + Z = new Half(v.Z, throwOnError); + W = new Half(v.W, throwOnError); + } + + #endregion Constructors + + #region Swizzle + + /// + /// Gets or sets an OpenTK.Vector2h with the X and Y components of this instance. + /// + [XmlIgnore] + public Vector2h Xy { get { return new Vector2h(X, Y); } set { X = value.X; Y = value.Y; } } + + /// + /// Gets or sets an OpenTK.Vector3h with the X, Y and Z components of this instance. + /// + [XmlIgnore] + public Vector3h Xyz { get { return new Vector3h(X, Y, Z); } set { X = value.X; Y = value.Y; Z = value.Z; } } + + #endregion + + #region Half -> Single + + /// + /// Returns this Half4 instance's contents as Vector4. + /// + /// OpenTK.Vector4 + public Vector4 ToVector4() + { + return new Vector4(X, Y, Z, W); + } + + /// + /// Returns this Half4 instance's contents as Vector4d. + /// + public Vector4d ToVector4d() + { + return new Vector4d(X, Y, Z, W); + } + + #endregion Half -> Single + + #region Conversions + + /// Converts OpenTK.Vector4 to OpenTK.Half4. + /// The Vector4 to convert. + /// The resulting Half vector. + public static explicit operator Vector4h(Vector4 v4f) + { + return new Vector4h(v4f); + } + + /// Converts OpenTK.Vector4d to OpenTK.Half4. + /// The Vector4d to convert. + /// The resulting Half vector. + public static explicit operator Vector4h(Vector4d v4d) + { + return new Vector4h(v4d); + } + + /// Converts OpenTK.Half4 to OpenTK.Vector4. + /// The Half4 to convert. + /// The resulting Vector4. + public static explicit operator Vector4(Vector4h h4) + { + Vector4 result = new Vector4(); + result.X = h4.X.ToSingle(); + result.Y = h4.Y.ToSingle(); + result.Z = h4.Z.ToSingle(); + result.W = h4.W.ToSingle(); + return result; + } + + /// Converts OpenTK.Half4 to OpenTK.Vector4d. + /// The Half4 to convert. + /// The resulting Vector4d. + public static explicit operator Vector4d(Vector4h h4) + { + Vector4d result = new Vector4d(); + result.X = h4.X.ToSingle(); + result.Y = h4.Y.ToSingle(); + result.Z = h4.Z.ToSingle(); + result.W = h4.W.ToSingle(); + return result; + } + + #endregion Conversions + + #region Constants + + /// The size in bytes for an instance of the Half4 struct is 8. + public static readonly int SizeInBytes = 8; + + #endregion Constants + + #region ISerializable + + /// Constructor used by ISerializable to deserialize the object. + /// + /// + public Vector4h(SerializationInfo info, StreamingContext context) + { + this.X = (Half)info.GetValue("X", typeof(Half)); + this.Y = (Half)info.GetValue("Y", typeof(Half)); + this.Z = (Half)info.GetValue("Z", typeof(Half)); + this.W = (Half)info.GetValue("W", typeof(Half)); + } + + /// Used by ISerialize to serialize the object. + /// + /// + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("X", this.X); + info.AddValue("Y", this.Y); + info.AddValue("Z", this.Z); + info.AddValue("W", this.W); + } + + #endregion ISerializable + + #region Binary dump + + /// Updates the X,Y,Z and W components of this instance by reading from a Stream. + /// A BinaryReader instance associated with an open Stream. + public void FromBinaryStream(BinaryReader bin) + { + X.FromBinaryStream(bin); + Y.FromBinaryStream(bin); + Z.FromBinaryStream(bin); + W.FromBinaryStream(bin); + } + + /// Writes the X,Y,Z and W components of this instance into a Stream. + /// A BinaryWriter instance associated with an open Stream. + public void ToBinaryStream(BinaryWriter bin) + { + X.ToBinaryStream(bin); + Y.ToBinaryStream(bin); + Z.ToBinaryStream(bin); + W.ToBinaryStream(bin); + } + + #endregion Binary dump + + #region IEquatable Members + + /// Returns a value indicating whether this instance is equal to a specified OpenTK.Half4 vector. + /// OpenTK.Half4 to compare to this instance.. + /// True, if other is equal to this instance; false otherwise. + public bool Equals(Vector4h other) + { + return (this.X.Equals(other.X) && this.Y.Equals(other.Y) && this.Z.Equals(other.Z) && this.W.Equals(other.W)); + } + + #endregion + + #region ToString() + + /// Returns a string that contains this Half4's numbers in human-legible form. + public override string ToString() + { + return String.Format("({0}, {1}, {2}, {3})", X.ToString(), Y.ToString(), Z.ToString(), W.ToString()); + } + + #endregion ToString() + + #region BitConverter + + /// Returns the Half4 as an array of bytes. + /// The Half4 to convert. + /// The input as byte array. + public static byte[] GetBytes(Vector4h h) + { + byte[] result = new byte[SizeInBytes]; + + byte[] temp = Half.GetBytes(h.X); + result[0] = temp[0]; + result[1] = temp[1]; + temp = Half.GetBytes(h.Y); + result[2] = temp[0]; + result[3] = temp[1]; + temp = Half.GetBytes(h.Z); + result[4] = temp[0]; + result[5] = temp[1]; + temp = Half.GetBytes(h.W); + result[6] = temp[0]; + result[7] = temp[1]; + + return result; + } + + /// Converts an array of bytes into Half4. + /// A Half4 in it's byte[] representation. + /// The starting position within value. + /// A new Half4 instance. + public static Vector4h FromBytes(byte[] value, int startIndex) + { + Vector4h h4 = new Vector4h(); + h4.X = Half.FromBytes(value, startIndex); + h4.Y = Half.FromBytes(value, startIndex + 2); + h4.Z = Half.FromBytes(value, startIndex + 4); + h4.W = Half.FromBytes(value, startIndex + 6); + return h4; + } + + #endregion BitConverter + } +} + +// flibit Added This!!! +#pragma warning restore 3021 \ No newline at end of file