GXS.LensFlare.pas 25 KB

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