1 unit uglcContextGtk2GLX;
\r
3 { Package: OpenGLCore
\r
4 Prefix: glc - OpenGL Core
\r
5 Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Kontexte für Linux
\r
6 Hint: diese Unit sollte niemals direkt genutzt werden (siehe uglcContext) }
\r
11 SysUtils, Controls, uglcContext, LCLType, XUtil, XLib, gdk2x, gtk2, gdk2, dglOpenGL,
\r
12 LMessages, uglcContextGtkCustomVisual;
\r
15 EGLXError = class(EGLError);
\r
17 TRenderControl = class(TCustomVisualControl)
\r
19 fTarget: TWinControl;
\r
21 procedure WndProc(var Message: TLMessage); override;
\r
23 property Target: TWinControl read fTarget write fTarget;
\r
26 { TglcContextGtk2GLX }
\r
28 TglcContextGtk2GLX = class(TglcContext)
\r
30 FVisual: PXVisualInfo;
\r
32 FWidget: PGtkWidget;
\r
33 FContext: GLXContext;
\r
34 FRenderControl: TRenderControl;
\r
35 procedure UpdateVisual(const aControl: TWinControl);
\r
37 procedure OpenContext; override;
\r
39 constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings); override; overload;
\r
40 constructor Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings); override; overload;
\r
41 destructor Destroy; override;
\r
43 procedure CloseContext; override;
\r
44 procedure Activate; override;
\r
45 procedure Deactivate; override;
\r
46 function IsActive: boolean; override;
\r
47 procedure SwapBuffers; override;
\r
48 procedure SetSwapInterval(const aInterval: GLint); override;
\r
49 procedure Share(const aContext: TglcContext); override;
\r
51 class function ChangeDisplaySettings(const aWidth, aHeight,
\r
52 aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean; override;
\r
53 class function IsAnyContextActive: boolean; override;
\r
59 TGLIntArray = packed array of GLInt;
\r
61 {$region messages -fold}
\r
62 procedure TRenderControl.WndProc(var Message: TLMessage);
\r
86 LM_LBUTTONTRIPLECLK,
\r
88 LM_MBUTTONTRIPLECLK,
\r
90 LM_RBUTTONTRIPLECLK,
\r
94 LM_XBUTTONTRIPLECLK,
\r
124 //LM_GETTEXTLENGTH,
\r
133 //LM_WINDOWPOSCHANGING,
\r
134 //LM_WINDOWPOSCHANGED,
\r
147 LM_NCLBUTTONDBLCLK,
\r
159 //LM_CTLCOLORMSGBOX,
\r
161 //LM_CTLCOLORLISTBOX,
\r
164 //LM_CTLCOLORSCROLLBAR,
\r
165 //LM_CTLCOLORSTATIC,
\r
181 //LM_CAPTURECHANGED,
\r
188 //LM_CONFIGUREEVENT,
\r
200 //CM_PARENTFONTCHANGED,
\r
201 //CM_PARENTCOLORCHANGED,
\r
203 //CM_VISIBLECHANGED,
\r
204 //CM_ENABLEDCHANGED,
\r
207 //CM_CURSORCHANGED,
\r
212 //CM_APPSYSCOMMAND,
\r
213 //CM_BUTTONPRESSED,
\r
214 //CM_SHOWINGCHANGED,
\r
217 //CM_DESIGNHITTEST,
\r
219 //CM_WANTSPECIALKEY,
\r
222 //CM_TABSTOPCHANGED,
\r
224 //CM_CONTROLLISTCHANGE,
\r
228 //CM_SYSFONTCHANGED,
\r
229 //CM_CONTROLCHANGE,
\r
231 //CM_BORDERCHANGED,
\r
232 //CM_BIDIMODECHANGED,
\r
233 //CM_PARENTBIDIMODECHANGED,
\r
234 //CM_ALLCHILDRENFLIPPED,
\r
236 //CM_ACTIONEXECUTE,
\r
237 //CM_HINTSHOWPAUSE,
\r
238 //CM_DOCKNOTIFICATION,
\r
240 //CM_APPSHOWBTNGLYPHCHANGED,
\r
241 //CM_APPSHOWMENUGLYPHCHANGED,
\r
250 //CN_CTLCOLORLISTBOX,
\r
251 //CN_CTLCOLORMSGBOX,
\r
252 //CN_CTLCOLORSCROLLBAR,
\r
253 //CN_CTLCOLORSTATIC,
\r
269 if Assigned(fTarget) then
\r
270 Message.Result := fTarget.Perform(Message.msg, Message.wParam, Message.lParam);
\r
273 inherited WndProc(Message);
\r
278 function CreateOpenGLContextAttrList(UseFB: boolean; pf: TglcContextPixelFormatSettings): TGLIntArray;
\r
282 procedure Add(i: integer);
\r
284 SetLength(Result, p+1);
\r
289 procedure CreateList;
\r
291 if UseFB then begin Add(GLX_X_RENDERABLE); Add(1); end;
\r
292 if pf.DoubleBuffered then begin
\r
293 if UseFB then begin
\r
294 Add(GLX_DOUBLEBUFFER); Add(1);
\r
296 Add(GLX_DOUBLEBUFFER);
\r
298 if not UseFB and (pf.ColorBits>24) then Add(GLX_RGBA);
\r
299 if UseFB then begin
\r
300 Add(GLX_DRAWABLE_TYPE);
\r
301 Add(GLX_WINDOW_BIT);
\r
303 Add(GLX_RED_SIZE); Add(8);
\r
304 Add(GLX_GREEN_SIZE); Add(8);
\r
305 Add(GLX_BLUE_SIZE); Add(8);
\r
306 if pf.ColorBits>24 then
\r
307 Add(GLX_ALPHA_SIZE); Add(8);
\r
308 Add(GLX_DEPTH_SIZE); Add(pf.DepthBits);
\r
309 Add(GLX_STENCIL_SIZE); Add(pf.StencilBits);
\r
310 Add(GLX_AUX_BUFFERS); Add(pf.AUXBuffers);
\r
312 if pf.MultiSampling > 1 then begin
\r
313 Add(GLX_SAMPLE_BUFFERS_ARB); Add(1);
\r
314 Add(GLX_SAMPLES_ARB); Add(pf.MultiSampling);
\r
317 Add(0); { 0 = X.None (be careful: GLX_NONE is something different) }
\r
321 SetLength(Result, 0);
\r
326 function FBglXChooseVisual(dpy:PDisplay; screen:longint; attrib_list:Plongint):PXVisualInfo;
\r
328 PGLXFBConfig = ^GLXFBConfig;
\r
330 FBConfigsCount: integer;
\r
331 FBConfigs: PGLXFBConfig;
\r
332 FBConfig: GLXFBConfig;
\r
336 FBConfigs:= glXChooseFBConfig(dpy, screen, attrib_list, @FBConfigsCount);
\r
337 if FBConfigsCount = 0 then
\r
340 { just choose the first FB config from the FBConfigs list.
\r
341 More involved selection possible. }
\r
342 FBConfig := FBConfigs^;
\r
343 Result:=glXGetVisualFromFBConfig(dpy, FBConfig);
\r
347 { TglcContextGtk2GLX }
\r
349 procedure TglcContextGtk2GLX.UpdateVisual(const aControl: TWinControl);
\r
351 attrList: TGLIntArray;
\r
352 drawable: PGdkDrawable;
\r
355 Temporary (realized) widget to get to display
\r
357 FWidget:= {%H-}PGtkWidget(PtrUInt(aControl.Handle));
\r
358 gtk_widget_realize(FWidget);
\r
359 drawable:= GTK_WIDGET(FWidget)^.window;
\r
361 FDisplay:= GDK_WINDOW_XDISPLAY(drawable);
\r
364 Find a suitable visual from PixelFormat using GLX 1.3 FBConfigs or
\r
367 if Assigned(glXChooseFBConfig) then begin
\r
368 attrList := CreateOpenGLContextAttrList(true, fPixelFormatSettings);
\r
369 FVisual := FBglXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
\r
370 if not Assigned(FVisual) and (fPixelFormatSettings.MultiSampling > 1) then begin
\r
371 fPixelFormatSettings.MultiSampling := 1;
\r
372 attrList := CreateOpenGLContextAttrList(true, fPixelFormatSettings);
\r
373 FVisual := FBglXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
\r
376 if not Assigned(FVisual) then begin
\r
377 attrList := CreateOpenGLContextAttrList(false, fPixelFormatSettings);
\r
378 FVisual := glXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
\r
379 if not Assigned(FVisual) and (fPixelFormatSettings.MultiSampling > 1) then begin
\r
380 fPixelFormatSettings.MultiSampling := 1;
\r
381 attrList := CreateOpenGLContextAttrList(false, fPixelFormatSettings);
\r
382 FVisual := glXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
\r
387 Most widgets inherit the drawable of their parent. In contrast to Windows, descending from
\r
388 TWinControl does not mean it's actually always a window of its own.
\r
389 Famous example: TPanel is just a frame painted on a canvas.
\r
390 Also, the LCL does somethin weird to colormaps in window creation, so we have
\r
391 to use a custom widget here to have full control about visual selection.
\r
393 FRenderControl:= TRenderControl.Create(aControl, FVisual^.visual^.visualid);
\r
395 FRenderControl.Parent := aControl;
\r
396 FRenderControl.HandleNeeded;
\r
397 FRenderControl.Target := aControl;
\r
399 FreeAndNil(FRenderControl);
\r
404 Real Widget handle, unrealized!!!
\r
406 FWidget:= FRenderControl.Widget;
\r
407 gtk_widget_realize(FWidget);
\r
408 drawable:= GTK_WIDGET(FWidget)^.window;
\r
409 FDisplay:= GDK_WINDOW_XDISPLAY(drawable);
\r
411 // FRenderControl.Align:= alClient breaks the context or something
\r
412 FRenderControl.BoundsRect := aControl.ClientRect;
\r
413 FRenderControl.Anchors := [akLeft, akTop, akRight, akBottom];
\r
416 procedure TglcContextGtk2GLX.OpenContext;
\r
418 Attribs: array of GLint;
\r
419 tmpContext: GLXContext;
\r
420 glxID: GLXDrawable;
\r
422 inherited OpenContext;
\r
424 if not Assigned(FVisual) then
\r
425 raise EGLXError.Create('Failed to find Visual');
\r
427 tmpContext := glXCreateContext(FDisplay, FVisual, nil, true);
\r
429 (fVersionSettings.Major <> GLC_CONTEXT_VERSION_UNKNOWN) and
\r
430 (fVersionSettings.Minor <> GLC_CONTEXT_VERSION_UNKNOWN) then
\r
432 // Set attributes to describe our requested context
\r
433 SetLength(Attribs, 5);
\r
434 Attribs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB;
\r
435 Attribs[1] := fVersionSettings.Major;
\r
436 Attribs[2] := WGL_CONTEXT_MINOR_VERSION_ARB;
\r
437 Attribs[3] := fVersionSettings.Minor;
\r
439 // Add context flag for forward compatible context
\r
440 // Forward compatible means no more support for legacy functions like
\r
441 // immediate mode (glvertex, glrotate, gltranslate, etc.)
\r
442 if fVersionSettings.ForwardCompatible then begin
\r
443 SetLength(Attribs, Length(Attribs)+2);
\r
444 Attribs[4] := WGL_CONTEXT_FLAGS_ARB;
\r
445 Attribs[5] := WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
\r
448 // Attribute flags must be finalized with a zero
\r
449 SetLength(Attribs, 1);
\r
450 Attribs[High(Attribs)] := 0;
\r
452 glxID := GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window);
\r
453 glXMakeCurrent(FDisplay, glxID, tmpContext);
\r
454 ReadImplementationProperties;
\r
455 if not Assigned(glXCreateContextAttribsARB) or not GLX_ARB_create_context then begin
\r
456 glXDestroyContext(FDisplay, tmpContext);
\r
457 raise Exception.Create('GLX_ARB_create_context not supported');
\r
459 FContext := glXCreateContextAttribsARB(FDisplay, FVisual, nil, true, @Attribs[0]);
\r
461 glXDestroyContext(FDisplay, tmpContext);
\r
463 FContext := tmpContext;
\r
465 if (FContext = nil) then
\r
466 raise EGLXError.Create('Failed to create Context');
\r
469 constructor TglcContextGtk2GLX.Create(const aControl: TWinControl;
\r
470 const aPixelFormatSettings: TglcContextPixelFormatSettings);
\r
472 inherited Create(aControl, aPixelFormatSettings);
\r
473 UpdateVisual(aControl);
\r
476 constructor TglcContextGtk2GLX.Create(const aControl: TWinControl;
\r
477 const aPixelFormatSettings: TglcContextPixelFormatSettings;
\r
478 const aVersionSettings: TglcContextVersionSettings);
\r
480 inherited Create(aControl, aPixelFormatSettings, aVersionSettings);
\r
481 UpdateVisual(aControl);
\r
484 destructor TglcContextGtk2GLX.Destroy;
\r
486 FreeAndNil(FRenderControl);
\r
491 procedure TglcContextGtk2GLX.CloseContext;
\r
493 if not Assigned(FWidget) then exit;
\r
494 if Assigned(FContext) then
\r
495 glXDestroyContext(FDisplay, FContext);
\r
496 FreeAndNil(FRenderControl);
\r
499 procedure TglcContextGtk2GLX.Activate;
\r
501 glxID: GLXDrawable;
\r
503 if not Assigned(FWidget) then exit;
\r
504 // make sure the widget is realized
\r
505 gtk_widget_realize(FWidget);
\r
506 if not GTK_WIDGET_REALIZED(FWidget) then exit;
\r
509 glxID := GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window);
\r
510 glXMakeCurrent(FDisplay, glxID, FContext);
\r
513 procedure TglcContextGtk2GLX.Deactivate;
\r
515 glxID: GLXDrawable;
\r
517 if not Assigned(FWidget) then exit;
\r
518 glxID := GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window);
\r
519 glXMakeCurrent(FDisplay, glxID, nil);
\r
522 function TglcContextGtk2GLX.IsActive: boolean;
\r
524 glxID: GLXDrawable;
\r
526 glxID := GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window);
\r
527 Result:= (FContext = glXGetCurrentContext()) and
\r
528 Assigned(FWidget) and
\r
529 (glxID = glXGetCurrentDrawable());
\r
532 procedure TglcContextGtk2GLX.SwapBuffers;
\r
534 glxID: GLXDrawable;
\r
536 if not Assigned(FWidget) then exit;
\r
537 glxID := GDK_DRAWABLE_XID(GTK_WIDGET(FWidget)^.window);
\r
538 glXSwapBuffers(FDisplay, glxID);
\r
541 procedure TglcContextGtk2GLX.SetSwapInterval(const aInterval: GLint);
\r
543 drawable: PGdkDrawable;
\r
545 drawable:= GTK_WIDGET(FWidget)^.window;
\r
546 if GLX_EXT_swap_control then
\r
547 glXSwapIntervalEXT(FDisplay, GDK_WINDOW_XWINDOW(drawable), aInterval);
\r
550 procedure TglcContextGtk2GLX.Share(const aContext: TglcContext);
\r
552 raise Exception.Create('not yet implemented');
\r
555 class function TglcContextGtk2GLX.{%H-}ChangeDisplaySettings(const aWidth, aHeight,
\r
556 aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean;
\r
558 raise Exception.Create('not yet implemented');
\r
561 class function TglcContextGtk2GLX.IsAnyContextActive: boolean;
\r
563 Result:= (glXGetCurrentContext()<>nil) and (glXGetCurrentDrawable()<>0);
\r