1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D Programming Language: 11 * John Reimer <terminal.node@gmail.com> 12 *******************************************************************************/ 13 14 module org.eclipse.swt.opengl.GLCanvas; 15 16 import java.lang.all; 17 18 import org.eclipse.swt.SWT; 19 import org.eclipse.swt.SWTException; 20 import org.eclipse.swt.graphics.Rectangle; 21 22 import org.eclipse.swt.internal.gtk.OS; 23 import org.eclipse.swt.internal.c.glx; 24 import org.eclipse.swt.internal.c.gdk : GdkWindowAttr, GdkDrawable; 25 import org.eclipse.swt.internal.c.Xutil : XVisualInfo; 26 27 import org.eclipse.swt.internal.opengl.glx.GLX; 28 29 import org.eclipse.swt.widgets.Canvas; 30 import org.eclipse.swt.widgets.Composite; 31 import org.eclipse.swt.widgets.Event; 32 import org.eclipse.swt.widgets.Listener; 33 34 import org.eclipse.swt.opengl.GLData; 35 36 /** 37 * GLCanvas is a widget capable of displaying OpenGL content. 38 * 39 * @see GLData 40 * @see <a href="http://www.eclipse.org/swt/snippets/#opengl">OpenGL snippets</a> 41 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 42 * 43 * @since 3.2 44 */ 45 46 public class GLCanvas : Canvas { 47 void* context; 48 size_t xWindow; 49 GdkDrawable* glWindow; 50 XVisualInfo vinfo; 51 static const int MAX_ATTRIBUTES = 32; 52 53 /** 54 * Create a GLCanvas widget using the attributes described in the GLData 55 * object provided. 56 * 57 * @param parent a composite widget 58 * @param style the bitwise OR'ing of widget styles 59 * @param data the requested attributes of the GLCanvas 60 * 61 * @exception IllegalArgumentException 62 * <ul><li>ERROR_NULL_ARGUMENT when the data is null 63 * <li>ERROR_UNSUPPORTED_DEPTH when the requested attributes cannot be provided</ul> 64 * </ul> 65 */ 66 public this (Composite parent, int style, GLData data) { 67 super (parent, style); 68 if (data is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 69 int[MAX_ATTRIBUTES] glxAttrib; 70 int pos = 0; 71 glxAttrib [pos++] = GLX.GLX_RGBA; 72 if (data.doubleBuffer) glxAttrib [pos++] = GLX.GLX_DOUBLEBUFFER; 73 if (data.stereo) glxAttrib [pos++] = GLX.GLX_STEREO; 74 if (data.redSize > 0) { 75 glxAttrib [pos++] = GLX.GLX_RED_SIZE; 76 glxAttrib [pos++] = data.redSize; 77 } 78 if (data.greenSize > 0) { 79 glxAttrib [pos++] = GLX.GLX_GREEN_SIZE; 80 glxAttrib [pos++] = data.greenSize; 81 } 82 if (data.blueSize > 0) { 83 glxAttrib [pos++] = GLX.GLX_BLUE_SIZE; 84 glxAttrib [pos++] = data.blueSize; 85 } 86 if (data.alphaSize > 0) { 87 glxAttrib [pos++] = GLX.GLX_ALPHA_SIZE; 88 glxAttrib [pos++] = data.alphaSize; 89 } 90 if (data.depthSize > 0) { 91 glxAttrib [pos++] = GLX.GLX_DEPTH_SIZE; 92 glxAttrib [pos++] = data.depthSize; 93 } 94 if (data.stencilSize > 0) { 95 glxAttrib [pos++] = GLX.GLX_STENCIL_SIZE; 96 glxAttrib [pos++] = data.stencilSize; 97 } 98 if (data.accumRedSize > 0) { 99 glxAttrib [pos++] = GLX.GLX_ACCUM_RED_SIZE; 100 glxAttrib [pos++] = data.accumRedSize; 101 } 102 if (data.accumGreenSize > 0) { 103 glxAttrib [pos++] = GLX.GLX_ACCUM_GREEN_SIZE; 104 glxAttrib [pos++] = data.accumGreenSize; 105 } 106 if (data.accumBlueSize > 0) { 107 glxAttrib [pos++] = GLX.GLX_ACCUM_BLUE_SIZE; 108 glxAttrib [pos++] = data.accumBlueSize; 109 } 110 if (data.accumAlphaSize > 0) { 111 glxAttrib [pos++] = GLX.GLX_ACCUM_ALPHA_SIZE; 112 glxAttrib [pos++] = data.accumAlphaSize; 113 } 114 if (data.sampleBuffers > 0) { 115 glxAttrib [pos++] = GLX.GLX_SAMPLE_BUFFERS; 116 glxAttrib [pos++] = data.sampleBuffers; 117 } 118 if (data.samples > 0) { 119 glxAttrib [pos++] = GLX.GLX_SAMPLES; 120 glxAttrib [pos++] = data.samples; 121 } 122 glxAttrib [pos++] = 0; 123 OS.gtk_widget_realize (handle); 124 auto window = OS.GTK_WIDGET_WINDOW (handle); 125 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); 126 auto infoPtr = GLX.glXChooseVisual (xDisplay, OS.XDefaultScreen (xDisplay), glxAttrib.ptr); 127 if (infoPtr is null) { 128 dispose (); 129 SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH); 130 } 131 132 vinfo = *infoPtr; 133 //tango.stdc.string.memmove (vinfo, infoPtr, XVisualInfo.sizeof); 134 OS.XFree (infoPtr); 135 auto screen = OS.gdk_screen_get_default (); 136 auto gdkvisual = OS.gdk_x11_screen_lookup_visual (screen, vinfo.visualid); 137 //FIXME- share lists 138 //context = GLX.glXCreateContext (xDisplay, info, share is null ? 0 : share.context, true); 139 context = GLX.glXCreateContext (xDisplay, &vinfo, null, true); 140 if (context is null) 141 SWT.error (SWT.ERROR_NO_HANDLES); 142 GdkWindowAttr attrs; 143 attrs.width = 1; 144 attrs.height = 1; 145 attrs.event_mask = OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK | 146 OS.GDK_FOCUS_CHANGE_MASK | OS.GDK_POINTER_MOTION_MASK | 147 OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK | 148 OS.GDK_ENTER_NOTIFY_MASK | OS.GDK_LEAVE_NOTIFY_MASK | 149 OS.GDK_EXPOSURE_MASK | OS.GDK_VISIBILITY_NOTIFY_MASK | 150 OS.GDK_POINTER_MOTION_HINT_MASK; 151 attrs.window_type = OS.GDK_WINDOW_CHILD; 152 attrs.visual = gdkvisual; 153 glWindow = OS.gdk_window_new (window, &attrs, OS.GDK_WA_VISUAL); 154 OS.gdk_window_set_user_data ( glWindow, cast(void*) handle); 155 if ((style & SWT.NO_BACKGROUND) !is 0) 156 OS.gdk_window_set_back_pixmap (window, null, false); 157 xWindow = OS.gdk_x11_drawable_get_xid ( glWindow ); 158 OS.gdk_window_show (glWindow); 159 160 Listener listener = new class() Listener { 161 public void handleEvent (Event event) { 162 switch (event.type) { 163 case SWT.Paint: 164 /** 165 * Bug in MESA. MESA does some nasty sort of polling to try 166 * to ensure that their buffer sizes match the current X state. 167 * This state can be updated using glViewport(). 168 * FIXME: There has to be a better way of doing this. 169 */ 170 int[4] viewport; 171 GLX.glGetIntegerv (GLX.GL_VIEWPORT, viewport); 172 GLX.glViewport (viewport [0],viewport [1],viewport [2],viewport [3]); 173 break; 174 case SWT.Resize: 175 Rectangle clientArea = getClientArea(); 176 OS.gdk_window_move (glWindow, clientArea.x, clientArea.y); 177 OS.gdk_window_resize (glWindow, clientArea.width, clientArea.height); 178 break; 179 case SWT.Dispose: 180 auto window = OS.GTK_WIDGET_WINDOW (handle); 181 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); 182 if (context !is null) { 183 if (GLX.glXGetCurrentContext () is context) { 184 GLX.glXMakeCurrent (xDisplay, 0, null); 185 } 186 GLX.glXDestroyContext (xDisplay, context); 187 context = null; 188 } 189 if (glWindow !is null) { 190 OS.gdk_window_destroy (glWindow); 191 glWindow = null; 192 } 193 break; 194 default: break; 195 } 196 } 197 }; 198 addListener (SWT.Resize, listener); 199 addListener (SWT.Paint, listener); 200 addListener (SWT.Dispose, listener); 201 } 202 203 /** 204 * Returns a GLData object describing the created context. 205 * 206 * @return GLData description of the OpenGL context attributes 207 * @exception SWTException <ul> 208 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 209 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 210 * </ul> 211 */ 212 public GLData getGLData () { 213 checkWidget (); 214 auto window = OS.GTK_WIDGET_WINDOW (handle); 215 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); 216 GLData data = new GLData (); 217 int [1] value; 218 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_DOUBLEBUFFER, value); 219 data.doubleBuffer = value [0] !is 0; 220 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_STEREO, value); 221 data.stereo = value [0] !is 0; 222 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_RED_SIZE, value); 223 data.redSize = value [0]; 224 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_GREEN_SIZE, value); 225 data.greenSize = value [0]; 226 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_BLUE_SIZE, value); 227 data.blueSize = value [0]; 228 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_ALPHA_SIZE, value); 229 data.alphaSize = value [0]; 230 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_DEPTH_SIZE, value); 231 data.depthSize = value [0]; 232 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_STENCIL_SIZE, value); 233 data.stencilSize = value [0]; 234 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_ACCUM_RED_SIZE, value); 235 data.accumRedSize = value [0]; 236 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_ACCUM_GREEN_SIZE, value); 237 data.accumGreenSize = value [0]; 238 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_ACCUM_BLUE_SIZE, value); 239 data.accumBlueSize = value [0]; 240 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_ACCUM_ALPHA_SIZE, value); 241 data.accumAlphaSize = value [0]; 242 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_SAMPLE_BUFFERS, value); 243 data.sampleBuffers = value [0]; 244 GLX.glXGetConfig (xDisplay, &vinfo, GLX.GLX_SAMPLES, value); 245 data.samples = value [0]; 246 return data; 247 } 248 249 /** 250 * Returns a bool indicating whether the receiver's OpenGL context 251 * is the current context. 252 * 253 * @return true if the receiver holds the current OpenGL context, 254 * false otherwise 255 * @exception SWTException <ul> 256 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 257 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 258 * </ul> 259 */ 260 public bool isCurrent () { 261 checkWidget (); 262 return (GLX.glXGetCurrentContext () is context); 263 } 264 265 /** 266 * Sets the OpenGL context associated with this GLCanvas to be the 267 * current GL context. 268 * 269 * @exception SWTException <ul> 270 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 271 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 272 * </ul> 273 */ 274 public void setCurrent () { 275 checkWidget (); 276 if (GLX.glXGetCurrentContext () is context) return; 277 auto window = OS.GTK_WIDGET_WINDOW (handle); 278 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); 279 GLX.glXMakeCurrent (xDisplay, xWindow, context); 280 } 281 282 /** 283 * Swaps the front and back color buffers. 284 * 285 * @exception SWTException <ul> 286 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 287 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 288 * </ul> 289 */ 290 public void swapBuffers () { 291 checkWidget (); 292 auto window = OS.GTK_WIDGET_WINDOW (handle); 293 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (window); 294 GLX.glXSwapBuffers (xDisplay, xWindow); 295 } 296 }