diff --git a/Source/Examples/OpenTK/GameWindow/MouseCursorSimple.cs b/Source/Examples/OpenTK/GameWindow/MouseCursorSimple.cs index f670b723..162be52d 100644 --- a/Source/Examples/OpenTK/GameWindow/MouseCursorSimple.cs +++ b/Source/Examples/OpenTK/GameWindow/MouseCursorSimple.cs @@ -13,7 +13,7 @@ namespace Examples.Tutorial /// /// Demonstrates the MouseCursor class. /// - [Example("MouseCursor Simple", ExampleCategory.OpenTK, "GameWindow", 1, Documentation = "MouseCursorSimple")] + [Example("Custom MouseCursor", ExampleCategory.OpenTK, "GameWindow", 1, Documentation = "MouseCursorSimple")] public class MouseCursorSimple : GameWindow { readonly MouseCursor MyCursor; @@ -31,7 +31,7 @@ namespace Examples.Tutorial System.Drawing.Imaging.PixelFormat.Format32bppPArgb); MyCursor = new OpenTK.MouseCursor( - data.Scan0, bitmap.Width, bitmap.Height, 0, 0); + 0, 0, data.Width, data.Height, data.Scan0); Cursor = MyCursor; } } diff --git a/Source/OpenTK/MouseCursor.cs b/Source/OpenTK/MouseCursor.cs index 5790d3d0..df8cd0cf 100644 --- a/Source/OpenTK/MouseCursor.cs +++ b/Source/OpenTK/MouseCursor.cs @@ -38,7 +38,7 @@ namespace OpenTK { static readonly MouseCursor default_cursor = new MouseCursor(); static readonly MouseCursor empty_cursor = new MouseCursor( - new byte[16 * 16 * 4], 16, 16, 0, 0); + 0, 0, 16, 16, new byte[16 * 16 * 4]); int x; int y; @@ -47,9 +47,28 @@ namespace OpenTK { } - // Todo: make public when byte-order issues are resolved - public MouseCursor(byte[] argb, int width, int height, int hotx, int hoty) - : base(argb, width, height) + /// + /// Initializes a new instance from a + /// contiguous array of BGRA pixels. + /// Each pixel is composed of 4 bytes, representing B, G, R and A values, + /// respectively. For correct antialiasing of translucent cursors, + /// the B, G and R components should be premultiplied with the A component: + /// + /// B = (byte)((B * A) / 255) + /// G = (byte)((G * A) / 255) + /// R = (byte)((R * A) / 255) + /// + /// + /// The x-coordinate of the cursor hotspot, in the range [0, width] + /// The y-coordinate of the cursor hotspot, in the range [0, height] + /// The width of the cursor data, in pixels. + /// The height of the cursor data, in pixels. + /// + /// A byte array representing the cursor image, + /// laid out as a contiguous array of BGRA pixels. + /// + public MouseCursor(int hotx, int hoty, int width, int height, byte[] data) + : base(width, height, data) { if (hotx < 0 || hotx >= Width || hoty < 0 || hoty >= Height) throw new ArgumentOutOfRangeException(); @@ -58,8 +77,27 @@ namespace OpenTK y = hoty; } - public MouseCursor(IntPtr argb, int width, int height, int hotx, int hoty) - : base(argb, width, height) + /// + /// Initializes a new instance from a + /// contiguous array of BGRA pixels. + /// Each pixel is composed of 4 bytes, representing B, G, R and A values, + /// respectively. For correct antialiasing of translucent cursors, + /// the B, G and R components should be premultiplied with the A component: + /// + /// B = (byte)((B * A) / 255) + /// G = (byte)((G * A) / 255) + /// R = (byte)((R * A) / 255) + /// + /// + /// The x-coordinate of the cursor hotspot, in the range [0, width] + /// The y-coordinate of the cursor hotspot, in the range [0, height] + /// The width of the cursor data, in pixels. + /// The height of the cursor data, in pixels. + /// + /// A pointer to the cursor image, laid out as a contiguous array of BGRA pixels. + /// + public MouseCursor(int hotx, int hoty, int width, int height, IntPtr data) + : base(width, height, data) { if (hotx < 0 || hotx >= Width || hoty < 0 || hoty >= Height) throw new ArgumentOutOfRangeException(); diff --git a/Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs b/Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs index bce6f4b3..33d53daf 100644 --- a/Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs +++ b/Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs @@ -987,7 +987,7 @@ namespace OpenTK.Platform.MacOS { for (int x = 0; x < cursor.Width; x++) { - uint argb = unchecked((uint)BitConverter.ToInt32(cursor.Argb, i)); + uint argb = unchecked((uint)BitConverter.ToInt32(cursor.Data, i)); if (BitConverter.IsLittleEndian) { argb = diff --git a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs index 48315266..023f2189 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs @@ -493,7 +493,7 @@ namespace OpenTK.Platform.SDL2 // the rgba values supplied by the user unsafe { - fixed (byte* pixels = value.Argb) + fixed (byte* pixels = value.Data) { IntPtr cursor_surface = SDL.CreateRGBSurfaceFrom( diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index d464f3a4..36b91faf 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -1219,7 +1219,7 @@ namespace OpenTK.Platform.Windows Bitmap bmp; unsafe { - fixed (byte* pixels = value.Argb) + fixed (byte* pixels = value.Data) { bmp = new Bitmap(value.Width, value.Height, stride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 6c44d5fb..a3cc9126 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -1483,7 +1483,7 @@ namespace OpenTK.Platform.X11 } else { - fixed(byte* pixels = value.Argb) + fixed(byte* pixels = value.Data) { var xcursorimage = Functions.XcursorImageCreate(value.Width, value.Height); xcursorimage->xhot = (uint)value.X; diff --git a/Source/OpenTK/WindowIcon.cs b/Source/OpenTK/WindowIcon.cs index 87262d7f..53d2d1f8 100644 --- a/Source/OpenTK/WindowIcon.cs +++ b/Source/OpenTK/WindowIcon.cs @@ -38,10 +38,14 @@ namespace OpenTK /// public class WindowIcon { - byte[] argb; + byte[] data; int width; int height; + /// \internal + /// + /// Initializes a new instance of the class. + /// internal protected WindowIcon() { } @@ -55,36 +59,31 @@ namespace OpenTK this.height = height; } - internal WindowIcon(byte[] argb, int width, int height) + internal WindowIcon(int width, int height, byte[] data) : this(width, height) { - if (argb == null) + if (data == null) throw new ArgumentNullException(); - if (argb.Length < Width * Height * 4) + if (data.Length < Width * Height * 4) throw new ArgumentOutOfRangeException(); - this.argb = argb; + this.data = data; } - internal WindowIcon(IntPtr argb, int width, int height) + internal WindowIcon(int width, int height, IntPtr data) : this(width, height) { - if (argb == IntPtr.Zero) + if (data == IntPtr.Zero) throw new ArgumentNullException(); // We assume that width and height are correctly set. // If they are not, we will read garbage and probably // crash. - this.argb = new byte[width * height * 4]; - for (int y = 0; y < height; y++) - { - var stride = width * 4; - var offset = new IntPtr(argb.ToInt64() + y * stride); - Marshal.Copy(offset, Argb, y * stride, stride); - } + this.data = new byte[width * height * 4]; + Marshal.Copy(data, this.data, 0, this.data.Length); } - internal byte[] Argb { get { return argb; } } + internal byte[] Data { get { return data; } } internal int Width { get { return width; } } internal int Height { get { return height; } } }