Introduction
I wanted to test some OpenGL (on Linux platforms alternatively Mesa) libraries, that provide a GUI with capabilities comparable to Windows Presentation Foundation. But I needed a minimalistic window template like GLUT Window Template from Ali BaderEddin for Linux and C#.
Background
There are a lot of forum questions/answers and tutorials, that deal with GLUT/GLU/GL window template, but almost all of them are based on Windows and C/C++. This tip shall provide quick access to a GLUT/GLU/GL window template for Linux/C#.
Using the Code
This is the main class:
class MainClass
{
private int _windowHandle;
public static void Main(string[] args)
{
MainClass instance = new MainClass();
instance.Run(args);
}
private void Run(string[] args)
{
GLUT.Init(args.Length, args);
GLUT.InitDisplayMode(GLUT.GLUT_RGB);
GLUT.InitWindowSize(400, 300);
_windowHandle = GLUT.CreateWindow("Hallo");
GL.ClearColor(0.0f ,0.0f ,0.0f ,0.0f);
GLU.Ortho2D(0,400,0,500);
GLUT.DisplayFunc(new GLUT.DisplayProcDelegate(DisplayProc));
GLUT.KeyboardFunc(new GLUT.KeyboardProcDelegate(KeyDownProc));
GLUT.KeyboardUpFunc(new GLUT.KeyboardUpProcDelegate(KeyUpProc));
GLUT.MouseFunc(new GLUT.MouseProcDelegate(MouseProcDelegate));
GLUT.MainLoop();
}
private void DisplayProc()
{
GL.Clear(GL.GL_COLOR_BUFFER_BIT);
GL.Color3f(1.0f , 1.0f , 1.0f);
GL.Begin(GL.GL_POLYGON);
GL.Vertex2i(200,125);
GL.Vertex2i(100,375);
GL.Vertex2i(300,375);
GL.End();
GL.Flush();
}
private void KeyDownProc (byte key, int x, int y)
{
if (key == 'q')
GLUT.DestroyWindow(_windowHandle);
}
private void KeyUpProc (byte key, int x, int y)
{
if (key == 'q')
GLUT.DestroyWindow(_windowHandle);
}
private void MouseProcDelegate(int button, int state, int x, int y)
{
if ((button == GLUT.GLUT_LEFT_BUTTON ) && (state == GLUT.GLUT_DOWN))
{
;
}
if ((button == GLUT.GLUT_LEFT_BUTTON ) && (state == GLUT.GLUT_UP))
{
;
}
}
}
To keep full control, I decided to declare the P/Invoke prototypes within the project. But I recommend you to take a look at Tao Framework and OpenTK as well.
First the GLUT function prototypes:
public static class GLUT
{
private const string LIB_GLUT = "libglut.so.3";
public const int GLUT_RGB = 0;
public const int GLUT_RGBA = GLUT_RGB;
public const int GLUT_LEFT_BUTTON = 0;
public const int GLUT_MIDDLE_BUTTON = 1;
public const int GLUT_RIGHT_BUTTON = 2;
public const int GLUT_DOWN = 0;
public const int GLUT_UP = 1;
public const int GLUT_ACTIVE_SHIFT = 1;
public const int GLUT_ACTIVE_CTRL = 2;
public const int GLUT_ACTIVE_ALT = 4;
#region Initialization and cleanup
[DllImport(LIB_GLUT, EntryPoint="glutInit", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
private static extern void glutInit(ref int argcp, string[] argv);
public static void Init(int argc, string[] argv)
{ int argcp = argc; glutInit(ref argcp, argv); }
[DllImport(LIB_GLUT, EntryPoint="glutInitDisplayMode", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void InitDisplayMode(int argcp);
[DllImport(LIB_GLUT, EntryPoint="glutInitWindowPosition",
CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void InitWindowPosition(int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutInitWindowSize", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void InitWindowSize(int widt, int height);
#endregion Initialization and cleanup
#region Window handling and main loop
[DllImport(LIB_GLUT, EntryPoint="glutMainLoop", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void MainLoop();
[DllImport(LIB_GLUT, EntryPoint="glutCreateWindow", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern int CreateWindow(string title);
[DllImport(LIB_GLUT, EntryPoint="glutDestroyWindow", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void DestroyWindow(int win);
#endregion Window handling and main loop
#region Callbacks (keyboard)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void KeyboardProcDelegate(byte key, int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutKeyboardFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void KeyboardFunc(KeyboardProcDelegate keyboardProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void KeyboardUpProcDelegate(byte key, int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutKeyboardUpFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void KeyboardUpFunc(KeyboardUpProcDelegate keyboardUpProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SpecialProcDelegate(int key, int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutSpecialFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void SpecialFunc(SpecialProcDelegate specialProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SpecialUpProcDelegate(int key, int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutSpecialUpFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
private static extern void SpecialUpFunc(SpecialUpProcDelegate specialUpProc);
#endregion Callbacks (keyboard)
#region Callbacks
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DisplayProcDelegate();
[DllImport(LIB_GLUT, EntryPoint="glutDisplayFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void DisplayFunc(DisplayProcDelegate displayProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MouseProcDelegate(int button, int state, int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutMouseFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void MouseFunc(MouseProcDelegate mouseProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MotionProcDelegate(int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutMotionFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void MotionFunc(MotionProcDelegate motionProc);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PassiveMotionProcDelegate(int x, int y);
[DllImport(LIB_GLUT, EntryPoint="glutPassiveMotionFunc", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void PassiveMotionFunc(PassiveMotionProcDelegate passiveMotionProc);
#endregion Callbacks
[DllImport(LIB_GLUT, EntryPoint="glutGetModifiers", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern int GetModifiers();
}
Now the GLU function prototypes:
public static class GLU
{
private const string LIB_GLU = "libGLU.so";
[DllImport(LIB_GLU, EntryPoint="gluOrtho2D", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Ortho2D (double left, double right, double bottom, double top);
}
And finally the GL function prototypes:
public static class GL
{
private const string LIB_GL = "libGL.so";
public const uint GL_DEPTH_BUFFER_BIT = 0x00000100;
public const uint GL_STENCIL_BUFFER_BIT = 0x00000400;
public const uint GL_COLOR_BUFFER_BIT = 0x00004000;
public const int GL_POINTS = 0x0000;
public const int GL_LINES = 0x0001;
public const int GL_LINE_LOOP = 0x0002;
public const int GL_LINE_STRIP = 0x0003;
public const int GL_TRIANGLES = 0x0004;
public const int GL_TRIANGLE_STRIP = 0x0005;
public const int GL_TRIANGLE_FAN = 0x0006;
public const int GL_QUADS = 0x0007;
public const int GL_QUAD_STRIP = 0x0008;
public const int GL_POLYGON = 0x0009;
[DllImport(LIB_GL, EntryPoint="glClearColor", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void ClearColor(float red, float green, float blue, float alpha);
[DllImport(LIB_GL, EntryPoint="glClear", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Clear(uint mask);
[DllImport(LIB_GL, EntryPoint="glColor3f", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Color3f(float red, float green, float blue);
[DllImport(LIB_GL, EntryPoint="glBegin", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Begin(int mode);
[DllImport(LIB_GL, EntryPoint="glVertex2i", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Vertex2i(int x, int y);
[DllImport(LIB_GL, EntryPoint="glEnd", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void End();
[DllImport(LIB_GL, EntryPoint="glFlush", CallingConvention=CallingConvention.Cdecl)]
[System.Security.SuppressUnmanagedCodeSecurity()]
public static extern void Flush();
}
My MonoDevelop 5.10 (older versions are possible as well) project target is AnyCPU
on openSuse Leap 42.1 64 bit. Consequently, the application runs with 64 bit and accesses the GLUT/GLU/GL libraries from /usr/lib64. The only reference, used by the project, is System
.
The GLU and GLUT (GL is a dependency) installation packages must be installed.
libGLU1
(OpenGL utility library) libglut3
(Freely licensed alternative to the GLUT library)
Points of Interest
I hope this tip will help you to test OpenGL on Linux with C# convenient.
References
History
- 09.03.2018 - Initial version