GLS.LensFlare.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.LensFlare;
  5. (*
  6. Lens flare object.
  7. Registered components: [TGLLensFlare]
  8. *)
  9. interface
  10. {$I Stage.Defines.inc}
  11. uses
  12. Winapi.OpenGL,
  13. Winapi.OpenGLext,
  14. System.Classes,
  15. System.SysUtils,
  16. System.Math,
  17. Stage.OpenGLTokens,
  18. GLS.PersistentClasses,
  19. Stage.VectorGeometry,
  20. GLS.BaseClasses,
  21. Stage.VectorTypes,
  22. GLS.Scene,
  23. Stage.PipelineTransform,
  24. GLS.Objects,
  25. GLS.Context,
  26. GLS.Color,
  27. GLS.RenderContextInfo,
  28. GLS.State,
  29. Stage.Utils,
  30. Stage.TextureFormat;
  31. type
  32. TGLFlareElement = (feGlow, feRing, feStreaks, feRays, feSecondaries);
  33. TGLFlareElements = set of TGLFlareElement;
  34. (* The actual gradients between two colors are, of course, calculated by OpenGL.
  35. The start and end colors of a gradient are stored to represent the color of
  36. lens flare elements. *)
  37. TGLFlareGradient = class(TGLUpdateAbleObject)
  38. private
  39. FFromColor: TGLColor;
  40. FToColor: TGLColor;
  41. protected
  42. procedure SetFromColor(const val: TGLColor);
  43. procedure SetToColor(const val: TGLColor);
  44. public
  45. constructor Create(AOwner: TPersistent); override;
  46. constructor CreateInitialized(AOwner: TPersistent;
  47. const fromColor, toColor: TGLColorVector);
  48. destructor Destroy; override;
  49. procedure Assign(Source: TPersistent); override;
  50. published
  51. property FromColor: TGLColor read FFromColor write SetFromColor;
  52. property ToColor: TGLColor read FToColor write SetToColor;
  53. end;
  54. const
  55. cDefaultFlareElements = [feGlow, feRing, feStreaks, feRays, feSecondaries];
  56. type
  57. TGLLensFlare = class(TGLBaseSceneObject)
  58. private
  59. FSize: Integer;
  60. FDeltaTime: Single;
  61. FCurrSize: Single;
  62. FSeed: Integer;
  63. FSqueeze: Single;
  64. FNumStreaks: Integer;
  65. FStreakWidth, FStreakAngle: Single;
  66. FNumSecs: Integer;
  67. FResolution: Integer;
  68. FAutoZTest: Boolean;
  69. FElements: TGLFlareElements;
  70. FSin20Res, FCos20Res: array of Single;
  71. FSinRes, FCosRes: array of Single;
  72. FTexRays: TGLTextureHandle;
  73. FFlareIsNotOccluded: Boolean;
  74. FOcclusionQuery: TGLOcclusionQueryHandle;
  75. FGlowGradient: TGLFlareGradient;
  76. FRingGradient: TGLFlareGradient;
  77. FStreaksGradient: TGLFlareGradient;
  78. FRaysGradient: TGLFlareGradient;
  79. FSecondariesGradient: TGLFlareGradient;
  80. FDynamic: Boolean;
  81. FPreRenderPoint: TGLRenderPoint;
  82. protected
  83. procedure SetGlowGradient(const val: TGLFlareGradient);
  84. procedure SetRingGradient(const val: TGLFlareGradient);
  85. procedure SetStreaksGradient(const val: TGLFlareGradient);
  86. procedure SetRaysGradient(const val: TGLFlareGradient);
  87. procedure SetSecondariesGradient(const val: TGLFlareGradient);
  88. procedure SetSize(aValue: Integer);
  89. procedure SetSeed(aValue: Integer);
  90. procedure SetSqueeze(aValue: Single);
  91. function StoreSqueeze: Boolean;
  92. procedure SetNumStreaks(aValue: Integer);
  93. procedure SetStreakWidth(aValue: Single);
  94. function StoreStreakWidth: Boolean;
  95. procedure SetStreakAngle(aValue: Single);
  96. procedure SetNumSecs(aValue: Integer);
  97. procedure SetResolution(aValue: Integer);
  98. procedure SetAutoZTest(aValue: Boolean);
  99. procedure SetElements(aValue: TGLFlareElements);
  100. procedure SetDynamic(aValue: Boolean);
  101. procedure SetPreRenderPoint(const val: TGLRenderPoint);
  102. procedure PreRenderEvent(Sender: TObject; var rci: TGLRenderContextInfo);
  103. procedure PreRenderPointFreed(Sender: TObject);
  104. (* These are quite unusual in that they don't use an RCI, since
  105. PreRender is done before proper rendering starts, but we do know
  106. which RC is being used, so we can use this state cache *)
  107. procedure SetupRenderingOptions(StateCache: TGLStateCache);
  108. procedure RenderRays(StateCache: TGLStateCache; const size: Single);
  109. procedure RenderStreaks(StateCache: TGLStateCache);
  110. procedure RenderRing;
  111. procedure RenderSecondaries(const posVector: TAffineVector);
  112. public
  113. constructor Create(AOwner: TComponent); override;
  114. destructor Destroy; override;
  115. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  116. procedure BuildList(var rci: TGLRenderContextInfo); override;
  117. procedure DoProgress(const progressTime: TGLProgressTimes); override;
  118. (* Prepares pre-rendered texture to speed up actual rendering.
  119. Will use the currently active context as scratch space, and will
  120. automatically do nothing if things have already been prepared,
  121. thus you can invoke it systematically in a Viewer.BeforeRender
  122. event f.i. *)
  123. procedure PreRender(activeBuffer: TGLSceneBuffer);
  124. (* Access to the Flare's current size.
  125. Flares decay or grow back over several frames, depending on their
  126. occlusion status, and this property allows to track or manually
  127. alter this instantaneous size. *)
  128. property FlareInstantaneousSize: Single read FCurrSize write FCurrSize;
  129. published
  130. property GlowGradient: TGLFlareGradient read FGlowGradient write SetGlowGradient;
  131. property RingGradient: TGLFlareGradient read FRingGradient;
  132. property StreaksGradient: TGLFlareGradient read FStreaksGradient;
  133. property RaysGradient: TGLFlareGradient read FRaysGradient;
  134. property SecondariesGradient: TGLFlareGradient read FSecondariesGradient;
  135. // MaxRadius of the flare.
  136. property Size: Integer read FSize write SetSize default 50;
  137. // Random seed
  138. property Seed: Integer read FSeed write SetSeed;
  139. // To create elliptic flares.
  140. property Squeeze: Single read FSqueeze write SetSqueeze stored StoreSqueeze;
  141. // Number of streaks.
  142. property NumStreaks: Integer read FNumStreaks write SetNumStreaks default 4;
  143. // Width of the streaks.
  144. property StreakWidth: Single read FStreakWidth write SetStreakWidth stored
  145. StoreStreakWidth;
  146. // Angle of the streaks (in degrees)
  147. property StreakAngle: Single read FStreakAngle write SetStreakAngle;
  148. // Number of secondary flares.
  149. property NumSecs: Integer read FNumSecs write SetNumSecs default 8;
  150. // Number of segments used when rendering circles.
  151. property Resolution: Integer read FResolution write SetResolution default 64;
  152. (* Automatically computes FlareIsNotOccluded depending on ZBuffer test.
  153. Not that the automated test may use test result from the previous
  154. frame into the next (to avoid a rendering stall). *)
  155. property AutoZTest: Boolean read FAutoZTest write SetAutoZTest default True;
  156. (* Is the LensFlare not occluded?.
  157. If false the flare will fade away, if true, it will fade in and stay.
  158. This value is automatically updated if AutoZTest is set. *)
  159. property FlareIsNotOccluded: Boolean read FFlareIsNotOccluded write
  160. FFlareIsNotOccluded;
  161. // Which elements should be rendered?
  162. property Elements: TGLFlareElements read FElements write SetElements default
  163. cDefaultFlareElements;
  164. (* Is the flare size adjusted dynamically?
  165. If true, the flare size will be grown and reduced over a few frames
  166. when it switches between occluded and non-occluded states. This
  167. requires animation to be active, but results in a smoother appearance.
  168. When false, flare will either be at full size or hidden.
  169. The flare is always considered non-dynamic at design-time. *)
  170. property Dynamic: Boolean read FDynamic write FDynamic default True;
  171. (* PreRender point for pre-rendered flare textures.
  172. See PreRender method for more details. *)
  173. property PreRenderPoint: TGLRenderPoint read FPreRenderPoint write
  174. SetPreRenderPoint;
  175. property ObjectsSorting;
  176. property Position;
  177. property Visible;
  178. property OnProgress;
  179. property Behaviours;
  180. property Effects;
  181. end;
  182. // ------------------------------------------------------------------
  183. implementation
  184. // ------------------------------------------------------------------
  185. // ------------------
  186. // ------------------ TGLFlareGradient ------------------
  187. // ------------------
  188. constructor TGLFlareGradient.Create(AOwner: TPersistent);
  189. begin
  190. inherited;
  191. FFromColor := TGLColor.Create(Self);
  192. FToColor := TGLColor.Create(Self);
  193. end;
  194. constructor TGLFlareGradient.CreateInitialized(AOwner: TPersistent;
  195. const fromColor, toColor: TGLColorVector);
  196. begin
  197. Create(AOwner);
  198. FFromColor.Initialize(fromColor);
  199. FToColor.Initialize(toColor);
  200. end;
  201. destructor TGLFlareGradient.Destroy;
  202. begin
  203. FToColor.Free;
  204. FFromColor.Free;
  205. inherited;
  206. end;
  207. procedure TGLFlareGradient.Assign(Source: TPersistent);
  208. begin
  209. if Source is TGLFlareGradient then
  210. begin
  211. FromColor := TGLFlareGradient(Source).FromColor;
  212. ToColor := TGLFlareGradient(Source).ToColor;
  213. end;
  214. inherited;
  215. end;
  216. procedure TGLFlareGradient.SetFromColor(const val: TGLColor);
  217. begin
  218. FFromColor.Assign(val);
  219. end;
  220. procedure TGLFlareGradient.SetToColor(const val: TGLColor);
  221. begin
  222. FToColor.Assign(val);
  223. end;
  224. // ------------------
  225. // ------------------ TGLLensFlare ------------------
  226. // ------------------
  227. constructor TGLLensFlare.Create(AOwner: TComponent);
  228. begin
  229. inherited;
  230. // Set default parameters:
  231. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  232. FSize := 50;
  233. FSeed := 1465;
  234. FSqueeze := 1;
  235. FNumStreaks := 4;
  236. FStreakWidth := 2;
  237. FNumSecs := 8;
  238. FAutoZTest := True;
  239. FlareIsNotOccluded := True;
  240. FDynamic := True;
  241. SetResolution(64);
  242. // Render all elements by default.
  243. FElements := [feGlow, feRing, feStreaks, feRays, feSecondaries];
  244. // Setup default gradients:
  245. FGlowGradient := TGLFlareGradient.CreateInitialized(Self,
  246. VectorMake(1, 1, 0.8, 0.3), VectorMake(1, 0.2, 0, 0));
  247. FRingGradient := TGLFlareGradient.CreateInitialized(Self,
  248. VectorMake(0.5, 0.2, 0, 0.1), VectorMake(0.5, 0.4, 0, 0.1));
  249. FStreaksGradient := TGLFlareGradient.CreateInitialized(Self,
  250. VectorMake(1, 1, 1, 0.2), VectorMake(0.2, 0, 1, 0));
  251. FRaysGradient := TGLFlareGradient.CreateInitialized(Self,
  252. VectorMake(1, 0.8, 0.5, 0.05), VectorMake(0.5, 0.2, 0, 0));
  253. FSecondariesGradient := TGLFlareGradient.CreateInitialized(Self,
  254. VectorMake(0, 0.2, 1, 0), VectorMake(0, 0.8, 0.2, 0.15));
  255. FTexRays := TGLTextureHandle.Create;
  256. end;
  257. destructor TGLLensFlare.Destroy;
  258. begin
  259. PreRenderPoint := nil;
  260. FGlowGradient.Free;
  261. FRingGradient.Free;
  262. FStreaksGradient.Free;
  263. FRaysGradient.Free;
  264. FSecondariesGradient.Free;
  265. FOcclusionQuery.Free;
  266. FTexRays.Free;
  267. inherited;
  268. end;
  269. procedure TGLLensFlare.Notification(AComponent: TComponent; Operation:
  270. TOperation);
  271. begin
  272. if (Operation = opRemove) and (AComponent = FPreRenderPoint) then
  273. PreRenderPoint := nil;
  274. inherited;
  275. end;
  276. procedure TGLLensFlare.SetupRenderingOptions(StateCache: TGLStateCache);
  277. begin
  278. StateCache.Disable(stLighting);
  279. StateCache.Disable(stDepthTest);
  280. StateCache.Disable(stFog);
  281. StateCache.Disable(stColorMaterial);
  282. StateCache.Disable(stCullFace);
  283. StateCache.DepthWriteMask := False;
  284. StateCache.Enable(stBlend);
  285. StateCache.SetBlendFunc(bfSrcAlpha, bfOne);
  286. StateCache.Disable(stAlphaTest);
  287. StateCache.PolygonMode := pmFill;
  288. end;
  289. procedure TGLLensFlare.RenderRays(StateCache: TGLStateCache; const size:
  290. Single);
  291. var
  292. i: Integer;
  293. rnd: Single;
  294. begin
  295. {$IFDEF USE_OPENGL_DEBUG}
  296. if gl.GREMEDY_string_marker then
  297. gl.StringMarkerGREMEDY(14, 'LensFlare.Rays');
  298. {$ENDIF}
  299. StateCache.LineWidth := 1;
  300. StateCache.Disable(stLineSmooth);
  301. StateCache.Disable(stLineStipple);
  302. gl.Begin_(GL_LINES);
  303. for i := 0 to Resolution * 20 - 1 do
  304. begin
  305. if (i and 1) <> 0 then
  306. rnd := 1.5 * Random * size
  307. else
  308. rnd := Random * size;
  309. gl.Color4fv(RaysGradient.FromColor.AsAddress);
  310. gl.Vertex2f(0, 0);
  311. gl.Color4fv(RaysGradient.ToColor.AsAddress);
  312. gl.Vertex2f(rnd * FCos20Res[i], rnd * FSin20Res[i] * Squeeze);
  313. end;
  314. gl.End_;
  315. end;
  316. procedure TGLLensFlare.RenderStreaks(StateCache: TGLStateCache);
  317. var
  318. i: Integer;
  319. a, f, s, c: Single;
  320. begin
  321. {$IFDEF USE_OPENGL_DEBUG}
  322. if gl.GREMEDY_string_marker then
  323. gl.StringMarkerGREMEDY(17, 'LensFlare.Streaks');
  324. {$ENDIF}
  325. StateCache.Enable(stLineSmooth);
  326. StateCache.LineWidth := StreakWidth;
  327. a := c2PI / NumStreaks;
  328. f := 1.5 * FCurrSize;
  329. gl.Begin_(GL_LINES);
  330. for i := 0 to NumStreaks - 1 do
  331. begin
  332. SinCosine(StreakAngle * cPIdiv180 + a * i, f, s, c);
  333. gl.Color4fv(StreaksGradient.FromColor.AsAddress);
  334. gl.Vertex3fv(@NullVector);
  335. gl.Color4fv(StreaksGradient.ToColor.AsAddress);
  336. gl.Vertex2f(c, Squeeze * s);
  337. end;
  338. gl.End_;
  339. StateCache.Disable(stLineSmooth);
  340. end;
  341. procedure TGLLensFlare.RenderRing;
  342. var
  343. i: Integer;
  344. rW, s0, c0, s, c: Single;
  345. begin
  346. {$IFDEF USE_OPENGL_DEBUG}
  347. if GL.GREMEDY_string_marker then
  348. GL.StringMarkerGREMEDY(14, 'LensFlare.Ring');
  349. {$ENDIF}
  350. rW := FCurrSize * (1 / 15); // Ring width
  351. gl.Begin_(GL_QUADS);
  352. s0 := 0;
  353. c0 := 0.6;
  354. for i := 0 to Resolution - 1 do
  355. begin
  356. s := s0;
  357. c := c0;
  358. s0 := FSinRes[i] * 0.6 * Squeeze;
  359. c0 := FCosRes[i] * 0.6;
  360. gl.Color4fv(GlowGradient.ToColor.AsAddress);
  361. gl.Vertex2f((FCurrSize - rW) * c, (FCurrSize - rW) * s);
  362. gl.Color4fv(RingGradient.FromColor.AsAddress);
  363. gl.Vertex2f(FCurrSize * c, Squeeze * FCurrSize * s);
  364. gl.Vertex2f(FCurrSize * c0, FCurrSize * s0);
  365. gl.Color4fv(GlowGradient.ToColor.AsAddress);
  366. gl.Vertex2f((FCurrSize - rW) * c0, (FCurrSize - rW) * s0);
  367. gl.Color4fv(RingGradient.FromColor.AsAddress);
  368. gl.Vertex2f(FCurrSize * c, FCurrSize * s);
  369. gl.Vertex2f(FCurrSize * c0, FCurrSize * s0);
  370. gl.Color4fv(GlowGradient.ToColor.AsAddress);
  371. gl.Vertex2f((FCurrSize + rW) * c0, (FCurrSize + rW) * s0);
  372. gl.Vertex2f((FCurrSize + rW) * c, (FCurrSize + rW) * s);
  373. end;
  374. gl.End_;
  375. end;
  376. procedure TGLLensFlare.RenderSecondaries(const posVector: TAffineVector);
  377. var
  378. i, j: Integer;
  379. rnd: Single;
  380. v: TAffineVector;
  381. grad: TGLFlareGradient;
  382. begin
  383. {$IFDEF USE_OPENGL_DEBUG}
  384. if GL.GREMEDY_string_marker then
  385. GL.StringMarkerGREMEDY(21, 'LensFlare.Secondaries');
  386. {$ENDIF}
  387. // Other secondaries (plain gradiented circles, like the glow):
  388. for j := 1 to NumSecs do
  389. begin
  390. rnd := 2 * Random - 1;
  391. // If rnd < 0 then the secondary glow will end up on the other side
  392. // of the origin. In this case, we can push it really far away from
  393. // the flare. If the secondary is on the flare's side, we pull it
  394. // slightly towards the origin to avoid it winding up in the middle
  395. // of the flare.
  396. if rnd < 0 then
  397. v := VectorScale(posVector, rnd)
  398. else
  399. v := VectorScale(posVector, 0.8 * rnd);
  400. if j mod 3 = 0 then
  401. grad := GlowGradient
  402. else
  403. grad := SecondariesGradient;
  404. rnd := (Random + 0.1) * FCurrSize * 0.25;
  405. gl.Begin_(GL_TRIANGLE_FAN);
  406. gl.Color4fv(grad.FromColor.AsAddress);
  407. gl.Vertex2f(v.X, v.Y);
  408. gl.Color4fv(grad.ToColor.AsAddress);
  409. for i := 0 to Resolution - 1 do
  410. gl.Vertex2f(FCosRes[i] * rnd + v.X, FSinRes[i] * rnd + v.Y);
  411. gl.End_;
  412. end;
  413. end;
  414. procedure TGLLensFlare.BuildList(var rci: TGLRenderContextInfo);
  415. var
  416. i: Integer;
  417. depth, dist: Single;
  418. posVector, v, rv: TAffineVector;
  419. screenPos: TAffineVector;
  420. flareInViewPort, dynamicSize: Boolean;
  421. oldSeed: LongInt;
  422. projMatrix: TGLMatrix;
  423. CurrentBuffer: TGLSceneBuffer;
  424. begin
  425. if (rci.drawState = dsPicking) then
  426. begin
  427. if Count <> 0 then
  428. Self.RenderChildren(0, Count - 1, rci);
  429. Exit;
  430. end;
  431. CurrentBuffer := TGLSceneBuffer(rci.buffer);
  432. SetVector(v, AbsolutePosition);
  433. // are we looking towards the flare?
  434. rv := VectorSubtract(v, PAffineVector(@rci.cameraPosition)^);
  435. if VectorDotProduct(rci.cameraDirection, rv) > 0 then
  436. begin
  437. // find out where it is on the screen.
  438. screenPos := CurrentBuffer.WorldToScreen(v);
  439. flareInViewPort := (screenPos.X < rci.viewPortSize.cx)
  440. and (screenPos.X >= 0)
  441. and (screenPos.Y < rci.viewPortSize.cy)
  442. and (screenPos.Y >= 0);
  443. end
  444. else
  445. flareInViewPort := False;
  446. dynamicSize := FDynamic and not (csDesigning in ComponentState);
  447. if dynamicSize then
  448. begin
  449. // make the glow appear/disappear progressively
  450. if flareInViewPort and FlareIsNotOccluded then
  451. begin
  452. FCurrSize := FCurrSize + FDeltaTime * 10 * Size;
  453. if FCurrSize > Size then
  454. FCurrSize := Size;
  455. end
  456. else
  457. begin
  458. FCurrSize := FCurrSize - FDeltaTime * 10 * Size;
  459. if FCurrSize < 0 then
  460. FCurrSize := 0;
  461. end;
  462. end
  463. else
  464. begin
  465. if flareInViewPort and FlareIsNotOccluded then
  466. FCurrSize := Size
  467. else
  468. FCurrSize := 0;
  469. end;
  470. // Prepare matrices
  471. gl.PushMatrix;
  472. gl.LoadMatrixf(@CurrentBuffer.BaseProjectionMatrix);
  473. gl.MatrixMode(GL_PROJECTION);
  474. gl.PushMatrix;
  475. projMatrix := IdentityHmgMatrix;
  476. projMatrix.V[0].X := 2 / rci.viewPortSize.cx;
  477. projMatrix.V[1].Y := 2 / rci.viewPortSize.cy;
  478. gl.LoadMatrixf(@projMatrix);
  479. MakeVector(posVector,
  480. screenPos.X - rci.viewPortSize.cx * 0.5,
  481. screenPos.Y - rci.viewPortSize.cy * 0.5,
  482. 0);
  483. if AutoZTest then
  484. begin
  485. if (dynamicSize and (GL.HP_occlusion_test or
  486. TGLOcclusionQueryHandle.IsSupported)) then
  487. begin
  488. // hardware-based occlusion test is possible
  489. FlareIsNotOccluded := True;
  490. rci.GLStates.SetColorMask([]);
  491. rci.GLStates.Disable(stAlphaTest);
  492. rci.GLStates.DepthWriteMask := False;
  493. rci.GLStates.Enable(stDepthTest);
  494. rci.GLStates.DepthFunc := cfLEqual;
  495. if TGLOcclusionQueryHandle.IsSupported then
  496. begin
  497. // preferred method, doesn't stall rendering too badly
  498. if not Assigned(FOcclusionQuery) then
  499. FOcclusionQuery := TGLOcclusionQueryHandle.Create;
  500. FOcclusionQuery.AllocateHandle;
  501. if FOcclusionQuery.IsDataNeedUpdate then
  502. FOcclusionQuery.NotifyDataUpdated
  503. else
  504. FlareIsNotOccluded := (FOcclusionQuery.PixelCount <> 0);
  505. FOcclusionQuery.BeginQuery;
  506. end
  507. else
  508. begin
  509. // occlusion_test, stalls rendering a bit
  510. gl.Enable(GL_OCCLUSION_TEST_HP);
  511. end;
  512. gl.Begin_(GL_QUADS);
  513. gl.Vertex3f(posVector.X + 2, posVector.Y, 1);
  514. gl.Vertex3f(posVector.X, posVector.Y + 2, 1);
  515. gl.Vertex3f(posVector.X - 2, posVector.Y, 1);
  516. gl.Vertex3f(posVector.X, posVector.Y - 2, 1);
  517. gl.End_;
  518. if TGLOcclusionQueryHandle.IsSupported then
  519. FOcclusionQuery.EndQuery
  520. else
  521. begin
  522. gl.Disable(GL_OCCLUSION_TEST_HP);
  523. gl.GetBooleanv(GL_OCCLUSION_TEST_RESULT_HP, @FFlareIsNotOccluded)
  524. end;
  525. rci.GLStates.DepthFunc := cfLEqual;
  526. rci.GLStates.SetColorMask(cAllColorComponents);
  527. end
  528. else
  529. begin
  530. //Compares the distance to the lensflare, to the z-buffer depth.
  531. //This prevents the flare from being occluded by objects BEHIND the light.
  532. (*
  533. depth := CurrentBuffer.PixelToDistance(Round(ScreenPos.X),
  534. Round(rci.viewPortSize.cy - ScreenPos.Y));
  535. dist := VectorDistance(rci.cameraPosition, self.AbsolutePosition);
  536. FlareIsNotOccluded := ((dist - depth) < 1);
  537. *)
  538. end;
  539. end;
  540. if FCurrSize >= 0 then
  541. begin
  542. // Random seed must be backed up, could be used for other purposes
  543. // (otherwise we essentially reset the random generator at each frame)
  544. oldSeed := RandSeed;
  545. RandSeed := Seed;
  546. SetupRenderingOptions(rci.GLStates);
  547. if [feGlow, feStreaks, feRays, feRing] * Elements <> [] then
  548. begin
  549. gl.Translatef(posVector.X, posVector.Y, posVector.Z);
  550. // Glow (a circle with transparent edges):
  551. if feGlow in Elements then
  552. begin
  553. gl.Begin_(GL_TRIANGLE_FAN);
  554. gl.Color4fv(GlowGradient.FromColor.AsAddress);
  555. gl.Vertex2f(0, 0);
  556. gl.Color4fv(GlowGradient.ToColor.AsAddress);
  557. for i := 0 to Resolution - 1 do
  558. gl.Vertex2f(FCurrSize * FCosRes[i],
  559. Squeeze * FCurrSize * FSinRes[i]);
  560. gl.End_;
  561. end;
  562. if feStreaks in Elements then
  563. RenderStreaks(rci.GLStates);
  564. // Rays (random-length lines from the origin):
  565. if feRays in Elements then
  566. begin
  567. if FTexRays.Handle <> 0 then
  568. begin
  569. {$IFDEF USE_OPENGL_DEBUG}
  570. if GL.GREMEDY_string_marker then
  571. GL.StringMarkerGREMEDY(19, 'LensFlare.RaysQuad');
  572. {$ENDIF}
  573. rci.GLStates.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
  574. rci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
  575. gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  576. gl.Begin_(GL_QUADS);
  577. gl.TexCoord2f(0, 0);
  578. gl.Vertex2f(-FCurrSize, -FCurrSize);
  579. gl.TexCoord2f(1, 0);
  580. gl.Vertex2f(FCurrSize, -FCurrSize);
  581. gl.TexCoord2f(1, 1);
  582. gl.Vertex2f(FCurrSize, FCurrSize);
  583. gl.TexCoord2f(0, 1);
  584. gl.Vertex2f(-FCurrSize, FCurrSize);
  585. gl.End_;
  586. rci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
  587. end
  588. else
  589. RenderRays(rci.GLStates, FCurrSize);
  590. end;
  591. if feRing in Elements then
  592. RenderRing;
  593. gl.LoadMatrixf(@projMatrix);
  594. end;
  595. if feSecondaries in Elements then
  596. RenderSecondaries(posVector);
  597. RandSeed := oldSeed;
  598. end;
  599. gl.PopMatrix;
  600. gl.MatrixMode(GL_MODELVIEW);
  601. gl.PopMatrix;
  602. if Count > 0 then
  603. Self.RenderChildren(0, Count - 1, rci);
  604. end;
  605. procedure TGLLensFlare.DoProgress(const progressTime: TGLProgressTimes);
  606. begin
  607. inherited;
  608. FDeltaTime := progressTime.deltaTime;
  609. end;
  610. procedure TGLLensFlare.PreRender(activeBuffer: TGLSceneBuffer);
  611. var
  612. i, texSize, maxSize: Integer;
  613. stateCache: TGLStateCache;
  614. begin
  615. if FTexRays.Handle <> 0 then
  616. Exit;
  617. with activeBuffer.RenderingContext do
  618. begin
  619. stateCache := GLStates;
  620. PipelineTransformation.Push;
  621. PipelineTransformation.SetProjectionMatrix(CreateOrthoMatrix(0, activeBuffer.Width, 0, activeBuffer.Height, -1, 1));
  622. PipelineTransformation.SetViewMatrix(IdentityHmgMatrix);
  623. end;
  624. SetupRenderingOptions(stateCache);
  625. texSize := RoundUpToPowerOf2(Size);
  626. if texSize < Size * 1.5 then
  627. texSize := texSize * 2;
  628. gl.GetIntegerv(GL_MAX_TEXTURE_SIZE, @maxSize);
  629. if texSize > maxSize then
  630. texSize := maxSize;
  631. stateCache.Disable(stBlend);
  632. gl.Color4f(0, 0, 0, 0);
  633. gl.Begin_(GL_QUADS);
  634. gl.Vertex2f(0, 0);
  635. gl.Vertex2f(texSize + 4, 0);
  636. gl.Vertex2f(texSize + 4, texSize + 4);
  637. gl.Vertex2f(0, texSize + 4);
  638. gl.End_;
  639. stateCache.Enable(stBlend);
  640. gl.Translatef(texSize * 0.5 + 2, texSize * 0.5 + 2, 0);
  641. RenderRays(stateCache, texSize * 0.5);
  642. FTexRays.AllocateHandle;
  643. stateCache.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
  644. if gl.EXT_texture_edge_clamp then
  645. i := GL_CLAMP_TO_EDGE
  646. else
  647. i := GL_CLAMP;
  648. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, i);
  649. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, i);
  650. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  651. gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  652. gl.CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, texSize, texSize, 0);
  653. activeBuffer.RenderingContext.PipelineTransformation.Pop;
  654. gl.CheckError;
  655. end;
  656. procedure TGLLensFlare.SetGlowGradient(const val: TGLFlareGradient);
  657. begin
  658. FGlowGradient.Assign(val);
  659. StructureChanged;
  660. end;
  661. procedure TGLLensFlare.SetRingGradient(const val: TGLFlareGradient);
  662. begin
  663. FRingGradient.Assign(val);
  664. StructureChanged;
  665. end;
  666. procedure TGLLensFlare.SetStreaksGradient(const val: TGLFlareGradient);
  667. begin
  668. FStreaksGradient.Assign(val);
  669. StructureChanged;
  670. end;
  671. procedure TGLLensFlare.SetRaysGradient(const val: TGLFlareGradient);
  672. begin
  673. FRaysGradient.Assign(val);
  674. StructureChanged;
  675. end;
  676. procedure TGLLensFlare.SetSecondariesGradient(const val: TGLFlareGradient);
  677. begin
  678. FSecondariesGradient.Assign(val);
  679. StructureChanged;
  680. end;
  681. procedure TGLLensFlare.SetSize(aValue: Integer);
  682. begin
  683. FSize := aValue;
  684. StructureChanged;
  685. end;
  686. procedure TGLLensFlare.SetSeed(aValue: Integer);
  687. begin
  688. FSeed := aValue;
  689. StructureChanged;
  690. end;
  691. procedure TGLLensFlare.SetSqueeze(aValue: Single);
  692. begin
  693. FSqueeze := aValue;
  694. StructureChanged;
  695. end;
  696. function TGLLensFlare.StoreSqueeze: Boolean;
  697. begin
  698. Result := (FSqueeze <> 1);
  699. end;
  700. procedure TGLLensFlare.SetNumStreaks(aValue: Integer);
  701. begin
  702. FNumStreaks := aValue;
  703. StructureChanged;
  704. end;
  705. procedure TGLLensFlare.SetStreakWidth(aValue: Single);
  706. begin
  707. FStreakWidth := aValue;
  708. StructureChanged;
  709. end;
  710. function TGLLensFlare.StoreStreakWidth: Boolean;
  711. begin
  712. Result := (FStreakWidth <> 2);
  713. end;
  714. procedure TGLLensFlare.SetStreakAngle(aValue: Single);
  715. begin
  716. FStreakAngle := aValue;
  717. StructureChanged;
  718. end;
  719. procedure TGLLensFlare.SetNumSecs(aValue: Integer);
  720. begin
  721. FNumSecs := aValue;
  722. StructureChanged;
  723. end;
  724. procedure TGLLensFlare.SetResolution(aValue: Integer);
  725. begin
  726. if FResolution <> aValue then
  727. begin
  728. FResolution := aValue;
  729. StructureChanged;
  730. SetLength(FSin20Res, 20 * FResolution);
  731. SetLength(FCos20Res, 20 * FResolution);
  732. PrepareSinCosCache(FSin20Res, FCos20Res, 0, 360);
  733. SetLength(FSinRes, FResolution);
  734. SetLength(FCosRes, FResolution);
  735. PrepareSinCosCache(FSinRes, FCosRes, 0, 360);
  736. end;
  737. end;
  738. procedure TGLLensFlare.SetAutoZTest(aValue: Boolean);
  739. begin
  740. if FAutoZTest <> aValue then
  741. begin
  742. FAutoZTest := aValue;
  743. StructureChanged;
  744. end;
  745. end;
  746. procedure TGLLensFlare.SetElements(aValue: TGLFlareElements);
  747. begin
  748. if FElements <> aValue then
  749. begin
  750. FElements := aValue;
  751. StructureChanged;
  752. end;
  753. end;
  754. procedure TGLLensFlare.SetDynamic(aValue: Boolean);
  755. begin
  756. if aValue <> FDynamic then
  757. begin
  758. FDynamic := aValue;
  759. NotifyChange(Self);
  760. end;
  761. end;
  762. procedure TGLLensFlare.SetPreRenderPoint(const val: TGLRenderPoint);
  763. begin
  764. if val <> FPreRenderPoint then
  765. begin
  766. if Assigned(FPreRenderPoint) then
  767. FPreRenderPoint.UnRegisterCallBack(Self.PreRenderEvent);
  768. FPreRenderPoint := val;
  769. if Assigned(FPreRenderPoint) then
  770. FPreRenderPoint.RegisterCallBack(Self.PreRenderEvent,
  771. Self.PreRenderPointFreed);
  772. end;
  773. end;
  774. procedure TGLLensFlare.PreRenderEvent(Sender: TObject; var rci:
  775. TGLRenderContextInfo);
  776. begin
  777. PreRender(rci.buffer as TGLSceneBuffer);
  778. end;
  779. procedure TGLLensFlare.PreRenderPointFreed(Sender: TObject);
  780. begin
  781. FPreRenderPoint := nil;
  782. end;
  783. // ------------------------------------------------------------------
  784. initialization
  785. // ------------------------------------------------------------------
  786. RegisterClasses([TGLLensFlare]);
  787. end.