mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-07 07:18:14 +02:00
343 lines
10 KiB
ObjectPascal
343 lines
10 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
ToDo: MultiSampling, AuxBuffers
|
|
}
|
|
unit GLCarbonAGLContext;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, LCLProc, LCLType, gl, Forms,
|
|
MacOSAll,
|
|
AGL, CarbonProc, CarbonDef, CarbonPrivate,
|
|
WSLCLClasses, CarbonUtils,
|
|
Controls;
|
|
|
|
procedure LOpenGLViewport(Handle: HWND; Left, Top, Width, Height: integer);
|
|
procedure LOpenGLSwapBuffers(Handle: HWND);
|
|
function LOpenGLMakeCurrent(Handle: HWND): boolean;
|
|
function LOpenGLReleaseContext(Handle: HWND): boolean;
|
|
procedure LOpenGLClip(Handle: HWND);
|
|
function LOpenGLCreateContext(AWinControl: TWinControl;
|
|
{%H-}WSPrivate: TWSPrivateClass; SharedControl: TWinControl;
|
|
DoubleBuffered, RGBA: boolean;
|
|
const RedBits, GreenBits, BlueBits: Cardinal;
|
|
const MultiSampling, AlphaBits, DepthBits, StencilBits, AUXBuffers: Cardinal;
|
|
const {%H-}AParams: TCreateParams): HWND;
|
|
procedure LOpenGLDestroyContextInfo(AWinControl: TWinControl);
|
|
function CreateOpenGLContextAttrList(DoubleBuffered: boolean; RGBA: boolean;
|
|
RedBits, GreenBits, BlueBits, MultiSampling, AlphaBits, DepthBits,
|
|
StencilBits, AUXBuffers: cardinal): PInteger;
|
|
|
|
|
|
type
|
|
TAGLControlInfo = record
|
|
Control: ControlRef;
|
|
WinControl: TWinControl;
|
|
AGLContext: TAGLContext;
|
|
end;
|
|
PAGLControlInfo = ^TAGLControlInfo;
|
|
|
|
var
|
|
AGLControlInfo_FOURCC: FourCharCode;
|
|
|
|
function CreateAGLControlInfo(Control: ControlRef; AGLContext: TAGLContext;
|
|
WinControl: TWinControl): PAGLControlInfo;
|
|
function GetAGLControlInfo(Control: ControlRef): PAGLControlInfo;
|
|
procedure FreeAGLControlInfo(Control: ControlRef);
|
|
function GetAGLContext(Control: ControlRef): TAGLContext;
|
|
|
|
implementation
|
|
|
|
procedure LOpenGLViewport(Handle: HWND; Left, Top, Width, Height: integer);
|
|
begin
|
|
glViewport(Left,Top,Width,Height);
|
|
end;
|
|
|
|
procedure LOpenGLSwapBuffers(Handle: HWND);
|
|
var
|
|
AGLContext: TAGLContext;
|
|
begin
|
|
AGLContext:=GetAGLContext({%H-}ControlRef(Handle));
|
|
aglSwapBuffers(AGLContext);
|
|
end;
|
|
|
|
function LOpenGLMakeCurrent(Handle: HWND): boolean;
|
|
var
|
|
AGLContext: TAGLContext;
|
|
Info: PAGLControlInfo;
|
|
Control: TCarbonCustomControl;
|
|
begin
|
|
Control:=TCarbonCustomControl(Handle);
|
|
Info:=GetAGLControlInfo(Control.Widget);
|
|
if Info=nil then exit;
|
|
AGLContext:=Info^.AGLContext;
|
|
Result:=aglSetCurrentContext(AGLContext)<>0;
|
|
end;
|
|
|
|
function LOpenGLReleaseContext(Handle: HWND): boolean;
|
|
begin
|
|
Result := aglSetCurrentContext(nil)<>GL_FALSE;
|
|
end;
|
|
|
|
procedure LOpenGLClip(Handle: HWND);
|
|
var
|
|
AGLContext: TAGLContext;
|
|
Info: PAGLControlInfo;
|
|
Form: TCustomForm;
|
|
Win: WindowRef;
|
|
//b: Rect;
|
|
clipRgn: RgnHandle;
|
|
Control: TCarbonCustomControl;
|
|
begin
|
|
Control:=TCarbonCustomControl(Handle);
|
|
Info:=GetAGLControlInfo(Control.Widget);
|
|
debugln(['LOpenGLMakeCurrent got ingo...']);
|
|
if Info=nil then exit;
|
|
AGLContext:=Info^.AGLContext;
|
|
aglSetCurrentContext(AGLContext);
|
|
debugln(['LOpenGLMakeCurrent set current ',dbgs(Handle)]);
|
|
Form:=GetParentForm(Info^.WinControl);
|
|
debugln(['LOpenGLMakeCurrent got parent form: ',DbgSName(Form)]);
|
|
Win:=TCarbonWindow(Form.Handle).Window;
|
|
|
|
debugln(['LOpenGLMakeCurrent set clipping ...']);
|
|
//GetWindowPortBounds(Win,b);
|
|
clipRgn:=NewRgn;
|
|
SetRectRgn(clipRgn,10,10,100,100);
|
|
aglSetInteger({%H-}TAGLContext(GetWRefCon(Win)),AGL_CLIP_REGION,clipRgn);
|
|
aglEnable({%H-}TAGLContext(GetWRefCon(Win)),AGL_CLIP_REGION);
|
|
DisposeRgn(clipRgn);
|
|
end;
|
|
|
|
procedure ResizeOGLControl(AWidget: TCarbonWidget);
|
|
var
|
|
info : PAGLControlInfo;
|
|
r : array [0..3] of Integer;
|
|
bnd : HIRect;
|
|
str : MacOSAll.Rect;
|
|
win : WindowRef;
|
|
begin
|
|
info:=GetAGLControlInfo(AWidget.Widget);
|
|
if not Assigned(info) then Exit;
|
|
win:=HIViewGetWindow(AWidget.Widget);
|
|
if not Assigned(win) then Exit;
|
|
GetWindowBounds(win, kWindowStructureRgn, str{%H-});
|
|
HIViewGetBounds(AWidget.Widget, bnd{%H-});
|
|
HIViewConvertPoint(bnd.origin, AWidget.Widget, nil);
|
|
|
|
r[0]:=Round(bnd.origin.x);
|
|
r[1]:=Round((str.bottom-str.top)- bnd.origin.y-bnd.size.height);
|
|
r[2]:=Round(bnd.size.width);
|
|
r[3]:=Round(bnd.size.height);
|
|
|
|
aglEnable(info^.aglContext, AGL_BUFFER_RECT);
|
|
aglSetInteger(info^.aglContext, AGL_BUFFER_RECT, @r[0]);
|
|
end;
|
|
|
|
function CarbonGLControl_Resize(ANextHandler: EventHandlerCallRef;
|
|
AEvent: EventRef;
|
|
AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF}
|
|
begin
|
|
Result:=CallNextEventHandler(ANextHandler, AEvent);
|
|
ResizeOGLControl(AWidget);
|
|
end;
|
|
|
|
function CarbonGLControl_WindowChange(ANextHandler: EventHandlerCallRef;
|
|
AEvent: EventRef;
|
|
AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF}
|
|
var
|
|
win : WindowRef;
|
|
begin
|
|
Result:=CallNextEventHandler(ANextHandler, AEvent);
|
|
if GetEventParameter(AEvent, kEventParamControlCurrentOwningWindow, typeWindowRef,
|
|
nil, sizeof(win), nil, @win) = noErr then
|
|
if Assigned(win) then ResizeOGLControl(AWidget);
|
|
end;
|
|
|
|
function LOpenGLCreateContext(AWinControl: TWinControl;
|
|
WSPrivate: TWSPrivateClass; SharedControl: TWinControl;
|
|
DoubleBuffered, RGBA: boolean;
|
|
const RedBits, GreenBits, BlueBits: Cardinal;
|
|
const MultiSampling, AlphaBits, DepthBits, StencilBits, AUXBuffers: Cardinal;
|
|
const AParams: TCreateParams): HWND;
|
|
var
|
|
disp: GDHandle;
|
|
aglPixFmt: TAGLPixelFormat;
|
|
aglContext: TAGLContext;
|
|
Control: TCarbonCustomControl;
|
|
AttrList: PInteger;
|
|
C: TCreateParams;
|
|
AGLInfo: PAGLControlInfo;
|
|
TempSpec: EventTypeSpec;
|
|
begin
|
|
Result:=0;
|
|
if AWinControl.Parent=nil then
|
|
RaiseGDBException('GLCarbonAGLContext.LOpenGLCreateContext no parent');
|
|
|
|
C.X := AWinControl.Left;
|
|
C.Y := AWinControl.Top;
|
|
C.Width := AWinControl.Width;
|
|
C.Height := AWinControl.Height;
|
|
// create a custom control
|
|
Control := TCarbonCustomControl.Create(AWinControl, C);
|
|
//debugln(['LOpenGLCreateContext ',dbgsName(AWinControl)]);
|
|
|
|
// create the AGL context
|
|
disp := GetMainDevice ();
|
|
AttrList:=CreateOpenGLContextAttrList(DoubleBuffered,RGBA,
|
|
RedBits,GreenBits,BlueBits,
|
|
MultiSampling,AlphaBits,DepthBits,StencilBits,AUXBuffers);
|
|
aglPixFmt := aglChoosePixelFormat (@disp, 1, AttrList);
|
|
System.FreeMem(AttrList);
|
|
aglContext := aglCreateContext (aglPixFmt, NIL);
|
|
aglDestroyPixelFormat(aglPixFmt);
|
|
|
|
aglSetDrawable(aglContext,
|
|
GetWindowPort(TCarbonWindow(GetParentForm(AWinControl).Handle).Window));
|
|
AGLControlInfo_FOURCC := MakeFourCC('ACI ');
|
|
|
|
AGLInfo:=CreateAGLControlInfo(Control.Widget, AGLContext, AWinControl);
|
|
if AGLInfo<>GetAGLControlInfo(Control.Widget) then
|
|
RaiseGDBException('GLCarbonAGLContext.LOpenGLCreateContext inconsistency');
|
|
|
|
ResizeOGLControl(Control);
|
|
TempSpec:=MakeEventSpec(kEventClassControl, kEventControlBoundsChanged);
|
|
InstallControlEventHandler(Control.Widget, RegisterEventHandler(@CarbonGLControl_Resize),
|
|
1, @TempSpec, Control, nil);
|
|
TempSpec:=MakeEventSpec(kEventClassControl, kEventControlOwningWindowChanged);
|
|
// The control might be embeded into a window after its creation.
|
|
// See example for this in bug report #17244
|
|
InstallControlEventHandler(Control.Widget, RegisterEventHandler(@CarbonGLControl_WindowChange),
|
|
1, @TempSpec, Control, nil);
|
|
|
|
Result:=HWnd(Control);
|
|
//debugln(['LOpenGLCreateContext ',dbgs(Result)]);
|
|
end;
|
|
|
|
procedure LOpenGLDestroyContextInfo(AWinControl: TWinControl);
|
|
var
|
|
Ref: ControlRef;
|
|
Info: PAGLControlInfo;
|
|
begin
|
|
if not AWinControl.HandleAllocated then Exit;
|
|
if csDesigning in AWinControl.ComponentState then Exit;
|
|
Ref := ControlRef(TCarbonControl(AWinControl.Handle).Widget);
|
|
Info := GetAGLControlInfo(Ref);
|
|
if Info=nil then exit;
|
|
aglDestroyContext(Info^.AGLContext);
|
|
Info^.AGLContext := nil;
|
|
FreeAGLControlInfo(Ref);
|
|
end;
|
|
|
|
function CreateOpenGLContextAttrList(DoubleBuffered: boolean; RGBA: boolean;
|
|
RedBits, GreenBits, BlueBits, MultiSampling, AlphaBits, DepthBits,
|
|
StencilBits, AUXBuffers: cardinal): PInteger;
|
|
var
|
|
p: integer;
|
|
|
|
procedure Add(i: integer);
|
|
begin
|
|
if Result<>nil then
|
|
Result[p]:=i;
|
|
inc(p);
|
|
end;
|
|
|
|
procedure CreateList;
|
|
begin
|
|
Add(AGL_WINDOW);
|
|
if DoubleBuffered then
|
|
Add(AGL_DOUBLEBUFFER);
|
|
if RGBA then
|
|
Add(AGL_RGBA);
|
|
Add(AGL_NO_RECOVERY);
|
|
Add(AGL_MAXIMUM_POLICY);
|
|
Add(AGL_SINGLE_RENDERER);
|
|
Add(AGL_RED_SIZE); Add(RedBits);
|
|
Add(AGL_GREEN_SIZE); Add(GreenBits);
|
|
Add(AGL_BLUE_SIZE); Add(BlueBits);
|
|
if AlphaBits>0 then
|
|
begin
|
|
Add(AGL_ALPHA_SIZE); Add(AlphaBits);
|
|
end;
|
|
if DepthBits>0 then
|
|
begin
|
|
Add(AGL_DEPTH_SIZE); Add(DepthBits);
|
|
end;
|
|
if StencilBits>0 then
|
|
begin
|
|
Add(AGL_STENCIL_SIZE); Add(StencilBits);
|
|
end;
|
|
if AUXBuffers>0 then
|
|
begin
|
|
Add(AGL_AUX_BUFFERS); Add(AUXBuffers);
|
|
end;
|
|
if MultiSampling > 1 then
|
|
begin
|
|
Add(AGL_SAMPLE_BUFFERS_ARB); Add(1);
|
|
Add(AGL_SAMPLES_ARB); Add(MultiSampling);
|
|
end;
|
|
|
|
Add(AGL_NONE);
|
|
end;
|
|
|
|
begin
|
|
Result:=nil;
|
|
p:=0;
|
|
CreateList;
|
|
GetMem(Result,SizeOf(integer)*p);
|
|
p:=0;
|
|
CreateList;
|
|
end;
|
|
|
|
function CreateAGLControlInfo(Control: ControlRef; AGLContext: TAGLContext;
|
|
WinControl: TWinControl): PAGLControlInfo;
|
|
begin
|
|
New(Result);
|
|
FillByte(Result^, SizeOf(Result^), 0);
|
|
Result^.Control:=Control;
|
|
Result^.WinControl:=WinControl;
|
|
Result^.AGLContext:=AGLContext;
|
|
|
|
SetControlProperty(Control, LAZARUS_FOURCC, AGLControlInfo_FOURCC,
|
|
SizeOf(Result), @Result);
|
|
end;
|
|
|
|
function GetAGLControlInfo(Control: ControlRef): PAGLControlInfo;
|
|
var
|
|
m: LongWord;
|
|
begin
|
|
GetControlProperty(Control, LAZARUS_FOURCC, AGLControlInfo_FOURCC,
|
|
SizeOf(Result), @m, @Result);
|
|
end;
|
|
|
|
procedure FreeAGLControlInfo(Control: ControlRef);
|
|
var
|
|
Info: PAGLControlInfo;
|
|
begin
|
|
Info:=GetAGLControlInfo(Control);
|
|
if Info=nil then exit;
|
|
RemoveControlProperty(Control, LAZARUS_FOURCC, AGLControlInfo_FOURCC);
|
|
System.FreeMem(Info);
|
|
end;
|
|
|
|
function GetAGLContext(Control: ControlRef): TAGLContext;
|
|
begin
|
|
Result:=GetAGLControlInfo(TCarbonCustomControl(Control).Widget)^.AGLContext;
|
|
end;
|
|
|
|
initialization
|
|
|
|
finalization
|
|
|
|
end.
|
|
|