Browse files

Merge branch 'develop' into utf8

  • Loading branch information...
2 parents 1d890fd + 962a9f7 commit 9268b5ed7f22136343f95f8143452bdc968ebb47 @thefiddler thefiddler committed Jan 16, 2014
Showing with 7,406 additions and 1,392 deletions.
  1. +1 −0 .gitignore
  2. +1 −0 Source/Examples/OpenTK.Examples.csproj
  3. +81 −0 Source/Examples/OpenTK/Test/ExternalContext.cs
  4. +275 −121 Source/Examples/OpenTK/Test/GameWindowStates.cs
  5. +0 −2 Source/GLControl/X11GLControl.cs
  6. +51 −16 Source/OpenTK/Audio/OpenAL/Alc/Alc.cs
  7. +2 −2 Source/OpenTK/Configuration.cs
  8. +88 −97 Source/OpenTK/GameWindow.cs
  9. +71 −50 Source/OpenTK/Graphics/GraphicsContext.cs
  10. +166 −0 Source/OpenTK/Input/Buttons.cs
  11. +41 −0 Source/OpenTK/Input/ConfigurationType.cs
  12. +82 −32 Source/OpenTK/Input/GamePad.cs
  13. +11 −26 Source/OpenTK/Input/{GamePadAxis.cs → GamePadAxes.cs}
  14. +0 −68 Source/OpenTK/Input/GamePadButton.cs
  15. +216 −0 Source/OpenTK/Input/GamePadButtons.cs
  16. +395 −0 Source/OpenTK/Input/GamePadCapabilities.cs
  17. +204 −0 Source/OpenTK/Input/GamePadConfiguration.cs
  18. +132 −0 Source/OpenTK/Input/GamePadConfigurationDatabase.cs
  19. +58 −0 Source/OpenTK/Input/GamePadConfigurationItem.cs
  20. +72 −0 Source/OpenTK/Input/GamePadConfigurationSource.cs
  21. +72 −0 Source/OpenTK/Input/GamePadConfigurationTarget.cs
  22. +223 −0 Source/OpenTK/Input/GamePadDPad.cs
  23. +208 −2 Source/OpenTK/Input/GamePadState.cs
  24. +142 −0 Source/OpenTK/Input/GamePadThumbSticks.cs
  25. +136 −0 Source/OpenTK/Input/GamePadTriggers.cs
  26. +97 −0 Source/OpenTK/Input/GamePadType.cs
  27. +5 −11 Source/OpenTK/Input/IGamePadDriver.cs
  28. +1 −0 Source/OpenTK/Input/IInputDriver2.cs
  29. +42 −0 Source/OpenTK/Input/IJoystickDriver2.cs
  30. +92 −0 Source/OpenTK/Input/Joystick.cs
  31. +66 −0 Source/OpenTK/Input/JoystickAxis.cs
  32. +76 −0 Source/OpenTK/Input/JoystickButton.cs
  33. +156 −0 Source/OpenTK/Input/JoystickCapabilities.cs
  34. +3 −76 Source/OpenTK/Input/JoystickDevice.cs
  35. +260 −0 Source/OpenTK/Input/JoystickState.cs
  36. +4 −0 Source/OpenTK/Input/KeyboardDevice.cs
  37. +5 −0 Source/OpenTK/Input/KeyboardState.cs
  38. +5 −0 Source/OpenTK/Input/MouseState.cs
  39. +40 −0 Source/OpenTK/Math/MathHelper.cs
  40. +23 −2 Source/OpenTK/OpenTK.csproj
  41. +29 −17 Source/OpenTK/Platform/Dummy/DummyGLContext.cs
  42. +10 −0 Source/OpenTK/Platform/Factory.cs
  43. +2 −0 Source/OpenTK/Platform/IPlatformFactory.cs
  44. +3 −51 Source/OpenTK/Platform/MacOS/AglContext.cs
  45. +44 −1 Source/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs
  46. +63 −10 Source/OpenTK/Platform/MacOS/CarbonBindings/CoreFoundation.cs
  47. +37 −36 Source/OpenTK/Platform/MacOS/CarbonGLNative.cs
  48. +5 −0 Source/OpenTK/Platform/MacOS/CarbonInput.cs
  49. +659 −102 Source/OpenTK/Platform/MacOS/HIDInput.cs
  50. +6 −1 Source/OpenTK/Platform/MacOS/MacOSFactory.cs
  51. +92 −0 Source/OpenTK/Platform/MacOS/NS.cs
  52. +196 −0 Source/OpenTK/Platform/MappedGamePadDriver.cs
  53. +383 −11 Source/OpenTK/Platform/SDL2/Sdl2.cs
  54. +7 −2 Source/OpenTK/Platform/SDL2/Sdl2Factory.cs
  55. +11 −1 Source/OpenTK/Platform/SDL2/Sdl2GraphicsContext.cs
  56. +58 −1 Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs
  57. +540 −54 Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs
  58. +5 −2 Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs
  59. +27 −1 Source/OpenTK/Platform/Utilities.cs
  60. +19 −28 Source/OpenTK/Platform/Windows/API.cs
  61. +2 −2 Source/OpenTK/Platform/Windows/Bindings/Wgl.cs
  62. +44 −43 Source/OpenTK/Platform/Windows/WglHelper.cs
  63. +6 −1 Source/OpenTK/Platform/Windows/WinFactory.cs
  64. +13 −3 Source/OpenTK/Platform/Windows/WinGLContext.cs
  65. +374 −225 Source/OpenTK/Platform/Windows/WinGLNative.cs
  66. +314 −158 Source/OpenTK/Platform/Windows/WinGraphicsMode.cs
  67. +2 −0 Source/OpenTK/Platform/Windows/WinInputBase.cs
  68. +114 −18 Source/OpenTK/Platform/Windows/WinMMJoystick.cs
  69. +16 −1 Source/OpenTK/Platform/Windows/WinRawInput.cs
  70. +8 −2 Source/OpenTK/Platform/Windows/WinRawKeyboard.cs
  71. +10 −3 Source/OpenTK/Platform/Windows/WinRawMouse.cs
  72. +405 −0 Source/OpenTK/Platform/Windows/XInputJoystick.cs
  73. +14 −1 Source/OpenTK/Platform/X11/X11DisplayDevice.cs
  74. +6 −0 Source/OpenTK/Platform/X11/X11Factory.cs
  75. +157 −73 Source/OpenTK/Platform/X11/X11GLNative.cs
  76. +61 −12 Source/OpenTK/Platform/X11/X11GraphicsMode.cs
  77. +26 −18 Source/OpenTK/Platform/X11/X11Input.cs
  78. +34 −8 Source/OpenTK/Platform/X11/X11Joystick.cs
  79. +1 −1 Source/OpenTK/ToolkitOptions.cs
