1 | unit BGLVirtualScreen;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
|
---|
9 | ExtCtrls, BGRABitmapTypes, BGRAOpenGL, OpenGLContext, BGRACanvasGL,
|
---|
10 | BGRASpriteGL;
|
---|
11 |
|
---|
12 | type
|
---|
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 |
|
---|
150 | procedure Register;
|
---|
151 |
|
---|
152 | implementation
|
---|
153 |
|
---|
154 | uses Types;
|
---|
155 |
|
---|
156 | procedure Register;
|
---|
157 | begin
|
---|
158 | {$I bglvirtualscreen_icon.lrs}
|
---|
159 | RegisterComponents('OpenGL', [TBGLVirtualScreen]);
|
---|
160 | end;
|
---|
161 |
|
---|
162 | { TCustomBGLVirtualScreen }
|
---|
163 |
|
---|
164 | procedure TCustomBGLVirtualScreen.SetBevelInner(const AValue: TPanelBevel);
|
---|
165 | begin
|
---|
166 | if FBevelInner = AValue then
|
---|
167 | exit;
|
---|
168 | FBevelInner := AValue;
|
---|
169 | Invalidate;
|
---|
170 | end;
|
---|
171 |
|
---|
172 | function TCustomBGLVirtualScreen.GetCanvas: TBGLCustomCanvas;
|
---|
173 | begin
|
---|
174 | result := BGLCanvas;
|
---|
175 | end;
|
---|
176 |
|
---|
177 | procedure TCustomBGLVirtualScreen.SetBevelOuter(const AValue: TPanelBevel);
|
---|
178 | begin
|
---|
179 | if FBevelOuter = AValue then
|
---|
180 | exit;
|
---|
181 | FBevelOuter := AValue;
|
---|
182 | Invalidate;
|
---|
183 | end;
|
---|
184 |
|
---|
185 | procedure TCustomBGLVirtualScreen.SetBevelWidth(const AValue: TBevelWidth);
|
---|
186 | begin
|
---|
187 | if FBevelWidth = AValue then
|
---|
188 | exit;
|
---|
189 | FBevelWidth := AValue;
|
---|
190 | Invalidate;
|
---|
191 | end;
|
---|
192 |
|
---|
193 | procedure TCustomBGLVirtualScreen.SetBorderWidth(const AValue: TBorderWidth);
|
---|
194 | begin
|
---|
195 | if FBorderWidth = AValue then
|
---|
196 | exit;
|
---|
197 | FBorderWidth := AValue;
|
---|
198 | Invalidate;
|
---|
199 | end;
|
---|
200 |
|
---|
201 | procedure TCustomBGLVirtualScreen.SetRedrawOnIdle(AValue: Boolean);
|
---|
202 | var
|
---|
203 | i: Integer;
|
---|
204 | j: Integer;
|
---|
205 | begin
|
---|
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;
|
---|
232 | end;
|
---|
233 |
|
---|
234 | procedure TCustomBGLVirtualScreen.SetSmoothedElapse(AValue: boolean);
|
---|
235 | begin
|
---|
236 | if FSmoothedElapse=AValue then Exit;
|
---|
237 | FSmoothedElapse:=AValue;
|
---|
238 | end;
|
---|
239 |
|
---|
240 | procedure TCustomBGLVirtualScreen.DoOnPaint;
|
---|
241 | var
|
---|
242 | ctx: TBGLContext;
|
---|
243 | knownFPS: Integer;
|
---|
244 | begin
|
---|
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);
|
---|
296 | end;
|
---|
297 |
|
---|
298 | procedure TCustomBGLVirtualScreen.QueryLoadTextures;
|
---|
299 | begin
|
---|
300 | FTexturesLoaded := false;
|
---|
301 | end;
|
---|
302 |
|
---|
303 | procedure TCustomBGLVirtualScreen.LoadTextures;
|
---|
304 | var ctx: TBGLContext;
|
---|
305 | begin
|
---|
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;
|
---|
316 | end;
|
---|
317 |
|
---|
318 | function TCustomBGLVirtualScreen.PrepareBGLContext: TBGLContext;
|
---|
319 | begin
|
---|
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;
|
---|
329 | end;
|
---|
330 |
|
---|
331 | procedure TCustomBGLVirtualScreen.ReleaseBGLContext(ctx: TBGLContext);
|
---|
332 | begin
|
---|
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;
|
---|
338 | end;
|
---|
339 |
|
---|
340 | procedure TCustomBGLVirtualScreen.UnloadTextures;
|
---|
341 | var ctx: TBGLContext;
|
---|
342 | begin
|
---|
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;
|
---|
352 | end;
|
---|
353 |
|
---|
354 | procedure TCustomBGLVirtualScreen.UseContext(ACallback: TBGLUseContextCallback; AData: Pointer);
|
---|
355 | var
|
---|
356 | ctx: TBGLContext;
|
---|
357 | begin
|
---|
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;
|
---|
366 | end;
|
---|
367 |
|
---|
368 | procedure TCustomBGLVirtualScreen.RedrawContent(ctx: TBGLContext);
|
---|
369 | var
|
---|
370 | ARect: TRect;
|
---|
371 | w: integer;
|
---|
372 | begin
|
---|
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);
|
---|
389 | end;
|
---|
390 |
|
---|
391 | procedure TCustomBGLVirtualScreen.SetEnabled(Value: boolean);
|
---|
392 | begin
|
---|
393 | if Value <> Enabled then Invalidate;
|
---|
394 | inherited SetEnabled(Value);
|
---|
395 | end;
|
---|
396 |
|
---|
397 | class procedure TCustomBGLVirtualScreen.OnAppIdle(Sender: TObject; var Done: Boolean);
|
---|
398 | var
|
---|
399 | i: Integer;
|
---|
400 | begin
|
---|
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;
|
---|
408 | end;
|
---|
409 |
|
---|
410 | constructor TCustomBGLVirtualScreen.Create(TheOwner: TComponent);
|
---|
411 | begin
|
---|
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;
|
---|
421 | end;
|
---|
422 |
|
---|
423 | destructor TCustomBGLVirtualScreen.Destroy;
|
---|
424 | var
|
---|
425 | i: Integer;
|
---|
426 | begin
|
---|
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;
|
---|
433 | end;
|
---|
434 |
|
---|
435 | end.
|
---|
436 |
|
---|