-
-
Save DeafMan1983/7d9cdc0eb0c3bc7e4526113a1e4c8e69 to your computer and use it in GitHub Desktop.
That is simple Xlib/X11 GLArea for GtkSharp 2.x with Idle.Add(); Sorry it works only Linux / FreeBSD.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
/* | |
* Improved version for GLWidget as GLArea for GtkSharp 2.x | |
* with Idle Mode version | |
* Works fine: | |
* - Display and resize = OK! | |
* - Clickable in glx_context = hm, hmm, hmmm??? | |
* - Other events with X11's glx_context with Gdk.Event??? | |
* - Drawing triangle = OK | |
* -> glBegin and glEnd = OK! | |
* -> VAO and VBO = OK! | |
* | |
* - Other unknown??? | |
* | |
* - Xlib/X11's Vulkan's Surface will come soon. | |
*/ | |
namespace Gtk2SDL | |
{ | |
unsafe class MainClass : Gtk.Window | |
{ | |
private Gtk.DrawingArea area; | |
private IntPtr display, window, visualinfo, glx_context; | |
private const string libgdkx112 = "libgdk-x11-2.0.so.0"; | |
private const string libx11 = "libX11.so.6"; | |
private const string libGLX = "libGLX.so.0"; | |
private const string libGL = "libGL.so.1"; | |
[DllImport(libgdkx112)] | |
private extern static IntPtr gdk_x11_display_get_xdisplay(IntPtr gdk_display); | |
[DllImport(libx11)] | |
private extern static IntPtr gdk_x11_drawable_get_display(IntPtr gdk_window); | |
[DllImport(libgdkx112)] | |
private extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdk_window); | |
[DllImport(libgdkx112)] | |
private extern static IntPtr gdk_x11_get_default_root_xwindow(); | |
[DllImport(libx11)] | |
private extern static IntPtr gdk_x11_colormap_get_xcolormap(IntPtr gdk_colormap); | |
[DllImport(libgdkx112)] | |
private extern static IntPtr gdk_x11_visual_get_xvisual(IntPtr gdk_visual); | |
[DllImport(libx11)] | |
private extern static bool XPending(IntPtr x_display); | |
[DllImport(libx11)] | |
private extern static void XReparentWindow(IntPtr x_display, IntPtr x_window, IntPtr x_window_parent, int x, int y); | |
[DllImport(libx11)] | |
private extern static void XQueryTree(IntPtr x_display, IntPtr x_window, out IntPtr x_window_root, out IntPtr x_window_parent, out IntPtr x_window_child, out uint number_children); | |
[DllImport(libx11)] | |
private extern static void XFree(IntPtr data); | |
[DllImport(libx11)] | |
private extern static void XFlush(IntPtr x_display); | |
[DllImport(libx11)] | |
private extern static void XDrawRectangle(IntPtr x_display, IntPtr x_drawable, IntPtr x_gc, int x, int y, uint w, uint h); | |
[DllImport(libx11)] | |
private extern static IntPtr XDefaultGC(IntPtr x_display, int screen_number); | |
[DllImport(libx11)] | |
private extern static IntPtr XCreateSimpleWindow(IntPtr x_display, IntPtr x_window_parent, int x, int y, uint w, uint h, uint border_width, uint border, uint background); | |
[DllImport(libx11)] | |
private extern static int XMapWindow(IntPtr x_display, IntPtr x_window); | |
[DllImport(libx11)] | |
private extern static int XUnmapWindow(IntPtr x_display, IntPtr x_window); | |
[DllImport(libx11)] | |
private extern static void XDestroyWindow(IntPtr x_display, IntPtr x_window); | |
[DllImport(libx11)] | |
private extern static void XClearWindow(IntPtr x_display, IntPtr x_window); | |
[DllImport(libx11)] | |
private extern static void XSelectInput(IntPtr x_display, IntPtr x_window, IntPtr x_event_mask); | |
[DllImport(libx11)] | |
private static extern void XNextEvent(IntPtr display, out XEvent xev); | |
[DllImport(libx11)] | |
private static extern void XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes); | |
[StructLayout(LayoutKind.Explicit)] | |
internal struct XEvent | |
{ | |
[FieldOffset(0)] | |
public XEventName type; | |
} | |
public enum XEventName | |
{ | |
KeyPress = 2, | |
KeyRelease = 3, | |
ButtonPress = 4, | |
ButtonRelease = 5, | |
MotionNotify = 6, | |
EnterNotify = 7, | |
LeaveNotify = 8, | |
FocusIn = 9, | |
FocusOut = 10, | |
KeymapNotify = 11, | |
Expose = 12, | |
GraphicsExpose = 13, | |
NoExpose = 14, | |
VisibilityNotify = 15, | |
CreateNotify = 16, | |
DestroyNotify = 17, | |
UnmapNotify = 18, | |
MapNotify = 19, | |
MapRequest = 20, | |
ReparentNotify = 21, | |
ConfigureNotify = 22, | |
ConfigureRequest = 23, | |
GravityNotify = 24, | |
ResizeRequest = 25, | |
CirculateNotify = 26, | |
CirculateRequest = 27, | |
PropertyNotify = 28, | |
SelectionClear = 29, | |
SelectionRequest = 30, | |
SelectionNotify = 31, | |
ColormapNotify = 32, | |
ClientMessage = 33, | |
MappingNotify = 34, | |
GenericEvent = 35, | |
LASTEvent | |
} | |
public enum XGravity | |
{ | |
ForgetGravity = 0, | |
NorthWestGravity = 1, | |
NorthGravity = 2, | |
NorthEastGravity = 3, | |
WestGravity = 4, | |
CenterGravity = 5, | |
EastGravity = 6, | |
SouthWestGravity = 7, | |
SouthGravity = 8, | |
SouthEastGravity = 9, | |
StaticGravity = 10 | |
} | |
[Flags] | |
public enum EventMask | |
{ | |
NoEventMask = 0, | |
KeyPressMask = 1 << 0, | |
KeyReleaseMask = 1 << 1, | |
ButtonPressMask = 1 << 2, | |
ButtonReleaseMask = 1 << 3, | |
EnterWindowMask = 1 << 4, | |
LeaveWindowMask = 1 << 5, | |
PointerMotionMask = 1 << 6, | |
PointerMotionHintMask = 1 << 7, | |
Button1MotionMask = 1 << 8, | |
Button2MotionMask = 1 << 9, | |
Button3MotionMask = 1 << 10, | |
Button4MotionMask = 1 << 11, | |
Button5MotionMask = 1 << 12, | |
ButtonMotionMask = 1 << 13, | |
KeymapStateMask = 1 << 14, | |
ExposureMask = 1 << 15, | |
VisibilityChangeMask = 1 << 16, | |
StructureNotifyMask = 1 << 17, | |
ResizeRedirectMask = 1 << 18, | |
SubstructureNotifyMask = 1 << 19, | |
SubstructureRedirectMask = 1 << 20, | |
FocusChangeMask = 1 << 21, | |
PropertyChangeMask = 1 << 22, | |
ColormapChangeMask = 1 << 23, | |
OwnerGrabButtonMask = 1 << 24 | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
internal struct XWindowAttributes | |
{ | |
public int x; | |
public int y; | |
public int width; | |
public int height; | |
public int border_width; | |
public int depth; | |
public IntPtr visual; | |
public IntPtr root; | |
public int c_class; | |
public XGravity bit_gravity; | |
public XGravity win_gravity; | |
public int backing_store; | |
public IntPtr backing_planes; | |
public IntPtr backing_pixel; | |
public bool save_under; | |
public IntPtr colormap; | |
public bool map_installed; | |
// public MapState map_state; | |
public IntPtr all_event_masks; | |
public IntPtr your_event_mask; | |
public IntPtr do_not_propagate_mask; | |
public bool override_direct; | |
public IntPtr screen; | |
} | |
[DllImport(libGLX)] | |
private extern static IntPtr glXChooseVisual(IntPtr display, int screen_numberm, ref int[] attrilists); | |
[DllImport(libGLX)] | |
private extern static IntPtr glXCreateContext(IntPtr x_display, IntPtr x_visualinfo, IntPtr share, bool direct); | |
[DllImport(libGLX)] | |
private extern static bool glXIsDirect(IntPtr display, IntPtr context); | |
[DllImport(libGLX)] | |
private extern static bool glXMakeCurrent(IntPtr x_display, IntPtr x_window, IntPtr glx_context); | |
[DllImport(libGLX)] | |
private extern static void glXSwapBuffers(IntPtr display, IntPtr drawable); | |
[DllImport(libGLX)] | |
private extern static void glXDestroyContext(IntPtr display, IntPtr glx_context); | |
[Flags] | |
public enum GLXAttribute : int | |
{ | |
TRANSPARENT_BLUE_VALUE_EXT = 0x27, | |
GRAY_SCALE = 0x8006, | |
RGBA_TYPE = 0x8014, | |
TRANSPARENT_RGB_EXT = 0x8008, | |
ACCUM_BLUE_SIZE = 16, | |
SHARE_CONTEXT_EXT = 0x800A, | |
STEREO = 6, | |
ALPHA_SIZE = 11, | |
FLOAT_COMPONENTS_NV = 0x20B0, | |
NONE = 0x8000, | |
DEPTH_SIZE = 12, | |
TRANSPARENT_INDEX_VALUE_EXT = 0x24, | |
MAX_PBUFFER_WIDTH_SGIX = 0x8016, | |
GREEN_SIZE = 9, | |
X_RENDERABLE_SGIX = 0x8012, | |
LARGEST_PBUFFER = 0x801C, | |
DONT_CARE = unchecked((int)0xFFFFFFFF), | |
TRANSPARENT_ALPHA_VALUE_EXT = 0x28, | |
PSEUDO_COLOR_EXT = 0x8004, | |
USE_GL = 1, | |
SAMPLE_BUFFERS_SGIS = 100000, | |
TRANSPARENT_GREEN_VALUE_EXT = 0x26, | |
HYPERPIPE_ID_SGIX = 0x8030, | |
COLOR_INDEX_TYPE_SGIX = 0x8015, | |
SLOW_CONFIG = 0x8001, | |
PRESERVED_CONTENTS = 0x801B, | |
ACCUM_RED_SIZE = 14, | |
EVENT_MASK = 0x801F, | |
VISUAL_ID_EXT = 0x800B, | |
EVENT_MASK_SGIX = 0x801F, | |
SLOW_VISUAL_EXT = 0x8001, | |
TRANSPARENT_GREEN_VALUE = 0x26, | |
MAX_PBUFFER_WIDTH = 0x8016, | |
DIRECT_COLOR_EXT = 0x8003, | |
VISUAL_ID = 0x800B, | |
ACCUM_GREEN_SIZE = 15, | |
DRAWABLE_TYPE_SGIX = 0x8010, | |
SCREEN_EXT = 0x800C, | |
SAMPLES = 100001, | |
HEIGHT = 0x801E, | |
TRANSPARENT_INDEX_VALUE = 0x24, | |
SAMPLE_BUFFERS_ARB = 100000, | |
PBUFFER = 0x8023, | |
RGBA_TYPE_SGIX = 0x8014, | |
MAX_PBUFFER_HEIGHT = 0x8017, | |
FBCONFIG_ID_SGIX = 0x8013, | |
DRAWABLE_TYPE = 0x8010, | |
SCREEN = 0x800C, | |
RED_SIZE = 8, | |
VISUAL_SELECT_GROUP_SGIX = 0x8028, | |
VISUAL_CAVEAT_EXT = 0x20, | |
PSEUDO_COLOR = 0x8004, | |
PBUFFER_HEIGHT = 0x8040, | |
STATIC_GRAY = 0x8007, | |
PRESERVED_CONTENTS_SGIX = 0x801B, | |
RGBA_FLOAT_TYPE_ARB = 0x20B9, | |
TRANSPARENT_RED_VALUE = 0x25, | |
TRANSPARENT_ALPHA_VALUE = 0x28, | |
WINDOW = 0x8022, | |
X_RENDERABLE = 0x8012, | |
STENCIL_SIZE = 13, | |
TRANSPARENT_RGB = 0x8008, | |
LARGEST_PBUFFER_SGIX = 0x801C, | |
STATIC_GRAY_EXT = 0x8007, | |
TRANSPARENT_BLUE_VALUE = 0x27, | |
DIGITAL_MEDIA_PBUFFER_SGIX = 0x8024, | |
BLENDED_RGBA_SGIS = 0x8025, | |
NON_CONFORMANT_VISUAL_EXT = 0x800D, | |
COLOR_INDEX_TYPE = 0x8015, | |
TRANSPARENT_RED_VALUE_EXT = 0x25, | |
GRAY_SCALE_EXT = 0x8006, | |
WINDOW_SGIX = 0x8022, | |
X_VISUAL_TYPE = 0x22, | |
MAX_PBUFFER_HEIGHT_SGIX = 0x8017, | |
DOUBLEBUFFER = 5, | |
OPTIMAL_PBUFFER_WIDTH_SGIX = 0x8019, | |
X_VISUAL_TYPE_EXT = 0x22, | |
WIDTH_SGIX = 0x801D, | |
STATIC_COLOR_EXT = 0x8005, | |
BUFFER_SIZE = 2, | |
DIRECT_COLOR = 0x8003, | |
MAX_PBUFFER_PIXELS = 0x8018, | |
NONE_EXT = 0x8000, | |
HEIGHT_SGIX = 0x801E, | |
RENDER_TYPE = 0x8011, | |
FBCONFIG_ID = 0x8013, | |
TRANSPARENT_INDEX_EXT = 0x8009, | |
TRANSPARENT_INDEX = 0x8009, | |
TRANSPARENT_TYPE_EXT = 0x23, | |
ACCUM_ALPHA_SIZE = 17, | |
PBUFFER_SGIX = 0x8023, | |
MAX_PBUFFER_PIXELS_SGIX = 0x8018, | |
OPTIMAL_PBUFFER_HEIGHT_SGIX = 0x801A, | |
DAMAGED = 0x8020, | |
SAVED_SGIX = 0x8021, | |
TRANSPARENT_TYPE = 0x23, | |
MULTISAMPLE_SUB_RECT_WIDTH_SGIS = 0x8026, | |
NON_CONFORMANT_CONFIG = 0x800D, | |
BLUE_SIZE = 10, | |
TRUE_COLOR_EXT = 0x8002, | |
SAMPLES_SGIS = 100001, | |
SAMPLES_ARB = 100001, | |
TRUE_COLOR = 0x8002, | |
RGBA = 4, | |
AUX_BUFFERS = 7, | |
SAMPLE_BUFFERS = 100000, | |
SAVED = 0x8021, | |
MULTISAMPLE_SUB_RECT_HEIGHT_SGIS = 0x8027, | |
DAMAGED_SGIX = 0x8020, | |
STATIC_COLOR = 0x8005, | |
PBUFFER_WIDTH = 0x8041, | |
WIDTH = 0x801D, | |
LEVEL = 3, | |
CONFIG_CAVEAT = 0x20, | |
RENDER_TYPE_SGIX = 0x8011, | |
SWAP_INTERVAL_EXT = 0x20F1, | |
MAX_SWAP_INTERVAL_EXT = 0x20F2, | |
} | |
[DllImport(libGL)] | |
private extern static void glEnable(uint enable_flag); | |
[DllImport(libGL)] | |
private extern static void glViewport(int x, int y, int width, int height); | |
[DllImport(libGL)] | |
private extern static void glClearColor(float r, float g, float b, float a); | |
[DllImport(libGL)] | |
private extern static void glClear(uint clear_mask); | |
[DllImport(libGL)] | |
private extern static void glBegin(uint primitive_mode); | |
[DllImport(libGL)] | |
private extern static void glEnd(); | |
[DllImport(libGL)] | |
private extern static void glColor3f(float r, float g, float b); | |
[DllImport(libGL)] | |
private extern static void glVertex3f(float x, float y, float z); | |
// Modern OpenGL | |
[DllImport(libGL)] | |
private extern static void glGenVertexArrays(int size, uint* vaos); | |
[DllImport(libGL)] | |
private extern static void glGenBuffers(int size, uint* vbos); | |
[DllImport(libGL)] | |
private extern static void glBindVertexArray(uint array); | |
[DllImport(libGL)] | |
private extern static void glBufferData(uint target, int size, void* data, uint usage); | |
[DllImport(libGL)] | |
private extern static void glVertexAttribPointer(uint index, int size, uint type, bool normalized, int stride, void* pointer); | |
[DllImport(libGL)] | |
private extern static void glEnableVertexAttribArray(uint obj); | |
[DllImport(libGL)] | |
private extern static void glBindBuffer(uint target, uint vbo); | |
[DllImport(libGL)] | |
private extern static uint glCreateProgram(); | |
[DllImport(libGL)] | |
private extern static uint glCreateShader(uint shader_type); | |
[DllImport(libGL)] | |
private extern static void glShaderSource(uint shader_source, int count, IntPtr shader_string, int* length); | |
[DllImport(libGL)] | |
private extern static void glCompileShader(uint shader_source); | |
[DllImport(libGL)] | |
private extern static void glAttachShader(uint program, uint shader); | |
[DllImport(libGL)] | |
private extern static void glLinkProgram(uint program_source); | |
[DllImport(libGL)] | |
private extern static void glUseProgram(uint program_source); | |
[DllImport(libGL)] | |
private extern static void glDeleteShader(uint shader_source); | |
[DllImport(libGL)] | |
private extern static void glDrawArrays(uint primitive_mode, int first, int count); | |
private void LegacyOpenGL() | |
{ | |
glBegin(0x0004); | |
glColor3f(1.0f, 0.0f, 0.0f); | |
glVertex3f(0f, 0.5f, 0.0f); | |
glColor3f(0.0f, 1.0f, 0.0f); | |
glVertex3f(0.5f, -0.5f, 0.0f); | |
glColor3f(0.0f, 0.0f, 1.0f); | |
glVertex3f(-0.5f, -0.5f, 0.0f); | |
glEnd(); | |
} | |
const string vertexShaderSource = @"#version 300 es | |
precision highp float; | |
layout (location = 0) in vec4 Position0; | |
layout (location = 1) in vec4 Color0; | |
out vec4 color; | |
void main() | |
{ | |
gl_Position = Position0; | |
color = Color0; | |
}"; | |
const string fragmentShaderSource = @"#version 300 es | |
precision highp float; | |
in vec4 color; | |
out vec4 fragColor; | |
void main() | |
{ | |
fragColor = color; | |
}"; | |
private void ModernOpenGL() | |
{ | |
// Shader | |
uint vertexshader = glCreateShader(0x8B31); | |
IntPtr* textPtr = stackalloc IntPtr[1]; | |
int* lengthArray = stackalloc int[1]; | |
lengthArray[0] = vertexShaderSource.Length; | |
textPtr[0] = Marshal.StringToHGlobalAnsi(vertexShaderSource); | |
glShaderSource(vertexshader, 1, (IntPtr)textPtr, lengthArray); | |
glCompileShader(vertexshader); | |
uint fragmentshader = glCreateShader(0x8B30); | |
lengthArray[0] = fragmentShaderSource.Length; | |
textPtr[0] = Marshal.StringToHGlobalAnsi(fragmentShaderSource); | |
glShaderSource(fragmentshader, 1, (IntPtr)textPtr, lengthArray); | |
glCompileShader(fragmentshader); | |
uint shaderprogram = glCreateProgram(); | |
glAttachShader(shaderprogram, vertexshader); | |
glAttachShader(shaderprogram, fragmentshader); | |
glLinkProgram(shaderprogram); | |
glDeleteShader(vertexshader); | |
glDeleteShader(fragmentshader); | |
float[] vertices = new float[] | |
{ | |
// vertices colors | |
0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, | |
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, | |
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f | |
}; | |
// VertexArrayObject | |
uint vao = 0; | |
uint vbo = 0; | |
glGenVertexArrays(1, &vao); | |
glGenBuffers(1, &vbo); | |
glBindVertexArray(vao); | |
glBindBuffer(0x8892, vao); | |
fixed (float* verticesPtr = &vertices[0]) | |
{ | |
glBufferData(0x8892, vertices.Length * sizeof(float), verticesPtr, 0x88E4); | |
} | |
int stride = 8 * sizeof(float); | |
glVertexAttribPointer(0, 4, 0x1406, false, stride, (void*)null); | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(1, 4, 0x1406, false, stride, (void*)16); | |
glEnableVertexAttribArray(1); | |
glBindBuffer(0x8892, 0); | |
glBindVertexArray(vao); | |
glUseProgram(shaderprogram); | |
glBindVertexArray(vao); | |
glDrawArrays(0x0004, 0, 3); | |
} | |
private Random random = new Random(); | |
private bool idlehandle() | |
{ | |
if (display == IntPtr.Zero && window == IntPtr.Zero || glx_context == IntPtr.Zero) | |
{ | |
display = gdk_x11_display_get_xdisplay(area.Display.Handle); | |
window = gdk_x11_drawable_get_xid(area.GdkWindow.Handle); | |
int[] attrlist = { | |
(int)GLXAttribute.RGBA_TYPE, | |
(int)GLXAttribute.DOUBLEBUFFER, | |
24, | |
(int)GLXAttribute.NONE | |
}; | |
visualinfo = glXChooseVisual(display, area.Screen.Number, ref attrlist); | |
glx_context = glXCreateContext(display, visualinfo, IntPtr.Zero, true); | |
if (glXIsDirect(display, glx_context)) | |
{ | |
Console.WriteLine("GLX Context is direct = Yes!"); | |
} | |
} | |
else | |
{ | |
glXMakeCurrent(display, window, glx_context); | |
glEnable(0x0B71); | |
glViewport(0, 0, area.Allocation.Width, area.Allocation.Height); | |
glClear(0x00004000); | |
glClearColor(1f, .33f, 0f, 1.0f); | |
//LegacyOpenGL(); | |
ModernOpenGL(); | |
glXSwapBuffers(display, window); | |
area.Display.Sync(); | |
} | |
return true; | |
} | |
public MainClass() : base(Gtk.WindowType.Toplevel) | |
{ | |
Title = "X11/Xlib + GLX in GtkSharp 2"; | |
SetDefaultSize(500, 400); | |
SetPosition(Gtk.WindowPosition.Center); | |
Gtk.VBox container = new Gtk.VBox(false, 0); | |
Add(container); | |
area = new Gtk.DrawingArea | |
{ | |
AppPaintable = true | |
}; | |
container.PackStart(area, true, true, 0); | |
area.ButtonPressEvent += buttlepresshandler; | |
DeleteEvent += delegate { | |
glXDestroyContext(display, glx_context); | |
Gtk.Application.Quit(); | |
}; | |
ShowAll(); | |
GLib.Idle.Add(idlehandle); | |
} | |
private void buttlepresshandler(object o, Gtk.ButtonPressEventArgs args) | |
{ | |
GLib.Idle.Add(delegate | |
{ | |
glClearColor((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), 1.0f); | |
return true; | |
}); | |
} | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("Hello World - X11/Xlib + GLX in GtkSharp 2"); | |
Gtk.Application.Init(); | |
new MainClass().Show(); | |
Gtk.Application.Run(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment