source: trunk/Packages/bgrabitmap/bglvirtualscreen.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 12.2 KB
Line 
1unit BGLVirtualScreen;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
9 ExtCtrls, BGRABitmapTypes, BGRAOpenGL, OpenGLContext, BGRACanvasGL,
10 BGRASpriteGL;
11
12type
13 TCustomBGLVirtualScreen = class;
14 TBGLRedrawEvent = procedure (Sender: TObject; BGLContext: TBGLContext) of object;
15 TBGLLoadTexturesEvent = procedure (Sender: TObject; BGLContext: TBGLContext) of object;
16 TBGLElapseEvent = procedure (Sender: TObject; BGLContext: TBGLContext; ElapsedMs: integer) of object;
17 TBGLFramesPerSecondEvent = procedure (Sender: TObject; BGLContext: TBGLContext; FramesPerSecond: integer) of object;
18 TBGLUseContextCallback = procedure (Sender: TObject; BGLContext: TBGLContext; Data: Pointer) of object;
19
20 { TCustomBGLVirtualScreen }
21
22 TCustomBGLVirtualScreen = class(TCustomOpenGLControl)
23 private
24 { Private declarations }
25 FOnRedraw: TBGLRedrawEvent;
26 FOnLoadTextures: TBGLLoadTexturesEvent;
27 FOnUnloadTextures: TBGLLoadTexturesEvent;
28 FOnElapse: TBGLElapseEvent;
29 FOnFramesPerSecond: TBGLFramesPerSecondEvent;
30 FSmoothedElapse: boolean;
31 FTexturesLoaded: boolean;
32 FBevelInner, FBevelOuter: TPanelBevel;
33 FBevelWidth: TBevelWidth;
34 FBorderWidth: TBorderWidth;
35 FRedrawOnIdle: boolean;
36 FSprites: TBGLCustomSpriteEngine;
37 FElapseAccumulator, FElapseCount, FStoredFPS: integer;
38 FSmoothedElapseAccumulator: single;
39 FContextPrepared: boolean;
40 FOldSprites: TBGLCustomSpriteEngine;
41 FShaderList,FOldShaderList: TStringList;
42 function GetCanvas: TBGLCustomCanvas;
43 procedure SetBevelInner(const AValue: TPanelBevel);
44 procedure SetBevelOuter(const AValue: TPanelBevel);
45 procedure SetBevelWidth(const AValue: TBevelWidth);
46 procedure SetBorderWidth(const AValue: TBorderWidth);
47 procedure SetRedrawOnIdle(AValue: Boolean);
48 procedure SetSmoothedElapse(AValue: boolean);
49 protected
50 class var FToRedrawOnIdle: array of TCustomBGLVirtualScreen;
51 { Protected declarations }
52 procedure RedrawContent(ctx: TBGLContext); virtual;
53 procedure SetEnabled(Value: boolean); override;
54 class procedure OnAppIdle(Sender: TObject; var Done: Boolean);
55 procedure LoadTextures; virtual;
56 function PrepareBGLContext: TBGLContext;
57 procedure ReleaseBGLContext(ctx: TBGLContext);
58 public
59 { Public declarations }
60 procedure DoOnPaint; override;
61 procedure QueryLoadTextures; virtual;
62 procedure UnloadTextures; virtual;
63 procedure UseContext(ACallback: TBGLUseContextCallback; AData: Pointer = nil);
64 constructor Create(TheOwner: TComponent); override;
65 destructor Destroy; override;
66 public
67 property Canvas: TBGLCustomCanvas read GetCanvas;
68 property Sprites: TBGLCustomSpriteEngine read FSprites;
69 property OnLoadTextures: TBGLLoadTexturesEvent Read FOnLoadTextures Write FOnLoadTextures;
70 property OnUnloadTextures: TBGLLoadTexturesEvent Read FOnUnloadTextures Write FOnUnloadTextures;
71 property OnRedraw: TBGLRedrawEvent Read FOnRedraw Write FOnRedraw;
72 property OnElapse: TBGLElapseEvent Read FOnElapse Write FOnElapse;
73 property OnFramesPerSecond: TBGLFramesPerSecondEvent Read FOnFramesPerSecond Write FOnFramesPerSecond;
74 property RedrawOnIdle: Boolean read FRedrawOnIdle write SetRedrawOnIdle default False;
75 property BorderWidth: TBorderWidth Read FBorderWidth Write SetBorderWidth default 0;
76 property BevelInner: TPanelBevel Read FBevelInner Write SetBevelInner default bvNone;
77 property BevelOuter: TPanelBevel Read FBevelOuter Write SetBevelOuter default bvNone;
78 property BevelWidth: TBevelWidth Read FBevelWidth Write SetBevelWidth default 1;
79 property SmoothedElapse: boolean read FSmoothedElapse write SetSmoothedElapse default False;
80 end;
81
82 TBGLVirtualScreen = class(TCustomBGLVirtualScreen)
83 published
84 property OnRedraw;
85 property Align;
86 property Anchors;
87 property AutoSize;
88 property BorderSpacing;
89 property BevelInner;
90 property BevelOuter;
91 property BevelWidth;
92 property BidiMode;
93 property BorderWidth;
94 property BorderStyle;
95 property Caption;
96 property ChildSizing;
97 property ClientHeight;
98 property ClientWidth;
99 property Color;
100 property Constraints;
101 property DockSite;
102 property DragCursor;
103 property DragKind;
104 property DragMode;
105 property Enabled;
106 property Font;
107 property ParentBidiMode;
108 property ParentColor;
109 property ParentFont;
110 property ParentShowHint;
111 property PopupMenu;
112 property RedrawOnIdle;
113 property ShowHint;
114 property TabOrder;
115 property TabStop;
116 property UseDockManager default True;
117 property Visible;
118 property OnClick;
119 property OnContextPopup;
120 property OnDockDrop;
121 property OnDockOver;
122 property OnDblClick;
123 property OnDragDrop;
124 property OnDragOver;
125 property OnElapse;
126 property OnEndDock;
127 property OnEndDrag;
128 property OnEnter;
129 property OnExit;
130 property OnFramesPerSecond;
131 property OnGetSiteInfo;
132 property OnGetDockCaption;
133 property OnLoadTextures;
134 property OnUnloadTextures;
135 property OnMouseDown;
136 property OnMouseEnter;
137 property OnMouseLeave;
138 property OnMouseMove;
139 property OnMouseUp;
140 property OnMouseWheel;
141 property OnMouseWheelDown;
142 property OnMouseWheelUp;
143 property OnResize;
144 property OnStartDock;
145 property OnStartDrag;
146 property OnUnDock;
147 property SmoothedElapse;
148 end;
149
150procedure Register;
151
152implementation
153
154uses Types;
155
156procedure Register;
157begin
158 {$I bglvirtualscreen_icon.lrs}
159 RegisterComponents('OpenGL', [TBGLVirtualScreen]);
160end;
161
162{ TCustomBGLVirtualScreen }
163
164procedure TCustomBGLVirtualScreen.SetBevelInner(const AValue: TPanelBevel);
165begin
166 if FBevelInner = AValue then
167 exit;
168 FBevelInner := AValue;
169 Invalidate;
170end;
171
172function TCustomBGLVirtualScreen.GetCanvas: TBGLCustomCanvas;
173begin
174 result := BGLCanvas;
175end;
176
177procedure TCustomBGLVirtualScreen.SetBevelOuter(const AValue: TPanelBevel);
178begin
179 if FBevelOuter = AValue then
180 exit;
181 FBevelOuter := AValue;
182 Invalidate;
183end;
184
185procedure TCustomBGLVirtualScreen.SetBevelWidth(const AValue: TBevelWidth);
186begin
187 if FBevelWidth = AValue then
188 exit;
189 FBevelWidth := AValue;
190 Invalidate;
191end;
192
193procedure TCustomBGLVirtualScreen.SetBorderWidth(const AValue: TBorderWidth);
194begin
195 if FBorderWidth = AValue then
196 exit;
197 FBorderWidth := AValue;
198 Invalidate;
199end;
200
201procedure TCustomBGLVirtualScreen.SetRedrawOnIdle(AValue: Boolean);
202var
203 i: Integer;
204 j: Integer;
205begin
206 if FRedrawOnIdle=AValue then Exit;
207 FRedrawOnIdle:=AValue;
208
209 if FRedrawOnIdle then
210 begin
211 if length(FToRedrawOnIdle)= 0 then
212 Application.AddOnIdleHandler(@OnAppIdle);
213 setlength(FToRedrawOnIdle, length(FToRedrawOnIdle)+1);
214 FToRedrawOnIdle[high(FToRedrawOnIdle)] := self;
215 end
216 else
217 if length(FToRedrawOnIdle)> 0 then
218 begin
219 for i := 0 to high(FToRedrawOnIdle) do
220 begin
221 if FToRedrawOnIdle[i]=self then
222 begin
223 for j := i to high(FToRedrawOnIdle)-1 do
224 FToRedrawOnIdle[j] := FToRedrawOnIdle[j+1];
225 setlength(FToRedrawOnIdle, length(FToRedrawOnIdle)-1);
226 break;
227 end;
228 end;
229 if length(FToRedrawOnIdle) = 0 then
230 Application.RemoveOnIdleHandler(@OnAppIdle);
231 end;
232end;
233
234procedure TCustomBGLVirtualScreen.SetSmoothedElapse(AValue: boolean);
235begin
236 if FSmoothedElapse=AValue then Exit;
237 FSmoothedElapse:=AValue;
238end;
239
240procedure TCustomBGLVirtualScreen.DoOnPaint;
241var
242 ctx: TBGLContext;
243 knownFPS: Integer;
244begin
245 if not FTexturesLoaded then LoadTextures;
246
247 ctx := PrepareBGLContext;
248 if Color = clNone then
249 BGLViewPort(ClientWidth,ClientHeight)
250 else
251 if Color = clDefault then
252 BGLViewPort(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clWindow)))
253 else
254 BGLViewPort(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(Color)));
255
256 RedrawContent(ctx);
257 inherited DoOnPaint;
258 SwapBuffers;
259
260 FElapseAccumulator += FrameDiffTimeInMSecs;
261 Inc(FElapseCount);
262 if FElapseAccumulator >= 2000 then
263 begin
264 FStoredFPS := 1000*FElapseCount div FElapseAccumulator;
265 if Assigned(FOnFramesPerSecond) then
266 FOnFramesPerSecond(self, ctx, FStoredFPS);
267 FElapseAccumulator := 0;
268 FElapseCount := 0;
269 end;
270
271 If Assigned(FOnElapse) then
272 begin
273 if SmoothedElapse then
274 begin
275 If FStoredFPS <> 0 then
276 knownFPS:= FStoredFPS
277 else
278 if FElapseAccumulator >= 500 then
279 knownFPS := 1000*FElapseCount div FElapseAccumulator
280 else
281 knownFPS := 0;
282
283 if knownFPS > 0 then
284 begin
285 FSmoothedElapseAccumulator += 1000/knownFPS;
286 end else
287 FSmoothedElapseAccumulator += FrameDiffTimeInMSecs;
288
289 FOnElapse(self, ctx, Trunc(FSmoothedElapseAccumulator));
290 FSmoothedElapseAccumulator -= Trunc(FSmoothedElapseAccumulator);
291 end else
292 FOnElapse(self, ctx, FrameDiffTimeInMSecs);
293 end;
294
295 ReleaseBGLContext(ctx);
296end;
297
298procedure TCustomBGLVirtualScreen.QueryLoadTextures;
299begin
300 FTexturesLoaded := false;
301end;
302
303procedure TCustomBGLVirtualScreen.LoadTextures;
304var ctx: TBGLContext;
305begin
306 if MakeCurrent then
307 begin
308 if Assigned(FOnLoadTextures) then
309 begin
310 ctx := PrepareBGLContext;
311 FOnLoadTextures(self, ctx);
312 ReleaseBGLContext(ctx);
313 end;
314 FTexturesLoaded:= true;
315 end;
316end;
317
318function TCustomBGLVirtualScreen.PrepareBGLContext: TBGLContext;
319begin
320 if FContextPrepared then
321 raise exception.Create('Context already prepared');
322 FOldSprites := BGRASpriteGL.BGLSpriteEngine;
323 BGRASpriteGL.BGLSpriteEngine := FSprites;
324 FOldShaderList := BGLCanvas.Lighting.ShaderList;
325 BGLCanvas.Lighting.ShaderList := FShaderList;
326 result.Canvas := BGLCanvas;
327 result.Sprites := FSprites;
328 FContextPrepared := true;
329end;
330
331procedure TCustomBGLVirtualScreen.ReleaseBGLContext(ctx: TBGLContext);
332begin
333 if not FContextPrepared then
334 raise exception.Create('Context not prepared');
335 ctx.Canvas.Lighting.ShaderList := FOldShaderList;
336 BGRASpriteGL.BGLSpriteEngine := FOldSprites;
337 FContextPrepared := false;
338end;
339
340procedure TCustomBGLVirtualScreen.UnloadTextures;
341var ctx: TBGLContext;
342begin
343 if MakeCurrent then
344 begin
345 ctx := PrepareBGLContext;
346 if Assigned(FOnUnloadTextures) then FOnUnloadTextures(self, ctx);
347 FSprites.Clear;
348 ctx.Canvas.Lighting.FreeShaders;
349 ReleaseBGLContext(ctx);
350 FTexturesLoaded := false;
351 end;
352end;
353
354procedure TCustomBGLVirtualScreen.UseContext(ACallback: TBGLUseContextCallback; AData: Pointer);
355var
356 ctx: TBGLContext;
357begin
358 if not MakeCurrent then
359 raise exception.Create('Unable to switch to the OpenGL context');
360 ctx := PrepareBGLContext;
361 try
362 ACallback(self, ctx, AData);
363 finally
364 ReleaseBGLContext(ctx);
365 end;
366end;
367
368procedure TCustomBGLVirtualScreen.RedrawContent(ctx: TBGLContext);
369var
370 ARect: TRect;
371 w: integer;
372begin
373 ARect := rect(0,0,ctx.Canvas.Width,ctx.Canvas.Height);
374 w := BevelWidth;
375 if w = 0 then w := 1;
376
377 // if BevelOuter is set then draw a frame with BevelWidth
378 if (BevelOuter <> bvNone) and (w > 0) then
379 ctx.Canvas.Frame3d(ARect, w, BevelOuter); // Note: Frame3D inflates ARect
380
381 InflateRect(ARect, -BorderWidth, -BorderWidth);
382
383 // if BevelInner is set then skip the BorderWidth and draw a frame with BevelWidth
384 if (BevelInner <> bvNone) and (w > 0) then
385 ctx.Canvas.Frame3d(ARect, w, BevelInner); // Note: Frame3D inflates ARect
386
387 if Assigned(FOnRedraw) then
388 FOnRedraw(self, ctx);
389end;
390
391procedure TCustomBGLVirtualScreen.SetEnabled(Value: boolean);
392begin
393 if Value <> Enabled then Invalidate;
394 inherited SetEnabled(Value);
395end;
396
397class procedure TCustomBGLVirtualScreen.OnAppIdle(Sender: TObject; var Done: Boolean);
398var
399 i: Integer;
400begin
401 if length(FToRedrawOnIdle) > 0 then
402 begin
403 for i := 0 to high(FToRedrawOnIdle) do
404 if not (csDesigning in FToRedrawOnIdle[i].ComponentState) then
405 FToRedrawOnIdle[i].Invalidate;
406 Done:=false;
407 end;
408end;
409
410constructor TCustomBGLVirtualScreen.Create(TheOwner: TComponent);
411begin
412 inherited Create(TheOwner);
413 FTexturesLoaded:= False;
414 AutoResizeViewport := true;
415 FSprites := TBGLDefaultSpriteEngine.Create;
416 FShaderList:= TStringList.Create;
417 FStoredFPS := 0;
418 FElapseAccumulator := 0;
419 FElapseCount := 0;
420 FSmoothedElapseAccumulator := 0;
421end;
422
423destructor TCustomBGLVirtualScreen.Destroy;
424var
425 i: Integer;
426begin
427 for i := 0 to FShaderList.Count-1 do
428 FShaderList.Objects[i].Free;
429 FShaderList.Free;
430 RedrawOnIdle := false;
431 FSprites.Free;
432 inherited Destroy;
433end;
434
435end.
436
Note: See TracBrowser for help on using the repository browser.