lazarus/components/opengl/glcarbonaglcontext.pas
2017-06-15 21:01:28 +00:00

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.