View
1 .gitignore
@@ -70,6 +70,7 @@ Binaries/
*.vspscc
*.vssscc
.builds
+*.pidb
# Visual C++ cache files
ipch/
View
1 Source/Examples/OpenTK.Examples.csproj
@@ -565,6 +565,7 @@
<None Include="..\..\Dependencies\x64\libSDL2.dylib">
<Link>Dependencies\x64\libSDL2.dylib</Link>
</None>
+ <Compile Include="OpenTK\Test\ExternalContext.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
View
81 Source/Examples/OpenTK/Test/ExternalContext.cs
@@ -0,0 +1,81 @@
+// This code was written for the OpenTK library and has been released
+// to the Public Domain.
+// It is provided "as is" without express or implied warranty of any kind.
+
+using System;
+using System.Runtime.InteropServices;
+using OpenTK;
+using OpenTK.Graphics;
+using OpenTK.Graphics.OpenGL;
+
+namespace Examples.Tests
+{
+ [Example("External Context Test", ExampleCategory.OpenTK, "OpenGL")]
+ class ExternalContext
+ {
+ public static void Main()
+ {
+ using (Toolkit.Init(new ToolkitOptions { Backend = PlatformBackend.PreferNative }))
+ {
+ var window = Sdl2.CreateWindow("Test", 0, 0, 640, 480, WindowFlags.AllowHighDpi | WindowFlags.OpenGL);
+ var context = Sdl2.CreateContext(window);
+ Sdl2.MakeCurrent(window, context);
+
+ using (var dummy = new GraphicsContext(new ContextHandle(context), OpenTK.Platform.Utilities.CreateDummyWindowInfo()))
+ {
+ for (int i = 0; i < 100; i++)
+ {
+ Sdl2.PumpEvents();
+ GL.ClearColor(i / 100.0f, i / 100.0f, i / 100.0f, i / 100.0f);
+ GL.Clear(ClearBufferMask.ColorBufferBit);
+
+ Sdl2.SwapWindow(window);
+ }
+
+ Sdl2.DestroyWindow(window);
+ }
+ }
+ }
+ }
+
+ #region SDL2 bindings
+
+ public enum WindowFlags
+ {
+ Default = 0,
+ OpenGL = 0x00000002,
+ AllowHighDpi = 0x00002000,
+ }
+
+ static class Sdl2
+ {
+ const string lib = "SDL2.dll";
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindow", ExactSpelling = true)]
+ public static extern IntPtr CreateWindow(string title, int x, int y, int w, int h, WindowFlags flags);
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_CreateContext", ExactSpelling = true)]
+ public static extern IntPtr CreateContext(IntPtr window);
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_DestroyWindow", ExactSpelling = true)]
+ public static extern void DestroyWindow(IntPtr window);
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetCurrentContext", ExactSpelling = true)]
+ public static extern IntPtr GetCurrentContext();
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetProcAddress", ExactSpelling = true)]
+ public static extern IntPtr GetAddress(string name);
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_MakeCurrent", ExactSpelling = true)]
+ public static extern int MakeCurrent(IntPtr window, IntPtr context);
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_PumpEvents", ExactSpelling = true)]
+ public static extern void PumpEvents();
+
+ [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_SwapWindow", ExactSpelling = true)]
+ public static extern void SwapWindow(IntPtr window);
+ }
+
+ #endregion
+
+}
View
396 Source/Examples/OpenTK/Test/GameWindowStates.cs
@@ -25,9 +25,22 @@ public class GameWindowStates : GameWindow
int texture;
bool mouse_in_window = false;
bool viewport_changed = true;
- bool refresh_text = true;
- MouseState mouse, mouse_old;
- KeyboardState keyboard, keyboard_old;
+
+ // time drift
+ Stopwatch watch = new Stopwatch();
+ double update_time, render_time;
+
+ // timing information
+ double timestamp;
+ int update_count;
+ int update_fps;
+ int render_count;
+ int render_fps;
+
+ // position of moving objects on screen
+ double variable_update_timestep_pos = -1;
+ double variable_refresh_timestep_pos = -1;
+ double fixed_update_timestep_pos = -1;
public GameWindowStates()
: base(800, 600, GraphicsMode.Default)
@@ -36,24 +49,13 @@ public GameWindowStates()
Keyboard.KeyRepeat = true;
KeyDown += KeyDownHandler;
KeyPress += KeyPressHandler;
-
+
MouseEnter += delegate { mouse_in_window = true; };
MouseLeave += delegate { mouse_in_window = false; };
-
- Move += delegate { refresh_text = true; };
- Resize += delegate { refresh_text = true; };
- WindowBorderChanged += delegate { refresh_text = true; };
- WindowStateChanged += delegate { refresh_text = true; };
- FocusedChanged += delegate { refresh_text = true; };
+
Mouse.Move += MouseMoveHandler;
Mouse.ButtonDown += MouseButtonHandler;
Mouse.ButtonUp += MouseButtonHandler;
- foreach (var joystick in Joysticks)
- {
- joystick.Move += delegate { refresh_text = true; };
- joystick.ButtonDown += delegate { refresh_text = true; };
- joystick.ButtonUp += delegate { refresh_text = true; };
- }
}
private void KeyPressHandler(object sender, KeyPressEventArgs e)
@@ -94,18 +96,24 @@ void KeyDownHandler(object sender, KeyboardKeyEventArgs e)
case Key.KeypadMinus:
case Key.Minus: Size -= new Size(16, 16); break;
+
+ case Key.V:
+ VSync = VSync == VSyncMode.On ? VSyncMode.Off : VSyncMode.On;
+ break;
+
+ case Key.BracketLeft: TargetUpdateFrequency--; break;
+ case Key.BracketRight: TargetUpdateFrequency++; break;
+ case Key.Comma: TargetRenderFrequency--; break;
+ case Key.Period: TargetRenderFrequency++; break;
}
}
void MouseMoveHandler(object sender, MouseMoveEventArgs e)
{
- refresh_text = true;
}
void MouseButtonHandler(object sender, MouseButtonEventArgs e)
{
- refresh_text = true;
-
if (e.Button == MouseButton.Left && e.IsPressed)
{
CursorVisible = false;
@@ -116,142 +124,223 @@ static int Clamp(int val, int min, int max)
{
return val > max ? max : val < min ? min : val;
}
-
- static void DrawString(Graphics gfx, string str, int line)
+
+ static float DrawString(Graphics gfx, string str, int line)
{
- gfx.DrawString(str, TextFont, Brushes.White, new PointF(0, line * TextFont.Height));
+ return DrawString(gfx, str, line, 0);
}
- static void DrawString(Graphics gfx, string str, int line, float offset)
+ static float DrawString(Graphics gfx, string str, int line, float offset)
{
gfx.DrawString(str, TextFont, Brushes.White, new PointF(offset, line * TextFont.Height));
+ return offset + gfx.MeasureString(str, TextFont).Width;
}
- static void DrawKeyboard(Graphics gfx, KeyboardState keyboard, int line)
+ static int DrawKeyboards(Graphics gfx, int line)
{
- const string str = "Keys pressed:";
- float space = gfx.MeasureString(" ", TextFont).Width;
- float offset = gfx.MeasureString(str, TextFont).Width + space;
- DrawString(gfx, str, line);
- for (int i = 0; i < (int)Key.LastKey; i++)
+ line++;
+ DrawString(gfx, "Keyboard:", line++);
+ for (int i = 0; i < 4; i++)
{
- Key k = (Key)i;
- if (keyboard[k])
+ var state = OpenTK.Input.Keyboard.GetState(i);
+ if (state.IsConnected)
{
- string key = k.ToString();
- DrawString(gfx, key, line, offset);
- offset += gfx.MeasureString(key, TextFont).Width + space;
+ StringBuilder sb = new StringBuilder();
+ sb.Append(i);
+ sb.Append(": ");
+ for (int key_index = 0; key_index < (int)Key.LastKey; key_index++)
+ {
+ Key k = (Key)key_index;
+ if (state[k])
+ {
+ sb.Append(k);
+ sb.Append(" ");
+ }
+ }
+ DrawString(gfx, sb.ToString(), line++);
}
}
+ return line;
}
- static void DrawMouse(Graphics gfx, MouseState mouse, int line)
+ static int DrawMice(Graphics gfx, int line)
{
- const string str = "Buttons pressed:";
- float space = gfx.MeasureString(" ", TextFont).Width;
- float offset = gfx.MeasureString(str, TextFont).Width + space;
- DrawString(gfx, str, line);
- for (int i = 0; i < (int)MouseButton.LastButton; i++)
+ line++;
+ DrawString(gfx, "Mouse:", line++);
+ for (int i = 0; i < 4; i++)
{
- MouseButton b = (MouseButton)i;
- if (mouse[b])
+ var state = OpenTK.Input.Mouse.GetState(i);
+ if (state.IsConnected)
{
- string button = b.ToString();
- DrawString(gfx, button, line, offset);
- offset += gfx.MeasureString(button, TextFont).Width + space;
+ StringBuilder sb = new StringBuilder();
+ Vector3 pos = new Vector3(state.X, state.Y, state.WheelPrecise);
+ sb.Append(i);
+ sb.Append(": ");
+ sb.Append(pos);
+ for (int button_index = 0; button_index < (int)MouseButton.LastButton; button_index++)
+ {
+ MouseButton b = (MouseButton)button_index;
+ if (state[b])
+ {
+ sb.Append(b);
+ sb.Append(" ");
+ }
+ }
+ DrawString(gfx, sb.ToString(), line++);
}
}
+ return line;
}
- static void DrawJoysticks(Graphics gfx, IList<JoystickDevice> joysticks, int line)
+ static int DrawLegacyJoysticks(Graphics gfx, IList<JoystickDevice> joysticks, int line)
{
- float space = gfx.MeasureString(" ", TextFont).Width;
+ line++;
+ DrawString(gfx, "Legacy Joystick:", line++);
+ int joy_index = -1;
foreach (var joy in joysticks)
{
- string str = String.Format("Joystick '{0}': ", joy.Description);
- DrawString(gfx, str, line);
-
- float offset = 0;
- line++;
- for (int i = 0; i < joy.Axis.Count; i++)
+ joy_index++;
+ if (!String.IsNullOrEmpty(joy.Description))
{
- string axis = joy.Axis[i].ToString();
- DrawString(gfx, axis, line, offset);
- offset += gfx.MeasureString(axis, TextFont).Width + space;
+ StringBuilder sb = new StringBuilder();
+ sb.Append(joy_index);
+ sb.Append(": '");
+ sb.Append(joy.Description);
+ sb.Append("' ");
+
+ for (int i = 0; i < joy.Axis.Count; i++)
+ {
+ sb.Append(joy.Axis[i]);
+ sb.Append(" ");
+ }
+
+ for (int i = 0; i < joy.Button.Count; i++)
+ {
+ sb.Append(joy.Button[i]);
+ sb.Append(" ");
+ }
+ DrawString(gfx, sb.ToString(), line++);
}
+ }
+
+ return line;
+ }
- offset = 0;
+ protected override void OnUpdateFrame(FrameEventArgs e)
+ {
+ double clock_time = watch.Elapsed.TotalSeconds;
+ update_time += e.Time;
+ timestamp += e.Time;
+ update_count++;
+
+ using (Graphics gfx = Graphics.FromImage(TextBitmap))
+ {
+ int line = 0;
+
+ gfx.Clear(Color.Black);
+ gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
+
+ // OpenGL information
+ DrawString(gfx, GL.GetString(StringName.Renderer), line++);
+ DrawString(gfx, GL.GetString(StringName.Version), line++);
+ DrawString(gfx, Context.GraphicsMode.ToString(), line++);
+
+ // GameWindow information
+ line++;
+ DrawString(gfx, "GameWindow:", line++);
+ DrawString(gfx, String.Format("[1 - 4]:[5 - 7]: WindowState.{0}:WindowBorder.{1}",
+ this.WindowState, this.WindowBorder), line++);
+ DrawString(gfx, String.Format("[V]: VSync.{0}.", VSync), line++);
+ DrawString(gfx, String.Format("Bounds: {0}", Bounds), line++);
+ DrawString(gfx, String.Format("ClientRectangle: {0}", ClientRectangle), line++);
+ DrawString(gfx, String.Format("Mouse {0} and {1}. {2}.",
+ mouse_in_window ? "inside" : "outside",
+ CursorVisible ? "visible" : "hidden",
+ Focused ? "Focused" : "Not focused"), line++);
+ DrawString(gfx, String.Format("Mouse coordinates: {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.WheelPrecise)), line++);
+
+ // Timing information
line++;
- for (int i = 0; i < joy.Button.Count; i++)
+ DrawString(gfx, "Timing:", line++);
+ DrawString(gfx,
+ String.Format("Frequency: update {4} ({0:f2}/{1:f2}); render {5} ({2:f2}/{3:f2})",
+ UpdateFrequency, TargetUpdateFrequency,
+ RenderFrequency, TargetRenderFrequency,
+ update_fps, render_fps),
+ line++);
+ DrawString(gfx,
+ String.Format("Period: update {4:N4} ({0:f4}/{1:f4}); render {5:N4} ({2:f4}/{3:f4})",
+ UpdatePeriod, TargetUpdatePeriod,
+ RenderPeriod, TargetRenderPeriod,
+ 1.0 / update_fps, 1.0 / render_fps),
+ line++);
+ DrawString(gfx, String.Format("Time: update {0:f4}; render {1:f4}",
+ UpdateTime, RenderTime), line++);
+ DrawString(gfx, String.Format("Drift: clock {0:f4}; update {1:f4}; render {2:f4}",
+ clock_time, clock_time - update_time, clock_time - render_time), line++);
+ DrawString(gfx, String.Format("Text: {0}", TypedText.ToString()), line++);
+
+ if (timestamp >= 1)
{
- string button = joy.Button[i].ToString();
- DrawString(gfx, button, line, offset);
- offset += gfx.MeasureString(button, TextFont).Width + space;
+ timestamp -= 1;
+ update_fps = update_count;
+ render_fps = render_count;
+ update_count = 0;
+ render_count = 0;
+
}
- line++;
+ // Input information
+ line = DrawKeyboards(gfx, line);
+ line = DrawMice(gfx, line);
+ line = DrawJoysticks(gfx, line);
+ line = DrawLegacyJoysticks(gfx, Joysticks, line);
}
- }
-
- protected override void OnUpdateFrame(FrameEventArgs e)
- {;
- InputDriver.Poll();
- mouse = OpenTK.Input.Mouse.GetState();
- if (mouse != mouse_old)
- refresh_text = true;
- mouse_old = mouse;
+ fixed_update_timestep_pos += TargetUpdatePeriod;
+ variable_update_timestep_pos += e.Time;
+ if (fixed_update_timestep_pos >= 1)
+ fixed_update_timestep_pos -= 2;
+ if (variable_update_timestep_pos >= 1)
+ variable_update_timestep_pos -= 2;
+ }
- keyboard = OpenTK.Input.Keyboard.GetState();
- if (keyboard != keyboard_old)
- refresh_text = true;
- keyboard_old = keyboard;
+ int DrawJoysticks(Graphics gfx, int line)
+ {
+ line++;
+ DrawString(gfx, "GamePad:", line++);
+ for (int i = 0; i < 4; i++)
+ {
+ GamePadCapabilities caps = GamePad.GetCapabilities(i);
+ GamePadState state = GamePad.GetState(i);
+ if (state.IsConnected)
+ {
+ DrawString(gfx, String.Format("{0}: {1}", i, caps), line++);
+ DrawString(gfx, state.ToString(), line++);
+ }
+ }
- if (refresh_text)
+ line++;
+ DrawString(gfx, "Joystick:", line++);
+ for (int i = 0; i < 4; i++)
{
- refresh_text = false;
-
- using (Graphics gfx = Graphics.FromImage(TextBitmap))
+ JoystickCapabilities caps = Joystick.GetCapabilities(i);
+ JoystickState state = Joystick.GetState(i);
+ if (state.IsConnected)
{
- int line = 0;
-
- gfx.Clear(Color.Black);
- gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
-
- DrawString(gfx, Context.GraphicsMode.ToString(), line++);
-
- DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++);
- DrawString(gfx, String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), line++);
- DrawString(gfx, String.Format("Focused: {0}.", this.Focused), line++);
- DrawString(gfx, String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), line++);
- DrawString(gfx, String.Format("Mouse visible: {0}", CursorVisible), line++);
- DrawString(gfx, String.Format("Mouse position (absolute): {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel)), line++);
- DrawString(gfx, String.Format("Mouse position (relative): {0}", new Vector3(mouse.X, mouse.Y, mouse.WheelPrecise)), line++);
- DrawString(gfx, String.Format("Window.Bounds: {0}", Bounds), line++);
- DrawString(gfx, String.Format("Window.Location: {0}, Size: {1}", Location, Size), line++);
- DrawString(gfx, String.Format("Window: {{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height), line++);
- DrawString(gfx, String.Format("Window.ClientRectangle: {0}", ClientRectangle), line++);
- DrawString(gfx, TypedText.ToString(), line++);
- DrawKeyboard(gfx, keyboard, line++);
- DrawMouse(gfx, mouse, line++);
- DrawJoysticks(gfx, Joysticks, line++);
+ DrawString(gfx, String.Format("{0}: {1}", i, caps), line++);
+ DrawString(gfx, state.ToString(), line++);
}
}
- System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(
- new System.Drawing.Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
- System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, TextBitmap.Width, TextBitmap.Height, PixelFormat.Bgra,
- PixelType.UnsignedByte, data.Scan0);
- TextBitmap.UnlockBits(data);
+ return line;
}
-
protected override void OnLoad(EventArgs e)
{
- base.OnLoad(e);
-
+ watch.Start();
+
GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.Texture2D);
@@ -274,31 +363,96 @@ protected override void OnResize(EventArgs e)
protected override void OnRenderFrame(FrameEventArgs e)
{
- base.OnRenderFrame(e);
-
+ render_time += e.Time;
+ render_count++;
+
+ GL.Clear(ClearBufferMask.ColorBufferBit);
+
if (viewport_changed)
{
viewport_changed = false;
-
GL.Viewport(0, 0, Width, Height);
-
- Matrix4 ortho_projection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, -1, 1);
- GL.MatrixMode(MatrixMode.Projection);
- GL.LoadMatrix(ref ortho_projection);
}
- GL.Clear(ClearBufferMask.ColorBufferBit);
+ DrawText();
+
+ DrawMovingObjects();
- GL.Begin(BeginMode.Quads);
+ variable_refresh_timestep_pos += e.Time;
+ if (variable_refresh_timestep_pos >= 1)
+ variable_refresh_timestep_pos -= 2;
+ SwapBuffers();
+ }
+
+ // Uploads our text Bitmap to an OpenGL texture
+ // and displays is to screen.
+ private void DrawText()
+ {
+ System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits(
+ new System.Drawing.Rectangle(0, 0, TextBitmap.Width, TextBitmap.Height),
+ System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, TextBitmap.Width, TextBitmap.Height, PixelFormat.Bgra,
+ PixelType.UnsignedByte, data.Scan0);
+ TextBitmap.UnlockBits(data);
+
+ Matrix4 text_projection = Matrix4.CreateOrthographicOffCenter(0, Width, Height, 0, -1, 1);
+ GL.MatrixMode(MatrixMode.Projection);
+ GL.LoadMatrix(ref text_projection);
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadIdentity();
+
+ GL.Color4(Color4.White);
+ GL.Enable(EnableCap.Texture2D);
+ GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
GL.TexCoord2(1, 0); GL.Vertex2(TextBitmap.Width, 0);
GL.TexCoord2(1, 1); GL.Vertex2(TextBitmap.Width, TextBitmap.Height);
GL.TexCoord2(0, 1); GL.Vertex2(0, TextBitmap.Height);
-
GL.End();
+ GL.Disable(EnableCap.Texture2D);
+ }
- SwapBuffers();
+ // Draws three moving objects, using three different timing methods:
+ // 1. fixed framerate based on TargetUpdatePeriod
+ // 2. variable framerate based on UpdateFrame e.Time
+ // 3. variable framerate based on RenderFrame e.Time
+ // If the timing implementation is correct, all three objects
+ // should be moving at the same speed, regardless of the current
+ // UpdatePeriod and RenderPeriod.
+ void DrawMovingObjects()
+ {
+ Matrix4 thing_projection = Matrix4.CreateOrthographic(2, 2, -1, 1);
+ GL.MatrixMode(MatrixMode.Projection);
+ GL.LoadMatrix(ref thing_projection);
+
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadIdentity();
+ GL.Translate(fixed_update_timestep_pos, -0.2, 0);
+ GL.Color4(Color4.Red);
+ DrawRectangle();
+
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadIdentity();
+ GL.Translate(variable_update_timestep_pos, -0.4, 0);
+ GL.Color4(Color4.DarkGoldenrod);
+ DrawRectangle();
+
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadIdentity();
+ GL.Translate(variable_refresh_timestep_pos, -0.8, 0);
+ GL.Color4(Color4.DarkGreen);
+ DrawRectangle();
+ }
+
+ private void DrawRectangle()
+ {
+ GL.Begin(PrimitiveType.Quads);
+ GL.Vertex2(-0.05, -0.05);
+ GL.Vertex2(+0.05, -0.05);
+ GL.Vertex2(+0.05, +0.05);
+ GL.Vertex2(-0.05, +0.05);
+ GL.End();
}
public static void Main()
View
2 Source/GLControl/X11GLControl.cs
@@ -76,8 +76,6 @@ internal X11GLControl(GraphicsMode mode, Control control)
throw new ArgumentNullException("mode");
if (control == null)
throw new ArgumentNullException("control");
- if (!mode.Index.HasValue)
- throw new GraphicsModeException("Invalid or unsupported GraphicsMode.");
this.mode = mode;
View
67 Source/OpenTK/Audio/OpenAL/Alc/Alc.cs
@@ -9,6 +9,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
@@ -262,7 +263,13 @@ public static IntPtr GetContextsDevice(ContextHandle context)
/// <returns>A string containing the name of the Device.</returns>
public static string GetString(IntPtr device, AlcGetString param)
{
- return Marshal.PtrToStringAnsi(GetStringPrivate(device, param));
+ IntPtr pstr = GetStringPrivate(device, param);
+ string str = String.Empty;
+ if (pstr != IntPtr.Zero)
+ {
+ str = Marshal.PtrToStringAnsi(pstr);
+ }
+ return str;
}
/// <summary>This function returns a List of strings related to the context.</summary>
@@ -277,26 +284,54 @@ public static string GetString(IntPtr device, AlcGetString param)
public static IList<string> GetString(IntPtr device, AlcGetStringList param)
{
List<string> result = new List<string>();
- IntPtr t = GetStringPrivate(IntPtr.Zero, (AlcGetString)param);
- System.Text.StringBuilder sb = new System.Text.StringBuilder();
- byte b;
- int offset = 0;
- do
+
+ // We cannot use Marshal.PtrToStringAnsi(),
+ // because alcGetString is defined to return either a nul-terminated string,
+ // or an array of nul-terminated strings terminated by an extra nul.
+ // Marshal.PtrToStringAnsi() will fail in the latter case (it will only
+ // return the very first string in the array.)
+ // We'll have to marshal this ourselves.
+ IntPtr t = GetStringPrivate(device, (AlcGetString)param);
+ if (t != IntPtr.Zero)
{
- b = Marshal.ReadByte(t, offset++);
- if (b != 0)
- sb.Append((char)b);
- if (b == 0)
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ byte b;
+ int offset = 0;
+ do
{
- result.Add(sb.ToString());
- if (Marshal.ReadByte(t, offset) == 0) // offset already properly increased through ++
- break; // 2x null
+ b = Marshal.ReadByte(t, offset++);
+ if (b != 0)
+ {
+ sb.Append((char)b);
+ }
else
- sb.Remove(0, sb.Length); // 1x null
+ {
+ // One string from the array is complete
+ result.Add(sb.ToString());
+
+ // Check whether the array has finished
+ // Note: offset already been increased through offset++ above
+ if (Marshal.ReadByte(t, offset) == 0)
+ {
+ // 2x consecutive nuls, we've read the whole array
+ break;
+ }
+ else
+ {
+ // Another string is starting, clear the StringBuilder
+ sb.Remove(0, sb.Length);
+ }
+ }
}
- } while (true);
+ while (true);
+ }
+ else
+ {
+ Debug.Print("[Audio] Alc.GetString({0}, {1}) returned null.",
+ device, param);
+ }
- return (IList<string>)result;
+ return result;
}
[DllImport(Alc.Lib, EntryPoint = "alcGetIntegerv", ExactSpelling = true, CallingConvention = Alc.Style, CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity()]
View
4 Source/OpenTK/Configuration.cs
@@ -206,8 +206,8 @@ static bool DetectSdl2()
{
if (!OpenTK.Platform.SDL2.SDL.WasInit(0))
{
- var flags = OpenTK.Platform.SDL2.SystemFlags.EVERYTHING;
- flags &= ~OpenTK.Platform.SDL2.SystemFlags.AUDIO;
+ var flags =
+ OpenTK.Platform.SDL2.SystemFlags.VIDEO | Platform.SDL2.SystemFlags.TIMER;
if (OpenTK.Platform.SDL2.SDL.Init(flags) == 0)
{
supported = true;
View
185 Source/OpenTK/GameWindow.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
//
// The Open Toolkit Library License
//
@@ -75,20 +75,29 @@ public class GameWindow : NativeWindow, IGameWindow, IDisposable
{
#region --- Fields ---
- object exit_lock = new object();
+ const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
+
+ readonly Stopwatch watch = new Stopwatch();
IGraphicsContext glContext;
bool isExiting = false;
double update_period, render_period;
double target_update_period, target_render_period;
- // TODO: Implement these:
- double update_time, render_time;
+
+ double update_time; // length of last UpdateFrame event
+ double render_time; // length of last RenderFrame event
+
+ double update_timestamp; // timestamp of last UpdateFrame event
+ double render_timestamp; // timestamp of last RenderFrame event
+
+ double update_epsilon; // quantization error for UpdateFrame events
+
+ bool is_running_slowly; // true, when UpdatePeriod cannot reach TargetUpdatePeriod
+
VSyncMode vsync;
- Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch();
- double next_render = 0.0, next_update = 0.0;
FrameEventArgs update_args = new FrameEventArgs();
FrameEventArgs render_args = new FrameEventArgs();
@@ -404,8 +413,7 @@ public void Run(double updates_per_second, double frames_per_second)
//Resize += DispatchUpdateAndRenderFrame;
Debug.Print("Entering main loop.");
- update_watch.Start();
- render_watch.Start();
+ watch.Start();
while (true)
{
ProcessEvents();
@@ -429,101 +437,84 @@ public void Run(double updates_per_second, double frames_per_second)
}
}
- void DispatchUpdateAndRenderFrame(object sender, EventArgs e)
+ double ClampElapsed(double elapsed)
{
- RaiseUpdateFrame(update_watch, ref next_update, update_args);
- RaiseRenderFrame(render_watch, ref next_render, render_args);
+ return MathHelper.Clamp(elapsed, 0.0, 1.0);
}
- void RaiseUpdateFrame(Stopwatch update_watch, ref double next_update, FrameEventArgs update_args)
+ void DispatchUpdateAndRenderFrame(object sender, EventArgs e)
{
- int num_updates = 0;
- double total_update_time = 0;
+ int is_running_slowly_retries = 4;
+ double timestamp = watch.Elapsed.TotalSeconds;
+ double elapsed = 0;
- // Cap the maximum time drift to 1 second (e.g. when the process is suspended).
- double time = update_watch.Elapsed.TotalSeconds;
- if (time <= 0)
+ elapsed = ClampElapsed(timestamp - update_timestamp);
+ while (elapsed > 0 && elapsed + update_epsilon >= TargetUpdatePeriod)
{
- // Protect against negative Stopwatch.Elapsed values.
- // See http://connect.microsoft.com/VisualStudio/feedback/details/94083/stopwatch-returns-negative-elapsed-time
- update_watch.Reset();
- update_watch.Start();
- return;
- }
- if (time > 1.0)
- time = 1.0;
+ RaiseUpdateFrame(elapsed, ref timestamp);
+
+ // Calculate difference (positive or negative) between
+ // actual elapsed time and target elapsed time. We must
+ // compensate for this difference.
+ update_epsilon += elapsed - TargetUpdatePeriod;
- // Raise UpdateFrame events until we catch up with our target update rate.
- while (next_update - time <= 0 && time > 0)
- {
- next_update -= time;
- update_args.Time = time;
- OnUpdateFrameInternal(update_args);
- time = update_time = Math.Max(update_watch.Elapsed.TotalSeconds, 0) - time;
- // Stopwatches are not accurate over long time periods.
- // We accumulate the total elapsed time into the time variable
- // while reseting the Stopwatch frequently.
- update_watch.Reset();
- update_watch.Start();
-
- // Don't schedule a new update more than 1 second in the future.
- // Sometimes the hardware cannot keep up with updates
- // (e.g. when the update rate is too high, or the UpdateFrame processing
- // is too costly). This cap ensures we can catch up in a reasonable time
- // once the load becomes lighter.
- next_update += TargetUpdatePeriod;
- next_update = Math.Max(next_update, -1.0);
-
- total_update_time += update_time;
-
- // Allow up to 10 consecutive UpdateFrame events to prevent the
- // application from "hanging" when the hardware cannot keep up
- // with the requested update rate.
- if (++num_updates >= 10 || TargetUpdateFrequency == 0.0)
+ // Prepare for next loop
+ elapsed = ClampElapsed(timestamp - update_timestamp);
+
+ if (TargetUpdatePeriod <= Double.Epsilon)
+ {
+ // According to the TargetUpdatePeriod documentation,
+ // a TargetUpdatePeriod of zero means we will raise
+ // UpdateFrame events as fast as possible (one event
+ // per ProcessEvents() call)
break;
+ }
+
+ is_running_slowly = update_epsilon >= TargetUpdatePeriod;
+ if (is_running_slowly && --is_running_slowly_retries == 0)
+ {
+ // If UpdateFrame consistently takes longer than TargetUpdateFrame
+ // stop raising events to avoid hanging inside the UpdateFrame loop.
+ break;
+ }
}
- // Calculate statistics
- if (num_updates > 0)
+ elapsed = ClampElapsed(timestamp - render_timestamp);
+ if (elapsed > 0 && elapsed >= TargetRenderPeriod)
{
- update_period = total_update_time / (double)num_updates;
+ RaiseRenderFrame(elapsed, ref timestamp);
}
}
- void RaiseRenderFrame(Stopwatch render_watch, ref double next_render, FrameEventArgs render_args)
+ void RaiseUpdateFrame(double elapsed, ref double timestamp)
{
- // Cap the maximum time drift to 1 second (e.g. when the process is suspended).
- double time = render_watch.Elapsed.TotalSeconds;
- if (time <= 0)
- {
- // Protect against negative Stopwatch.Elapsed values.
- // See http://connect.microsoft.com/VisualStudio/feedback/details/94083/stopwatch-returns-negative-elapsed-time
- render_watch.Reset();
- render_watch.Start();
- return;
- }
- if (time > 1.0)
- time = 1.0;
- double time_left = next_render - time;
+ // Raise UpdateFrame event
+ update_args.Time = elapsed;
+ OnUpdateFrameInternal(update_args);
- if (time_left <= 0.0 && time > 0)
- {
- // Schedule next render event. The 1 second cap ensures
- // the process does not appear to hang.
- next_render = time_left + TargetRenderPeriod;
- if (next_render < -1.0)
- next_render = -1.0;
+ // Update UpdatePeriod/UpdateFrequency properties
+ update_period = elapsed;
- render_watch.Reset();
- render_watch.Start();
+ // Update UpdateTime property
+ update_timestamp = timestamp;
+ timestamp = watch.Elapsed.TotalSeconds;
+ update_time = timestamp - update_timestamp;
+ }
- if (time > 0)
- {
- render_period = render_args.Time = time;
- OnRenderFrameInternal(render_args);
- render_time = render_watch.Elapsed.TotalSeconds;
- }
- }
+
+ void RaiseRenderFrame(double elapsed, ref double timestamp)
+ {
+ // Raise RenderFrame event
+ render_args.Time = elapsed;
+ OnRenderFrameInternal(render_args);
+
+ // Update RenderPeriod/UpdateFrequency properties
+ render_period = elapsed;
+
+ // Update RenderTime property
+ render_timestamp = timestamp;
+ timestamp = watch.Elapsed.TotalSeconds;
+ render_time = timestamp - render_timestamp;
}
#endregion
@@ -692,7 +683,7 @@ protected set
/// </summary>
/// <remarks>
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
- /// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
+ /// <para>Values lower than 1.0Hz are clamped to 0.0. Values higher than 500.0Hz are clamped to 200.0Hz.</para>
/// </remarks>
public double TargetRenderFrequency
{
@@ -710,11 +701,11 @@ public double TargetRenderFrequency
{
TargetRenderPeriod = 0.0;
}
- else if (value <= 200.0)
+ else if (value <= MaxFrequency)
{
TargetRenderPeriod = 1.0 / value;
}
- else Debug.Print("Target render frequency clamped to 200.0Hz."); // TODO: Where is it actually performed?
+ else Debug.Print("Target render frequency clamped to {0}Hz.", MaxFrequency);
}
}
@@ -727,7 +718,7 @@ public double TargetRenderFrequency
/// </summary>
/// <remarks>
/// <para>A value of 0.0 indicates that RenderFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
- /// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
+ /// <para>Values lower than 0.002 seconds (500Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
/// </remarks>
public double TargetRenderPeriod
{
@@ -739,7 +730,7 @@ public double TargetRenderPeriod
set
{
EnsureUndisposed();
- if (value <= 0.005)
+ if (value <= 1 / MaxFrequency)
{
target_render_period = 0.0;
}
@@ -760,7 +751,7 @@ public double TargetRenderPeriod
/// </summary>
/// <remarks>
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
- /// <para>Values lower than 1.0Hz are clamped to 1.0Hz. Values higher than 200.0Hz are clamped to 200.0Hz.</para>
+ /// <para>Values lower than 1.0Hz are clamped to 0.0. Values higher than 500.0Hz are clamped to 500.0Hz.</para>
/// </remarks>
public double TargetUpdateFrequency
{
@@ -778,11 +769,11 @@ public double TargetUpdateFrequency
{
TargetUpdatePeriod = 0.0;
}
- else if (value <= 200.0)
+ else if (value <= MaxFrequency)
{
TargetUpdatePeriod = 1.0 / value;
}
- else Debug.Print("Target update frequency clamped to 200.0Hz."); // TODO: Where is it actually performed?
+ else Debug.Print("Target render frequency clamped to {0}Hz.", MaxFrequency);
}
}
@@ -795,7 +786,7 @@ public double TargetUpdateFrequency
/// </summary>
/// <remarks>
/// <para>A value of 0.0 indicates that UpdateFrame events are generated at the maximum possible frequency (i.e. only limited by the hardware's capabilities).</para>
- /// <para>Values lower than 0.005 seconds (200Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
+ /// <para>Values lower than 0.002 seconds (500Hz) are clamped to 0.0. Values higher than 1.0 seconds (1Hz) are clamped to 1.0.</para>
/// </remarks>
public double TargetUpdatePeriod
{
@@ -807,15 +798,15 @@ public double TargetUpdatePeriod
set
{
EnsureUndisposed();
- if (value <= 0.005)
+ if (value <= 1 / MaxFrequency)
{
target_update_period = 0.0;
}
else if (value <= 1.0)
{
target_update_period = value;
}
- else Debug.Print("Target update period clamped to 1.0 seconds."); // TODO: Where is it actually performed?
+ else Debug.Print("Target update period clamped to 1.0 seconds.");
}
}
@@ -1101,4 +1092,4 @@ public enum VSyncMode
}
#endregion
-}
+}
View
121 Source/OpenTK/Graphics/GraphicsContext.cs
@@ -39,14 +39,13 @@ namespace OpenTK.Graphics
/// </summary>
public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal
{
+ public delegate IntPtr GetAddressDelegate(string function);
+ public delegate ContextHandle GetCurrentContextDelegate();
+
#region --- Fields ---
IGraphicsContext implementation; // The actual render context implementation for the underlying platform.
bool disposed;
- // Indicates that this context was created through external means, e.g. Tao.Sdl or GLWidget#.
- // In this case, We'll assume that the external program will manage the lifetime of this
- // context - we'll not destroy it manually.
- readonly bool IsExternal;
bool check_errors = true;
// Cache for the context handle. We need this for RemoveContext()
// in case the user does not call Dispose(). When this happens,
@@ -67,17 +66,6 @@ public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal
#region --- Constructors ---
- // Necessary to allow creation of dummy GraphicsContexts (see CreateDummyContext static method).
- GraphicsContext(ContextHandle handle)
- {
- implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
-
- lock (SyncRoot)
- {
- AddContext(this);
- }
- }
-
/// <summary>
/// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window.
/// </summary>
@@ -164,54 +152,81 @@ public GraphicsContext(GraphicsMode mode, IWindowInfo window, int major, int min
}
/// <summary>
- /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
+ /// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using
+ /// an external context handle that was created by a third-party library.
/// </summary>
- /// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
- /// <param name="window">The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo.</param>
- /// <exception cref="GraphicsContextException">Occurs if handle is identical to a context already registered with OpenTK.</exception>
- public GraphicsContext(ContextHandle handle, IWindowInfo window)
- : this(handle, window, null, 1, 0, GraphicsContextFlags.Default)
- { }
-
- /// <summary>
- /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
- /// </summary>
- /// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
- /// <param name="window">The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo.</param>
- /// <param name="shareContext">A different context that shares resources with this instance, if any.
- /// Pass null if the context is not shared or if this is the first GraphicsContext instruct you construct.</param>
- /// <param name="major">The major version of the context (e.g. "2" for "2.1").</param>
- /// <param name="minor">The minor version of the context (e.g. "1" for "2.1").</param>
- /// <param name="flags">A bitwise combination of <see cref="GraphicsContextFlags"/> that describe this context.</param>
- /// <exception cref="GraphicsContextException">Occurs if handle is identical to a context already registered with OpenTK.</exception>
- public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
- : this(handle)
+ /// <param name="handle">
+ /// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context.
+ /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before.
+ /// </param>
+ /// <param name="getAddress">
+ /// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns
+ /// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be
+ /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with
+ /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function
+ /// pointers.)
+ /// </param>
+ /// <param name="getCurrent">
+ /// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context,
+ /// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented
+ /// using the same toolkit that created the OpenGL context (i.e. if the context was created with
+ /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve
+ /// the current context.)
+ /// </param>
+ public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent)
{
+ if (getAddress == null || getCurrent == null)
+ throw new ArgumentNullException();
+
lock (SyncRoot)
{
- IsExternal = true;
-
+ // Replace a zero-handle by the current context, if any
if (handle == ContextHandle.Zero)
{
- implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
+ handle = getCurrent();
}
- else if (available_contexts.ContainsKey(handle))
+
+ // Make sure this handle corresponds to a valid, unique OpenGL context
+ if (handle == ContextHandle.Zero)
{
- throw new GraphicsContextException("Context already exists.");
+ throw new GraphicsContextMissingException();
}
- else
+ else if (available_contexts.ContainsKey(handle))
{
- switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
- {
- case false: implementation = Factory.Default.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break;
- case true: implementation = Factory.Embedded.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break;
- }
+ throw new InvalidOperationException("Context handle has already been added");
}
- (this as IGraphicsContextInternal).LoadAll();
+ // We have a valid handle for an external OpenGL context, wrap it into a
+ // DummyGLContext instance.
+ implementation = new Platform.Dummy.DummyGLContext(handle, getAddress);
+ GetCurrentContext = getCurrent ?? GetCurrentContext;
+ AddContext(this);
}
+ implementation.LoadAll();
}
+ /// <summary>
+ /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
+ /// </summary>
+ /// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
+ /// <param name="window">This parameter is reserved.</param>
+ public GraphicsContext(ContextHandle handle, IWindowInfo window)
+ : this(handle, window, null, 1, 0, GraphicsContextFlags.Default)
+ { }
+
+ /// <summary>
+ /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
+ /// </summary>
+ /// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
+ /// <param name="window">This parameter is reserved.</param>
+ /// <param name="shareContext">This parameter is reserved.</param>
+ /// <param name="major">This parameter is reserved.</param>
+ /// <param name="minor">This parameter is reserved.</param>
+ /// <param name="flags">This parameter is reserved..</param>
+ public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
+ : this(handle, Platform.Utilities.CreateGetAddress(), Factory.Default.CreateGetCurrentGraphicsContext())
+ { }
+
#endregion
#region Public Members
@@ -309,6 +324,7 @@ static IGraphicsContext FindSharedContext()
/// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para>
/// <para>This method requires that a context is current on the calling thread.</para>
/// </remarks>
+ [Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")]
public static GraphicsContext CreateDummyContext()
{
ContextHandle handle = GetCurrentContext();
@@ -326,12 +342,13 @@ public static GraphicsContext CreateDummyContext()
/// <remarks>
/// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para>
/// </remarks>
+ [Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")]
public static GraphicsContext CreateDummyContext(ContextHandle handle)
{
if (handle == ContextHandle.Zero)
throw new ArgumentOutOfRangeException("handle");
- return new GraphicsContext(handle);
+ return new GraphicsContext(handle, (IWindowInfo)null);
}
#endregion
@@ -352,7 +369,6 @@ public static void Assert()
#region public static IGraphicsContext CurrentContext
- internal delegate ContextHandle GetCurrentContextDelegate();
internal static GetCurrentContextDelegate GetCurrentContext;
/// <summary>
@@ -628,6 +644,11 @@ void Dispose(bool manual)
}
}
+ /// <summary>
+ /// Marks this context as deleted, but does not actually release unmanaged resources
+ /// due to the threading requirements of OpenGL. Use <see cref="GraphicsContext.Dispose"/>
+ /// instead.
+ /// </summary>
~GraphicsContext()
{
Dispose(false);
View
166 Source/OpenTK/Input/Buttons.cs
@@ -0,0 +1,166 @@
+//
+// GamePadButton.cs
+//
+// Author:
+// robert <${AuthorEmail}>
+//
+// Copyright (c) 2012 robert
+//
+// 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.
+using System;
+
+namespace OpenTK.Input
+{
+ /// <summary>
+ /// Enumerates available buttons for a <c>GamePad</c> device.
+ /// </summary>
+ [Flags]
+ public enum Buttons
+ {
+ /// <summary>
+ /// DPad up direction button
+ /// </summary>
+ DPadUp = 1 << 0,
+
+ /// <summary>
+ /// DPad down direction button
+ /// </summary>
+ DPadDown = 1 << 1,
+
+ /// <summary>
+ /// DPad left direction button
+ /// </summary>
+ DPadLeft = 1 << 2,
+
+ /// <summary>
+ /// DPad right direction button
+ /// </summary>
+ DPadRight = 1 << 3,
+
+ /// <summary>
+ /// Start button
+ /// </summary>
+ Start = 1 << 4,
+
+ /// <summary>
+ /// Back button
+ /// </summary>
+ Back = 1 << 5,
+
+ /// <summary>
+ /// Left stick button
+ /// </summary>
+ LeftStick = 1 << 6,
+
+ /// <summary>
+ /// Right stick button
+ /// </summary>
+ RightStick = 1 << 7,
+
+ /// <summary>
+ /// Left shoulder button
+ /// </summary>
+ LeftShoulder = 1 << 8,
+
+ /// <summary>
+ /// Right shoulder button
+ /// </summary>
+ RightShoulder = 1 << 9,
+
+ /// <summary>
+ /// Home button
+ /// </summary>
+ Home = 1 << 11,
+
+ /// <summary>
+ /// Home button
+ /// </summary>
+ BigButton = Home,
+
+ /// <summary>
+ /// A button
+ /// </summary>
+ A = 1 << 12,
+
+ /// <summary>
+ /// B button
+ /// </summary>
+ B = 1 << 13,
+
+ /// <summary>
+ /// X button
+ /// </summary>
+ X = 1 << 14,
+
+ /// <summary>
+ /// Y button
+ /// </summary>
+ Y = 1 << 15,
+
+ /// <summary>
+ /// Left thumbstick left direction button
+ /// </summary>
+ LeftThumbstickLeft = 1 << 21,
+
+ /// <summary>
+ /// Right trigger button
+ /// </summary>
+ RightTrigger = 1 << 22,
+
+ /// <summary>
+ /// Left trigger button
+ /// </summary>
+ LeftTrigger = 1 << 23,
+
+ /// <summary>
+ /// Right thumbstick up direction button
+ /// </summary>
+ RightThumbstickUp = 1 << 24,
+
+ /// <summary>
+ /// Right thumbstick down direction button
+ /// </summary>
+ RightThumbstickDown = 1 << 25,
+
+ /// <summary>
+ /// Right stick right direction button
+ /// </summary>
+ RightThumbstickRight = 1 << 26,
+
+ /// <summary>
+ /// Right stick left direction button
+ /// </summary>
+ RightThumbstickLeft = 1 << 27,
+
+ /// <summary>
+ /// Left stick up direction button
+ /// </summary>
+ LeftThumbstickUp = 1 << 28,
+
+ /// <summary>
+ /// Left stick down direction button
+ /// </summary>
+ LeftThumbstickDown = 1 << 29,
+
+ /// <summary>
+ /// Left stick right direction button
+ /// </summary>
+ LeftThumbstickRight = 1 << 30,
+ }
+}
View
41 Source/OpenTK/Input/ConfigurationType.cs
@@ -0,0 +1,41 @@
+#region License
+//
+// ConfigurationType.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// 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;
+
+namespace OpenTK.Input
+{
+ enum ConfigurationType
+ {
+ Unmapped = 0,
+ Axis,
+ Button
+ }
+}
+
View
114 Source/OpenTK/Input/GamePad.cs
@@ -1,46 +1,96 @@
- #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
+#region License
+//
+// GamePad.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// 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;
namespace OpenTK.Input
{
/// <summary>
- /// Provides access to GamePad devices. Note: this API is not implemented yet.
+ /// Provides access to GamePad devices.
+ /// A GamePad device offers a well-defined layout with
+ /// one direction-pad, two thumbsticks, two triggers,
+ /// four main buttons (A, B, X, Y) and up to seven
+ /// auxilliary buttons.
+ /// Use <c>GetCapabilities</c> to retrieve the exact
+ /// capabilities of a given device.
+ /// Use <c>GetState</c> to retrieve the current state
+ /// of a given device.
/// </summary>
- public class GamePad
+ public sealed class GamePad
{
- #region Constructors
+ internal const int MaxAxisCount = 10;
+ internal const int MaxDPadCount = 2;
- static GamePad()
+ static readonly IGamePadDriver driver =
+ Platform.Factory.Default.CreateGamePadDriver();
+
+ private GamePad() { }
+
+ /// <summary>
+ /// Retrieves a <c>GamePadCapabilities</c> structure describing the
+ /// capabilities of a gamepad device.
+ /// </summary>
+ /// <param name="index">The zero-based index of a gamepad device.</param>
+ /// <returns>A <c>GamePadCapabilities</c> structure describing the capabilities of the gamepad device.</returns>
+ public static GamePadCapabilities GetCapabilities(int index)
+ {
+ if (index < 0)
+ throw new IndexOutOfRangeException();
+
+ return driver.GetCapabilities(index);
+ }
+
+ /// <summary>
+ /// Retrieves the <c>GamePadState</c> for the specified gamepad device.
+ /// </summary>
+ /// <param name="index">The zero-based index of a gamepad device.</param>
+ /// <returns>A <c>GamePadState</c> structure describing the state of the gamepad device.</returns>
+ public static GamePadState GetState(int index)
{
- throw new NotImplementedException();
+ return driver.GetState(index);
}
- #endregion
+ /// <summary>
+ /// Sets the vibration intensity for the left and right motors of this <see cref="GamePad"/>
+ /// </summary>
+ /// <returns>
+ /// <c>true</c>, if vibration was set, <c>false</c> otherwise. This method can return false
+ /// if the <c>GamePad</c> hardware does not support vibration or if it cannot respond to
+ /// the command for any reason. Do not loop until this becomes true, but rather ignore
+ /// a return value of false.
+ /// </returns>
+ /// <param name="index">A zero-based device index for the <c>GamePad</c> device to affect</param>
+ /// <param name="left">The vibration intensity for the left motor, between 0.0 and 1.0.</param>
+ /// <param name="right">The vibration intensity for the right motor, between 0.0 and 1.0.</param>
+ public static bool SetVibration(int index, float left, float right)
+ {
+ return driver.SetVibration(index, left, right);
+ }
}
}
View
37 Source/OpenTK/Input/GamePadAxis.cs → Source/OpenTK/Input/GamePadAxes.cs
@@ -25,32 +25,17 @@
// THE SOFTWARE.
using System;
-namespace OpenTK
+namespace OpenTK.Input
{
- public enum GamePadAxis
- {
- /// <summary>The first axis of the gamepad.</summary>
- Axis0 = 0,
- /// <summary>The second axis of the gamepad.</summary>
- Axis1,
- /// <summary>The third axis of the gamepad.</summary>
- Axis2,
- /// <summary>The fourth axis of the gamepad.</summary>
- Axis3,
- /// <summary>The fifth axis of the gamepad.</summary>
- Axis4,
- /// <summary>The sixth axis of the gamepad.</summary>
- Axis5,
- /// <summary>The seventh axis of the gamepad.</summary>
- Axis6,
- /// <summary>The eighth axis of the gamepad.</summary>
- Axis7,
- /// <summary>The ninth axis of the gamepad.</summary>
- Axis8,
- /// <summary>The tenth axis of the gamepad.</summary>
- Axis9,
- /// <summary>The last axis of the gamepad.</summary>
- LastAxis
- }
+ [Flags]
+ internal enum GamePadAxes : byte
+ {
+ LeftX = 1 << 0,
+ LeftY = 1 << 1,
+ LeftTrigger = 1 << 2,
+ RightX = 1 << 3,
+ RightY = 1 << 4,
+ RightTrigger = 1 << 5,
+ }
}
View
68 Source/OpenTK/Input/GamePadButton.cs
@@ -1,68 +0,0 @@
-//
-// GamePadButton.cs
-//
-// Author:
-// robert <${AuthorEmail}>
-//
-// Copyright (c) 2012 robert
-//
-// 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.
-using System;
-
-namespace OpenTK
-{
- public enum GamePadButton
- {
- /// <summary>The first button of the gamepad.</summary>
- Button0 = 0,
- /// <summary>The second button of the gamepad.</summary>
- Button1,
- /// <summary>The third button of the gamepad.</summary>
- Button2,
- /// <summary>The fourth button of the gamepad.</summary>
- Button3,
- /// <summary>The fifth button of the gamepad.</summary>
- Button4,
- /// <summary>The sixth button of the gamepad.</summary>
- Button5,
- /// <summary>The seventh button of the gamepad.</summary>
- Button6,
- /// <summary>The eighth button of the gamepad.</summary>
- Button7,
- /// <summary>The ninth button of the gamepad.</summary>
- Button8,
- /// <summary>The tenth button of the gamepad.</summary>
- Button9,
- /// <summary>The eleventh button of the gamepad.</summary>
- Button10,
- /// <summary>The twelfth button of the gamepad.</summary>
- Button11,
- /// <summary>The thirteenth button of the gamepad.</summary>
- Button12,
- /// <summary>The fourteenth button of the gamepad.</summary>
- Button13,
- /// <summary>The fifteenth button of the gamepad.</summary>
- Button14,
- /// <summary>The sixteenth button of the gamepad.</summary>
- Button15,
- /// <summary>The last button of the gamepad.</summary>
- LastButton
- }
-}
-
View
216 Source/OpenTK/Input/GamePadButtons.cs
@@ -0,0 +1,216 @@
+#region License
+//
+// GamePadButtons.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// 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;
+
+namespace OpenTK.Input
+{
+ /// <summary>
+ /// Describes the <see cref="ButtonState"/> of <see cref="GamePad"/> <see cref="Buttons"/>.
+ /// </summary>
+ public struct GamePadButtons : IEquatable<GamePadButtons>
+ {
+ Buttons buttons;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenTK.Input.GamePadButtons"/> structure.
+ /// </summary>
+ /// <param name="state">A bitmask containing the button state.</param>
+ public GamePadButtons(Buttons state)
+ {
+ buttons = state;
+ }
+
+ #region Public Members
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the A button.
+ /// </summary>
+ public ButtonState A
+ {
+ get { return GetButton(Buttons.A); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the B button.
+ /// </summary>
+ public ButtonState B
+ {
+ get { return GetButton(Buttons.B); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the X button.
+ /// </summary>
+ public ButtonState X
+ {
+ get { return GetButton(Buttons.X); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the Y button.
+ /// </summary>
+ public ButtonState Y
+ {
+ get { return GetButton(Buttons.Y); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the Back button.
+ /// </summary>
+ public ButtonState Back
+ {
+ get { return GetButton(Buttons.Back); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the big button.
+ /// This button is also known as Home or Guide.
+ /// </summary>
+ public ButtonState BigButton
+ {
+ get { return GetButton(Buttons.BigButton); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the left shoulder button.
+ /// </summary>
+ public ButtonState LeftShoulder
+ {
+ get { return GetButton(Buttons.LeftShoulder); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the left stick button.
+ /// This button represents a left stick that is pressed in.
+ /// </summary>
+ public ButtonState LeftStick
+ {
+ get { return GetButton(Buttons.LeftStick); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the right shoulder button.
+ /// </summary>
+ public ButtonState RightShoulder
+ {
+ get { return GetButton(Buttons.RightShoulder); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the right stick button.
+ /// This button represents a right stick that is pressed in.
+ /// </summary>
+ public ButtonState RightStick
+ {
+ get { return GetButton(Buttons.RightStick); }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="ButtonState"/> for the starth button.
+ /// </summary>
+ public ButtonState Start
+ {
+ get { return GetButton(Buttons.Start); }
+ }
+
+ /// <param name="left">A <see cref="GamePadButtons"/> instance to test for equality.</param>
+ /// <param name="right">A <see cref="GamePadButtons"/> instance to test for equality.</param>
+ public static bool operator ==(GamePadButtons left, GamePadButtons right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <param name="left">A <see cref="GamePadButtons"/> instance to test for inequality.</param>
+ /// <param name="right">A <see cref="GamePadButtons"/> instance to test for inequality.</param>
+ public static bool operator !=(GamePadButtons left, GamePadButtons right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.GamePadButtons"/>.
+ /// </summary>
+ /// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.GamePadButtons"/>.</returns>
+ public override string ToString()
+ {
+ return Convert.ToString((int)buttons, 2).PadLeft(10, '0');
+ }
+
+ /// <summary>
+ /// Serves as a hash function for a <see cref="OpenTK.Input.GamePadButtons"/> object.
+ /// </summary>
+ /// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
+ /// hash table.</returns>
+ public override int GetHashCode()
+ {
+ return buttons.GetHashCode();
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="OpenTK.Input.GamePadButtons"/>.
+ /// </summary>
+ /// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="OpenTK.Input.GamePadButtons"/>.</param>
+ /// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
+ /// <see cref="OpenTK.Input.GamePadButtons"/>; otherwise, <c>false</c>.</returns>
+ public override bool Equals(object obj)
+ {
+ return
+ obj is GamePadButtons &&
+ Equals((GamePadButtons)obj);
+ }
+
+ #endregion
+
+ #region IEquatable<GamePadButtons> Members
+
+ /// <summary>
+ /// Determines whether the specified <see cref="OpenTK.Input.GamePadButtons"/> is equal to the current <see cref="OpenTK.Input.GamePadButtons"/>.
+ /// </summary>
+ /// <param name="other">The <see cref="OpenTK.Input.GamePadButtons"/> to compare with the current <see cref="OpenTK.Input.GamePadButtons"/>.</param>
+ /// <returns><c>true</c> if the specified <see cref="OpenTK.Input.GamePadButtons"/> is equal to the current
+ /// <see cref="OpenTK.Input.GamePadButtons"/>; otherwise, <c>false</c>.</returns>
+ public bool Equals(GamePadButtons other)
+ {
+ return buttons == other.buttons;
+ }
+
+ #endregion
+
+ #region Private Members
+
+ ButtonState GetButton(Buttons b)
+ {
+ return (buttons & b) != 0 ? ButtonState.Pressed : ButtonState.Released;
+ }
+
+ #endregion
+ }
+}
+
View
395 Source/OpenTK/Input/GamePadCapabilities.cs
@@ -0,0 +1,395 @@
+#region License
+//
+// GamePadCapabilities.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2013 Stefanos Apostolopoulos
+//
+// 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;
+
+namespace OpenTK.Input
+{
+ /// <summary>
+ /// Describes the capabilities of a <c>GamePad</c> input device.
+ /// </summary>
+ public struct GamePadCapabilities : IEquatable<GamePadCapabilities>
+ {
+ Buttons buttons;
+ GamePadAxes axes;
+ byte gamepad_type;
+ bool is_connected;
+
+ #region Constructors
+
+ internal GamePadCapabilities(GamePadType type, GamePadAxes axes, Buttons buttons, bool is_connected)
+ : this()
+ {
+ gamepad_type = (byte)type;
+ this.axes = axes;
+ this.buttons = buttons;
+ this.is_connected = is_connected;
+ }
+
+ #endregion
+
+ #region Public Members
+
+ /// <summary>
+ /// Gets a <see cref="GamePadType"/> value describing the type of a <see cref="GamePad"/> input device.
+ /// This value depends on the connected device and the drivers in use. If <c>IsConnected</c>
+ /// is false, then this value will be <c>GamePadType.Unknown</c>.
+ /// </summary>
+ /// <value>The <c>GamePadType</c> of the connected input device.</value>
+ public GamePadType GamePadType
+ {
+ get { return (GamePadType)gamepad_type; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// an up digital pad button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has an up digital pad button; otherwise, <c>false</c>.</value>
+ public bool HasDPadUpButton
+ {
+ get { return (buttons & Buttons.DPadUp) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a down digital pad button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a down digital pad button; otherwise, <c>false</c>.</value>
+ public bool HasDPadDownButton
+ {
+ get { return (buttons & Buttons.DPadDown) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a left digital pad button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a left digital pad button; otherwise, <c>false</c>.</value>
+ public bool HasDPadLeftButton
+ {
+ get { return (buttons & Buttons.DPadLeft) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a right digital pad button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a right digital pad button; otherwise, <c>false</c>.</value>
+ public bool HasDPadRightButton
+ {
+ get { return (buttons & Buttons.DPadRight) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// an A button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has an A button; otherwise, <c>false</c>.</value>
+ public bool HasAButton
+ {
+ get { return (buttons & Buttons.A) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a B button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a B button; otherwise, <c>false</c>.</value>
+ public bool HasBButton
+ {
+ get { return (buttons & Buttons.B) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a X button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a X button; otherwise, <c>false</c>.</value>
+ public bool HasXButton
+ {
+ get { return (buttons & Buttons.X) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a Y button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a Y button; otherwise, <c>false</c>.</value>
+ public bool HasYButton
+ {
+ get { return (buttons & Buttons.Y) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a left stick button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a left stick button; otherwise, <c>false</c>.</value>
+ public bool HasLeftStickButton
+ {
+ get { return (buttons & Buttons.LeftStick) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a right stick button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a right stick button; otherwise, <c>false</c>.</value>
+ public bool HasRightStickButton
+ {
+ get { return (buttons & Buttons.RightStick) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a left shoulder button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a left shoulder button; otherwise, <c>false</c>.</value>
+ public bool HasLeftShoulderButton
+ {
+ get { return (buttons & Buttons.LeftShoulder) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a right shoulder button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a right shoulder button; otherwise, <c>false</c>.</value>
+ public bool HasRightShoulderButton
+ {
+ get { return (buttons & Buttons.RightShoulder) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a back button.
+ /// </summary>
+ /// <value><c>true</c> if this instance has a back button; otherwise, <c>false</c>.</value>
+ public bool HasBackButton
+ {
+ get { return (buttons & Buttons.Back) != 0; }
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Boolean"/> value describing whether this <c>GamePad</c> has
+ /// a big button. (also known as "guide" or "home" button).
+ /// </summary>
+ /// <value><c>true</c> if this instance has a big button; otherwise, <c>false</c>.</value>
+ public bool HasBigButton
+ {
+ get { return (buttons & Buttons.BigButton) != 0; }
+ }
+
+ /// <summary>