mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-07 05:58:15 +02:00
243 lines
7.3 KiB
ObjectPascal
243 lines
7.3 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
* *
|
|
* See the file COPYING.modifiedLGPL, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
}
|
|
unit GLGtk2GLXContext;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$LinkLib GL}
|
|
{$PACKRECORDS C}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLProc, LCLType, X, XUtil, XLib, gl, InterfaceBase,
|
|
WSLCLClasses, GtkWSControls,
|
|
{$IFDEF LCLGTK2}
|
|
GtkDef, glx, gdk2x, glib2, gdk2, gtk2, Gtk2Int,
|
|
{$ENDIF}
|
|
{$IFDEF LCLGTK}
|
|
glib, gdk, gtk, GtkInt,
|
|
{$ENDIF}
|
|
Controls;
|
|
|
|
procedure LOpenGLViewport(Left, Top, Width, Height: integer);
|
|
procedure LOpenGLSwapBuffers(Handle: HWND);
|
|
function LOpenGLMakeCurrent(Handle: HWND): boolean;
|
|
function LOpenGLCreateContext(AWinControl: TWinControl;
|
|
WSPrivate: TWSPrivateClass; SharedControl: TWinControl;
|
|
DoubleBuffered, RGBA: boolean): HWND;
|
|
procedure LOpenGLDestroyContextInfo(AWinControl: TWinControl);
|
|
function CreateOpenGLContextAttrList(DoubleBuffered: boolean;
|
|
RGBA: boolean): PInteger;
|
|
|
|
type
|
|
TWidgetSetWSWinControl = TGtkWSWinControl;
|
|
|
|
implementation
|
|
|
|
type
|
|
TLOpenGLInfo = record
|
|
Control: TWinControl;
|
|
xdisplay: PDisplay;
|
|
glxcontext: TGLXContext;
|
|
ref_count: guint;
|
|
AttrList: PInteger;
|
|
Mapped: boolean;
|
|
XWindow: x.TWindow;
|
|
end;
|
|
PLOpenGLInfo = ^TLOpenGLInfo;
|
|
|
|
procedure InternalResizeWnd(AWinControl: TWinControl);
|
|
var
|
|
Info: PLOpenGLInfo;
|
|
Widget: PGtkWidget;
|
|
begin
|
|
if (not AWinControl.HandleAllocated) then exit;
|
|
Widget:=PGtkWidget(AWinControl.Handle);
|
|
Info:=PLOpenGLInfo(gtk_object_get_data(PGtkObject(Widget),'LOpenGLInfo'));
|
|
|
|
DebugLn(['InternalResizeWnd ',dbgs(AWinControl.BoundsRect)]);
|
|
with Info^ do begin
|
|
if (AWinControl.Width > 0) and (AWinControl.Height > 0) then begin
|
|
if not Mapped then begin
|
|
Mapped:=True;
|
|
XMapWindow(xdisplay, XWindow);
|
|
end;
|
|
XResizeWindow(xdisplay, XWindow, AWinControl.Width, AWinControl.Height);
|
|
end else begin
|
|
if Mapped then begin
|
|
XUnmapWindow(xdisplay, XWindow);
|
|
Mapped:=False;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure LOpenGLViewport(Left, Top, Width, Height: integer);
|
|
begin
|
|
glViewport(Left,Top,Width,Height);
|
|
end;
|
|
|
|
procedure LOpenGLSwapBuffers(Handle: HWND);
|
|
var
|
|
Info: PLOpenGLInfo;
|
|
begin
|
|
Info:=PLOpenGLInfo(gtk_object_get_data(PGtkObject(Handle),'LOpenGLInfo'));
|
|
glXSwapBuffers(Info^.xdisplay, Info^.XWindow);
|
|
end;
|
|
|
|
function LOpenGLMakeCurrent(Handle: HWND): boolean;
|
|
var
|
|
Info: PLOpenGLInfo;
|
|
begin
|
|
Info:=PLOpenGLInfo(gtk_object_get_data(PGtkObject(Handle),'LOpenGLInfo'));
|
|
Result:=glXMakeCurrent(Info^.xdisplay, Info^.XWindow, Info^.glxcontext);
|
|
DebugLn(['LOpenGLMakeCurrent Result=',Result]);
|
|
InternalResizeWnd(Info^.Control);
|
|
end;
|
|
|
|
function gtkRealizeAfter(Widget: PGtkWidget; Data: Pointer): GBoolean; cdecl;
|
|
var
|
|
GdkWindow: PGdkWindow;
|
|
CurXWindow: TXID;
|
|
Info: PLOpenGLInfo;
|
|
XVInfo: PXVisualInfo;
|
|
ColorMap: TColormap;
|
|
WinAttr: TXSetWindowAttributes;
|
|
LCLControl: TWinControl;
|
|
begin
|
|
Result:={$IFDEF GTK2}false{$ELSE}true{$ENDIF};
|
|
|
|
DebugLn(['gtkRealizeAfter ']);
|
|
// disable gtk painting
|
|
gdk_window_set_back_pixmap(Widget^.Window, nil, GdkFalse);
|
|
|
|
GdkWindow:=Widget^.window;
|
|
CurXWindow:=gdk_window_xwindow(PGdkDrawable(GdkWindow));
|
|
|
|
Info:=PLOpenGLInfo(gtk_object_get_data(PGtkObject(Widget),'LOpenGLInfo'));
|
|
|
|
XVInfo:=glXChooseVisual(Info^.XDisplay, DefaultScreen(Info^.XDisplay), @Info^.AttrList[0]);
|
|
ColorMap:=XCreateColormap(Info^.XDisplay, CurXWindow, XVInfo^.visual, AllocNone);
|
|
|
|
FillChar(WinAttr, SizeOf(WinAttr), 0);
|
|
WinAttr.event_mask:=0; //ExposureMask;
|
|
WinAttr.colormap:=ColorMap;
|
|
|
|
LCLControl:=TWinControl(Data);
|
|
|
|
Info^.XWindow:=XCreateWindow(Info^.XDisplay, CurXWindow,
|
|
LCLControl.Left+30, LCLControl.Top+30, LCLControl.Width, LCLControl.Height, 0,
|
|
XVInfo^.depth, InputOutput, XVInfo^.visual, CWColormap, @WinAttr);
|
|
{Info^.XWindow:=XCreateSimpleWindow(Info^.XDisplay, CurXWindow,
|
|
LCLControl.Left+30, LCLControl.Top+30, LCLControl.Width, LCLControl.Height,
|
|
0,0,0);}
|
|
//Info^.XWindow:=CurXWindow;
|
|
|
|
Info^.glxcontext:=glXCreateContext(Info^.XDisplay, XVInfo, nil, True);
|
|
DebugLn(['gtkRealizeAfter ',dbgs(Info^.glxcontext),' mapped=',GTK_WIDGET_MAPPED(Widget)]);
|
|
glXMakeCurrent(Info^.xdisplay, Info^.XWindow, Info^.glxcontext);
|
|
InternalResizeWnd(LCLControl);
|
|
end;
|
|
|
|
function LOpenGLCreateContext(AWinControl: TWinControl;
|
|
WSPrivate: TWSPrivateClass; SharedControl: TWinControl; DoubleBuffered,
|
|
RGBA: boolean): HWND;
|
|
var
|
|
NewWidget: PGtkWidget;
|
|
Info: PLOpenGLInfo;
|
|
begin
|
|
if WSPrivate=nil then ;
|
|
if SharedControl<>nil then begin
|
|
//SharedArea:=PGtkGLArea(SharedControl.Handle);
|
|
//if not GTK_IS_GL_AREA(SharedArea) then
|
|
// RaiseGDBException('LOpenGLCreateContext');
|
|
//NewWidget:=gtk_gl_area_share_new(AttrList,SharedArea);
|
|
end else begin
|
|
//NewWidget:=gtk_gl_area_new(AttrList);
|
|
NewWidget:=gtk_frame_new('Test');
|
|
{$IFDEF GTK2}
|
|
gtk_fixed_set_has_window(PGtkFixed(Result), True);
|
|
{$ENDIF}
|
|
g_signal_connect_after(PGtkObject(NewWidget), 'realize',
|
|
TGTKSignalFunc(@GTKRealizeAfter), AWinControl);
|
|
New(Info);
|
|
FillChar(Info^,SizeOf(Info),0);
|
|
Info^.Control:=AWinControl;
|
|
Info^.xdisplay:=gdk_display;
|
|
Info^.AttrList:=CreateOpenGLContextAttrList(DoubleBuffered,RGBA);
|
|
gtk_object_set_data(PGtkObject(NewWidget),'LOpenGLInfo',Info);
|
|
//gtk_widget_set_double_buffered(NewWidget,false);
|
|
end;
|
|
Result:=HWND(NewWidget);
|
|
PGtkobject(NewWidget)^.flags:=PGtkobject(NewWidget)^.flags or GTK_CAN_FOCUS;
|
|
{$IFDEF LCLGtk}
|
|
TGTKWidgetSet(WidgetSet).FinishComponentCreate(AWinControl,NewWidget);
|
|
{$ELSE}
|
|
TGTK2WidgetSet(WidgetSet).FinishComponentCreate(AWinControl,NewWidget);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure LOpenGLDestroyContextInfo(AWinControl: TWinControl);
|
|
var
|
|
Info: PLOpenGLInfo;
|
|
begin
|
|
if not AWinControl.HandleAllocated then exit;
|
|
Info:=PLOpenGLInfo(gtk_object_get_data(PGtkObject(AWinControl.Handle),'LOpenGLInfo'));
|
|
gtk_object_set_data(PGtkObject(AWinControl.Handle),'LOpenGLInfo',nil);
|
|
ReAllocMem(Info^.AttrList,0);
|
|
glXDestroyContext(Info^.xdisplay, Info^.glxcontext);
|
|
XDestroyWindow(Info^.xdisplay, Info^.XWindow);
|
|
Dispose(Info);
|
|
end;
|
|
|
|
function CreateOpenGLContextAttrList(DoubleBuffered: boolean; RGBA: boolean
|
|
): PInteger;
|
|
var
|
|
p: integer;
|
|
|
|
procedure Add(i: integer);
|
|
begin
|
|
if Result<>nil then
|
|
Result[p]:=i;
|
|
inc(p);
|
|
end;
|
|
|
|
procedure CreateList;
|
|
begin
|
|
if DoubleBuffered then
|
|
Add(GLX_DOUBLEBUFFER);
|
|
if RGBA then
|
|
Add(GLX_RGBA);
|
|
Add(GLX_RED_SIZE); Add(1);
|
|
Add(GLX_GREEN_SIZE); Add(1);
|
|
Add(GLX_BLUE_SIZE); Add(1);
|
|
Add(GLX_DEPTH_SIZE); Add(1);
|
|
Add(GLX_STENCIL_SIZE); Add(1);
|
|
Add(0);
|
|
end;
|
|
|
|
begin
|
|
Result:=nil;
|
|
p:=0;
|
|
CreateList;
|
|
GetMem(Result,SizeOf(integer)*p);
|
|
p:=0;
|
|
CreateList;
|
|
end;
|
|
|
|
end.
|
|
|