#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.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
using ColorDepth = OpenTK
.Graphics.ColorFormat;
namespace OpenTK
.Platform.Windows
{
internal class WinGraphicsMode
: IGraphicsMode
{
// Todo: Get rid of the System.Windows.Forms.Control dependency.
#region --- Fields ---
// To avoid recursion when calling GraphicsMode.Default
bool creating
;
#endregion
#region --- Constructors ---
public WinGraphicsMode
()
{
}
#endregion
#region --- IGraphicsMode Members ---
public GraphicsMode SelectGraphicsMode
(ColorDepth color,
int depth,
int stencil,
int samples, ColorDepth accum,
int buffers,
bool stereo
)
{
GraphicsMode mode
= null;
if (!creating
)
{
try
{
creating
= true;
mode
= SelectGraphicsModeARB
(color, depth, stencil, samples, accum, buffers, stereo
);
}
finally
{
creating
= false;
}
}
if (mode
== null)
mode
= SelectGraphicsModePFD
(color, depth, stencil, samples, accum, buffers, stereo
);
return mode
;
}
#endregion
#region --- Private Methods ---
#region SelectGraphicsModePFD
GraphicsMode SelectGraphicsModePFD
(ColorDepth color,
int depth,
int stencil,
int samples, ColorDepth accum,
int buffers,
bool stereo
)
{
using (Control native_window
= new Control
())
using (WinWindowInfo window
= new WinWindowInfo
(native_window
.Handle,
null))
{
IntPtr deviceContext
= ((WinWindowInfo
)window
).DeviceContext;
Debug
.WriteLine(String.Format("Device context: {0}", deviceContext
));
Debug
.Write("Selecting pixel format... ");
PixelFormatDescriptor pixelFormat
= new PixelFormatDescriptor
();
pixelFormat
.Size = API
.PixelFormatDescriptorSize;
pixelFormat
.Version = API
.PixelFormatDescriptorVersion;
pixelFormat
.Flags =
PixelFormatDescriptorFlags
.SUPPORT_OPENGL |
PixelFormatDescriptorFlags
.DRAW_TO_WINDOW;
pixelFormat
.ColorBits = (byte)(color
.Red + color
.Green + color
.Blue);
pixelFormat
.PixelType = color
.IsIndexed ? PixelType
.INDEXED : PixelType
.RGBA;
pixelFormat
.RedBits = (byte)color
.Red;
pixelFormat
.GreenBits = (byte)color
.Green;
pixelFormat
.BlueBits = (byte)color
.Blue;
pixelFormat
.AlphaBits = (byte)color
.Alpha;
if (accum
.BitsPerPixel > 0)
{
pixelFormat
.AccumBits = (byte)(accum
.Red + accum
.Green + accum
.Blue);
pixelFormat
.AccumRedBits = (byte)accum
.Red;
pixelFormat
.AccumGreenBits = (byte)accum
.Green;
pixelFormat
.AccumBlueBits = (byte)accum
.Blue;
pixelFormat
.AccumAlphaBits = (byte)accum
.Alpha;
}
pixelFormat
.DepthBits = (byte)depth
;
pixelFormat
.StencilBits = (byte)stencil
;
if (depth
<= 0) pixelFormat
.Flags |= PixelFormatDescriptorFlags
.DEPTH_DONTCARE;
if (stereo
) pixelFormat
.Flags |= PixelFormatDescriptorFlags
.STEREO;
if (buffers
> 1) pixelFormat
.Flags |= PixelFormatDescriptorFlags
.DOUBLEBUFFER;
int pixel
= Functions
.ChoosePixelFormat(deviceContext,
ref pixelFormat
);
if (pixel
== 0)
throw new GraphicsModeException
("The requested GraphicsMode is not available.");
// Find out what we really got as a format:
PixelFormatDescriptor pfd
= new PixelFormatDescriptor
();
pixelFormat
.Size = API
.PixelFormatDescriptorSize;
pixelFormat
.Version = API
.PixelFormatDescriptorVersion;
Functions
.DescribePixelFormat(deviceContext, pixel, API
.PixelFormatDescriptorSize,
ref pfd
);
GraphicsMode fmt
= new GraphicsMode
((IntPtr
)pixel,
new ColorDepth
(pfd
.RedBits, pfd
.GreenBits, pfd
.BlueBits, pfd
.AlphaBits),
pfd
.DepthBits,
pfd
.StencilBits,
0,
new ColorDepth
(pfd
.AccumBits),
(pfd
.Flags & PixelFormatDescriptorFlags
.DOUBLEBUFFER) != 0 ? 2 : 1,
(pfd
.Flags & PixelFormatDescriptorFlags
.STEREO) != 0);
return fmt
;
}
}
#endregion
#region SelectGraphicsModeARB
GraphicsMode SelectGraphicsModeARB
(ColorDepth color,
int depth,
int stencil,
int samples, ColorDepth accum,
int buffers,
bool stereo
)
{
using (INativeWindow native_window
= new NativeWindow
())
using (IGraphicsContext context
= new GraphicsContext
(new GraphicsMode
(new ColorFormat
(),
0,
0,
0,
new ColorFormat
(),
2,
false), native_window
.WindowInfo,
1,
0, GraphicsContextFlags
.Default))
{
WinWindowInfo window
= (WinWindowInfo
)native_window
.WindowInfo;
// See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
// for more details
Debug
.Write("Selecting pixel format (ARB)... ");
if (Wgl
.Delegates.wglChoosePixelFormatARB == null || Wgl
.Delegates.wglGetPixelFormatAttribivARB == null)
{
Debug
.WriteLine("failed");
return null;
}
int[] attribs
= new int[]
{
(int)WGL_ARB_pixel_format
.AccelerationArb,
(int)WGL_ARB_pixel_format
.RedBitsArb,
(int)WGL_ARB_pixel_format
.GreenBitsArb,
(int)WGL_ARB_pixel_format
.BlueBitsArb,
(int)WGL_ARB_pixel_format
.AlphaBitsArb,
(int)WGL_ARB_pixel_format
.ColorBitsArb,
(int)WGL_ARB_pixel_format
.DepthBitsArb,
(int)WGL_ARB_pixel_format
.StencilBitsArb,
(int)WGL_ARB_multisample
.SampleBuffersArb,
(int)WGL_ARB_multisample
.SamplesArb,
(int)WGL_ARB_pixel_format
.AccumRedBitsArb,
(int)WGL_ARB_pixel_format
.AccumGreenBitsArb,
(int)WGL_ARB_pixel_format
.AccumBlueBitsArb,
(int)WGL_ARB_pixel_format
.AccumAlphaBitsArb,
(int)WGL_ARB_pixel_format
.AccumBitsArb,
(int)WGL_ARB_pixel_format
.DoubleBufferArb,
(int)WGL_ARB_pixel_format
.StereoArb,
0
};
int[] values
= new int[attribs
.Length];
int[] attribs_values
= new int[]
{
(int)WGL_ARB_pixel_format
.AccelerationArb,
(int)WGL_ARB_pixel_format
.FullAccelerationArb,
(int)WGL_ARB_pixel_format
.DrawToWindowArb,
1,
(int)WGL_ARB_pixel_format
.RedBitsArb, color
.Red,
(int)WGL_ARB_pixel_format
.GreenBitsArb, color
.Green,
(int)WGL_ARB_pixel_format
.BlueBitsArb, color
.Blue,
(int)WGL_ARB_pixel_format
.AlphaBitsArb, color
.Alpha,
(int)WGL_ARB_pixel_format
.ColorBitsArb, color
.BitsPerPixel - color
.Alpha,
// Should not contain alpha bpp (see spec)
(int)WGL_ARB_pixel_format
.DepthBitsArb, depth,
(int)WGL_ARB_pixel_format
.StencilBitsArb, stencil,
(int)WGL_ARB_multisample
.SampleBuffersArb, samples
> 0 ? 1 : 0,
(int)WGL_ARB_multisample
.SamplesArb, samples,
(int)WGL_ARB_pixel_format
.AccumRedBitsArb, accum
.Red,
(int)WGL_ARB_pixel_format
.AccumGreenBitsArb, accum
.Green,
(int)WGL_ARB_pixel_format
.AccumBlueBitsArb, accum
.Blue,
(int)WGL_ARB_pixel_format
.AccumAlphaBitsArb, accum
.Alpha,
(int)WGL_ARB_pixel_format
.AccumBitsArb, accum
.BitsPerPixel,
// Spec doesn't mention wether alpha bpp should be included...
(int)WGL_ARB_pixel_format
.DoubleBufferArb, buffers
> 1 ? 1 : 0,
(int)WGL_ARB_pixel_format
.StereoArb, stereo
? 1 : 0,
0,
0
};
int[] pixel
= new int[1], num_formats
= new int[1];
bool success
= Wgl
.Arb.ChoosePixelFormat(window
.DeviceContext, attribs_values,
null,
1, pixel, num_formats
);
if (!success
|| num_formats
[0] == 0 || pixel
[0] == 0)
{
// Try again without an accumulator. Many modern cards cannot accelerate multisampled formats with accumulator buffers.
int index_of_accum
= Array
.IndexOf(attribs_values,
(int)WGL_ARB_pixel_format
.AccumRedBitsArb);
attribs_values
[index_of_accum
+ 1] = attribs_values
[index_of_accum
+ 3] =
attribs_values
[index_of_accum
+ 5] = attribs_values
[index_of_accum
+ 7] =
attribs_values
[index_of_accum
+ 9] = 0;
Wgl
.Arb.ChoosePixelFormat(window
.DeviceContext, attribs_values,
null,
1, pixel, num_formats
);
}
if (!success
|| num_formats
[0] == 0 || pixel
[0] == 0)
{
Debug
.WriteLine("failed (no suitable pixel format).");
return null;
}
// Find out what we really got as a format:
success
= Wgl
.Arb.GetPixelFormatAttrib(window
.DeviceContext, pixel
[0],
0, attribs
.Length - 1, attribs, values
);
if (!success
)
{
Debug
.WriteLine("failed (pixel format attributes could not be determined).");
return null;
}
GraphicsMode mode
= new GraphicsMode
(new IntPtr
(pixel
[0]),
new ColorDepth
(values
[1], values
[2], values
[3], values
[4]),
values
[6],
values
[7],
values
[8] != 0 ? values
[9] : 0,
new ColorDepth
(values
[10], values
[11], values
[12], values
[13]),
values
[15] == 1 ? 2 : 1,
values
[16] == 1 ? true : false);
Debug
.WriteLine("success!");
return mode
;
}
}
#endregion
#endregion
}
}