123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- //
- // The graphics engine GLScene
- //
- unit GLS.LensFlare;
- (*
- Lens flare object.
- Registered components: [TGLLensFlare]
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- System.Math,
- Stage.OpenGLTokens,
- GLS.PersistentClasses,
- Stage.VectorGeometry,
- GLS.BaseClasses,
- Stage.VectorTypes,
- GLS.Scene,
- Stage.PipelineTransform,
- GLS.Objects,
- GLS.Context,
- GLS.Color,
- GLS.RenderContextInfo,
- GLS.State,
- Stage.Utils,
- Stage.TextureFormat;
- type
- TGLFlareElement = (feGlow, feRing, feStreaks, feRays, feSecondaries);
- TGLFlareElements = set of TGLFlareElement;
- (* The actual gradients between two colors are, of course, calculated by OpenGL.
- The start and end colors of a gradient are stored to represent the color of
- lens flare elements. *)
- TGLFlareGradient = class(TGLUpdateAbleObject)
- private
- FFromColor: TGLColor;
- FToColor: TGLColor;
- protected
- procedure SetFromColor(const val: TGLColor);
- procedure SetToColor(const val: TGLColor);
- public
- constructor Create(AOwner: TPersistent); override;
- constructor CreateInitialized(AOwner: TPersistent;
- const fromColor, toColor: TGLColorVector);
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- published
- property FromColor: TGLColor read FFromColor write SetFromColor;
- property ToColor: TGLColor read FToColor write SetToColor;
- end;
- const
- cDefaultFlareElements = [feGlow, feRing, feStreaks, feRays, feSecondaries];
- type
- TGLLensFlare = class(TGLBaseSceneObject)
- private
- FSize: Integer;
- FDeltaTime: Single;
- FCurrSize: Single;
- FSeed: Integer;
- FSqueeze: Single;
- FNumStreaks: Integer;
- FStreakWidth, FStreakAngle: Single;
- FNumSecs: Integer;
- FResolution: Integer;
- FAutoZTest: Boolean;
- FElements: TGLFlareElements;
- FSin20Res, FCos20Res: array of Single;
- FSinRes, FCosRes: array of Single;
- FTexRays: TGLTextureHandle;
- FFlareIsNotOccluded: Boolean;
- FOcclusionQuery: TGLOcclusionQueryHandle;
- FGlowGradient: TGLFlareGradient;
- FRingGradient: TGLFlareGradient;
- FStreaksGradient: TGLFlareGradient;
- FRaysGradient: TGLFlareGradient;
- FSecondariesGradient: TGLFlareGradient;
- FDynamic: Boolean;
- FPreRenderPoint: TGLRenderPoint;
- protected
- procedure SetGlowGradient(const val: TGLFlareGradient);
- procedure SetRingGradient(const val: TGLFlareGradient);
- procedure SetStreaksGradient(const val: TGLFlareGradient);
- procedure SetRaysGradient(const val: TGLFlareGradient);
- procedure SetSecondariesGradient(const val: TGLFlareGradient);
- procedure SetSize(aValue: Integer);
- procedure SetSeed(aValue: Integer);
- procedure SetSqueeze(aValue: Single);
- function StoreSqueeze: Boolean;
- procedure SetNumStreaks(aValue: Integer);
- procedure SetStreakWidth(aValue: Single);
- function StoreStreakWidth: Boolean;
- procedure SetStreakAngle(aValue: Single);
- procedure SetNumSecs(aValue: Integer);
- procedure SetResolution(aValue: Integer);
- procedure SetAutoZTest(aValue: Boolean);
- procedure SetElements(aValue: TGLFlareElements);
- procedure SetDynamic(aValue: Boolean);
- procedure SetPreRenderPoint(const val: TGLRenderPoint);
- procedure PreRenderEvent(Sender: TObject; var rci: TGLRenderContextInfo);
- procedure PreRenderPointFreed(Sender: TObject);
- (* These are quite unusual in that they don't use an RCI, since
- PreRender is done before proper rendering starts, but we do know
- which RC is being used, so we can use this state cache *)
- procedure SetupRenderingOptions(StateCache: TGLStateCache);
- procedure RenderRays(StateCache: TGLStateCache; const size: Single);
- procedure RenderStreaks(StateCache: TGLStateCache);
- procedure RenderRing;
- procedure RenderSecondaries(const posVector: TAffineVector);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- procedure DoProgress(const progressTime: TGLProgressTimes); override;
- (* Prepares pre-rendered texture to speed up actual rendering.
- Will use the currently active context as scratch space, and will
- automatically do nothing if things have already been prepared,
- thus you can invoke it systematically in a Viewer.BeforeRender
- event f.i. *)
- procedure PreRender(activeBuffer: TGLSceneBuffer);
- (* Access to the Flare's current size.
- Flares decay or grow back over several frames, depending on their
- occlusion status, and this property allows to track or manually
- alter this instantaneous size. *)
- property FlareInstantaneousSize: Single read FCurrSize write FCurrSize;
- published
- property GlowGradient: TGLFlareGradient read FGlowGradient write SetGlowGradient;
- property RingGradient: TGLFlareGradient read FRingGradient;
- property StreaksGradient: TGLFlareGradient read FStreaksGradient;
- property RaysGradient: TGLFlareGradient read FRaysGradient;
- property SecondariesGradient: TGLFlareGradient read FSecondariesGradient;
- // MaxRadius of the flare.
- property Size: Integer read FSize write SetSize default 50;
- // Random seed
- property Seed: Integer read FSeed write SetSeed;
- // To create elliptic flares.
- property Squeeze: Single read FSqueeze write SetSqueeze stored StoreSqueeze;
- // Number of streaks.
- property NumStreaks: Integer read FNumStreaks write SetNumStreaks default 4;
- // Width of the streaks.
- property StreakWidth: Single read FStreakWidth write SetStreakWidth stored
- StoreStreakWidth;
- // Angle of the streaks (in degrees)
- property StreakAngle: Single read FStreakAngle write SetStreakAngle;
- // Number of secondary flares.
- property NumSecs: Integer read FNumSecs write SetNumSecs default 8;
- // Number of segments used when rendering circles.
- property Resolution: Integer read FResolution write SetResolution default 64;
- (* Automatically computes FlareIsNotOccluded depending on ZBuffer test.
- Not that the automated test may use test result from the previous
- frame into the next (to avoid a rendering stall). *)
- property AutoZTest: Boolean read FAutoZTest write SetAutoZTest default True;
- (* Is the LensFlare not occluded?.
- If false the flare will fade away, if true, it will fade in and stay.
- This value is automatically updated if AutoZTest is set. *)
- property FlareIsNotOccluded: Boolean read FFlareIsNotOccluded write
- FFlareIsNotOccluded;
- // Which elements should be rendered?
- property Elements: TGLFlareElements read FElements write SetElements default
- cDefaultFlareElements;
- (* Is the flare size adjusted dynamically?
- If true, the flare size will be grown and reduced over a few frames
- when it switches between occluded and non-occluded states. This
- requires animation to be active, but results in a smoother appearance.
- When false, flare will either be at full size or hidden.
- The flare is always considered non-dynamic at design-time. *)
- property Dynamic: Boolean read FDynamic write FDynamic default True;
- (* PreRender point for pre-rendered flare textures.
- See PreRender method for more details. *)
- property PreRenderPoint: TGLRenderPoint read FPreRenderPoint write
- SetPreRenderPoint;
- property ObjectsSorting;
- property Position;
- property Visible;
- property OnProgress;
- property Behaviours;
- property Effects;
- end;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- // ------------------
- // ------------------ TGLFlareGradient ------------------
- // ------------------
- constructor TGLFlareGradient.Create(AOwner: TPersistent);
- begin
- inherited;
- FFromColor := TGLColor.Create(Self);
- FToColor := TGLColor.Create(Self);
- end;
- constructor TGLFlareGradient.CreateInitialized(AOwner: TPersistent;
- const fromColor, toColor: TGLColorVector);
- begin
- Create(AOwner);
- FFromColor.Initialize(fromColor);
- FToColor.Initialize(toColor);
- end;
- destructor TGLFlareGradient.Destroy;
- begin
- FToColor.Free;
- FFromColor.Free;
- inherited;
- end;
- procedure TGLFlareGradient.Assign(Source: TPersistent);
- begin
- if Source is TGLFlareGradient then
- begin
- FromColor := TGLFlareGradient(Source).FromColor;
- ToColor := TGLFlareGradient(Source).ToColor;
- end;
- inherited;
- end;
- procedure TGLFlareGradient.SetFromColor(const val: TGLColor);
- begin
- FFromColor.Assign(val);
- end;
- procedure TGLFlareGradient.SetToColor(const val: TGLColor);
- begin
- FToColor.Assign(val);
- end;
- // ------------------
- // ------------------ TGLLensFlare ------------------
- // ------------------
- constructor TGLLensFlare.Create(AOwner: TComponent);
- begin
- inherited;
- // Set default parameters:
- ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
- FSize := 50;
- FSeed := 1465;
- FSqueeze := 1;
- FNumStreaks := 4;
- FStreakWidth := 2;
- FNumSecs := 8;
- FAutoZTest := True;
- FlareIsNotOccluded := True;
- FDynamic := True;
- SetResolution(64);
- // Render all elements by default.
- FElements := [feGlow, feRing, feStreaks, feRays, feSecondaries];
- // Setup default gradients:
- FGlowGradient := TGLFlareGradient.CreateInitialized(Self,
- VectorMake(1, 1, 0.8, 0.3), VectorMake(1, 0.2, 0, 0));
- FRingGradient := TGLFlareGradient.CreateInitialized(Self,
- VectorMake(0.5, 0.2, 0, 0.1), VectorMake(0.5, 0.4, 0, 0.1));
- FStreaksGradient := TGLFlareGradient.CreateInitialized(Self,
- VectorMake(1, 1, 1, 0.2), VectorMake(0.2, 0, 1, 0));
- FRaysGradient := TGLFlareGradient.CreateInitialized(Self,
- VectorMake(1, 0.8, 0.5, 0.05), VectorMake(0.5, 0.2, 0, 0));
- FSecondariesGradient := TGLFlareGradient.CreateInitialized(Self,
- VectorMake(0, 0.2, 1, 0), VectorMake(0, 0.8, 0.2, 0.15));
- FTexRays := TGLTextureHandle.Create;
- end;
- destructor TGLLensFlare.Destroy;
- begin
- PreRenderPoint := nil;
- FGlowGradient.Free;
- FRingGradient.Free;
- FStreaksGradient.Free;
- FRaysGradient.Free;
- FSecondariesGradient.Free;
- FOcclusionQuery.Free;
- FTexRays.Free;
- inherited;
- end;
- procedure TGLLensFlare.Notification(AComponent: TComponent; Operation:
- TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FPreRenderPoint) then
- PreRenderPoint := nil;
- inherited;
- end;
- procedure TGLLensFlare.SetupRenderingOptions(StateCache: TGLStateCache);
- begin
- StateCache.Disable(stLighting);
- StateCache.Disable(stDepthTest);
- StateCache.Disable(stFog);
- StateCache.Disable(stColorMaterial);
- StateCache.Disable(stCullFace);
- StateCache.DepthWriteMask := False;
- StateCache.Enable(stBlend);
- StateCache.SetBlendFunc(bfSrcAlpha, bfOne);
- StateCache.Disable(stAlphaTest);
- StateCache.PolygonMode := pmFill;
- end;
- procedure TGLLensFlare.RenderRays(StateCache: TGLStateCache; const size:
- Single);
- var
- i: Integer;
- rnd: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if gl.GREMEDY_string_marker then
- gl.StringMarkerGREMEDY(14, 'LensFlare.Rays');
- {$ENDIF}
- StateCache.LineWidth := 1;
- StateCache.Disable(stLineSmooth);
- StateCache.Disable(stLineStipple);
- gl.Begin_(GL_LINES);
- for i := 0 to Resolution * 20 - 1 do
- begin
- if (i and 1) <> 0 then
- rnd := 1.5 * Random * size
- else
- rnd := Random * size;
- gl.Color4fv(RaysGradient.FromColor.AsAddress);
- gl.Vertex2f(0, 0);
- gl.Color4fv(RaysGradient.ToColor.AsAddress);
- gl.Vertex2f(rnd * FCos20Res[i], rnd * FSin20Res[i] * Squeeze);
- end;
- gl.End_;
- end;
- procedure TGLLensFlare.RenderStreaks(StateCache: TGLStateCache);
- var
- i: Integer;
- a, f, s, c: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if gl.GREMEDY_string_marker then
- gl.StringMarkerGREMEDY(17, 'LensFlare.Streaks');
- {$ENDIF}
- StateCache.Enable(stLineSmooth);
- StateCache.LineWidth := StreakWidth;
- a := c2PI / NumStreaks;
- f := 1.5 * FCurrSize;
- gl.Begin_(GL_LINES);
- for i := 0 to NumStreaks - 1 do
- begin
- SinCosine(StreakAngle * cPIdiv180 + a * i, f, s, c);
- gl.Color4fv(StreaksGradient.FromColor.AsAddress);
- gl.Vertex3fv(@NullVector);
- gl.Color4fv(StreaksGradient.ToColor.AsAddress);
- gl.Vertex2f(c, Squeeze * s);
- end;
- gl.End_;
- StateCache.Disable(stLineSmooth);
- end;
- procedure TGLLensFlare.RenderRing;
- var
- i: Integer;
- rW, s0, c0, s, c: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL.GREMEDY_string_marker then
- GL.StringMarkerGREMEDY(14, 'LensFlare.Ring');
- {$ENDIF}
- rW := FCurrSize * (1 / 15); // Ring width
- gl.Begin_(GL_QUADS);
- s0 := 0;
- c0 := 0.6;
- for i := 0 to Resolution - 1 do
- begin
- s := s0;
- c := c0;
- s0 := FSinRes[i] * 0.6 * Squeeze;
- c0 := FCosRes[i] * 0.6;
- gl.Color4fv(GlowGradient.ToColor.AsAddress);
- gl.Vertex2f((FCurrSize - rW) * c, (FCurrSize - rW) * s);
- gl.Color4fv(RingGradient.FromColor.AsAddress);
- gl.Vertex2f(FCurrSize * c, Squeeze * FCurrSize * s);
- gl.Vertex2f(FCurrSize * c0, FCurrSize * s0);
- gl.Color4fv(GlowGradient.ToColor.AsAddress);
- gl.Vertex2f((FCurrSize - rW) * c0, (FCurrSize - rW) * s0);
- gl.Color4fv(RingGradient.FromColor.AsAddress);
- gl.Vertex2f(FCurrSize * c, FCurrSize * s);
- gl.Vertex2f(FCurrSize * c0, FCurrSize * s0);
- gl.Color4fv(GlowGradient.ToColor.AsAddress);
- gl.Vertex2f((FCurrSize + rW) * c0, (FCurrSize + rW) * s0);
- gl.Vertex2f((FCurrSize + rW) * c, (FCurrSize + rW) * s);
- end;
- gl.End_;
- end;
- procedure TGLLensFlare.RenderSecondaries(const posVector: TAffineVector);
- var
- i, j: Integer;
- rnd: Single;
- v: TAffineVector;
- grad: TGLFlareGradient;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL.GREMEDY_string_marker then
- GL.StringMarkerGREMEDY(21, 'LensFlare.Secondaries');
- {$ENDIF}
- // Other secondaries (plain gradiented circles, like the glow):
- for j := 1 to NumSecs do
- begin
- rnd := 2 * Random - 1;
- // If rnd < 0 then the secondary glow will end up on the other side
- // of the origin. In this case, we can push it really far away from
- // the flare. If the secondary is on the flare's side, we pull it
- // slightly towards the origin to avoid it winding up in the middle
- // of the flare.
- if rnd < 0 then
- v := VectorScale(posVector, rnd)
- else
- v := VectorScale(posVector, 0.8 * rnd);
- if j mod 3 = 0 then
- grad := GlowGradient
- else
- grad := SecondariesGradient;
- rnd := (Random + 0.1) * FCurrSize * 0.25;
- gl.Begin_(GL_TRIANGLE_FAN);
- gl.Color4fv(grad.FromColor.AsAddress);
- gl.Vertex2f(v.X, v.Y);
- gl.Color4fv(grad.ToColor.AsAddress);
- for i := 0 to Resolution - 1 do
- gl.Vertex2f(FCosRes[i] * rnd + v.X, FSinRes[i] * rnd + v.Y);
- gl.End_;
- end;
- end;
- procedure TGLLensFlare.BuildList(var rci: TGLRenderContextInfo);
- var
- i: Integer;
- depth, dist: Single;
- posVector, v, rv: TAffineVector;
- screenPos: TAffineVector;
- flareInViewPort, dynamicSize: Boolean;
- oldSeed: LongInt;
- projMatrix: TGLMatrix;
- CurrentBuffer: TGLSceneBuffer;
- begin
- if (rci.drawState = dsPicking) then
- begin
- if Count <> 0 then
- Self.RenderChildren(0, Count - 1, rci);
- Exit;
- end;
- CurrentBuffer := TGLSceneBuffer(rci.buffer);
- SetVector(v, AbsolutePosition);
- // are we looking towards the flare?
- rv := VectorSubtract(v, PAffineVector(@rci.cameraPosition)^);
- if VectorDotProduct(rci.cameraDirection, rv) > 0 then
- begin
- // find out where it is on the screen.
- screenPos := CurrentBuffer.WorldToScreen(v);
- flareInViewPort := (screenPos.X < rci.viewPortSize.cx)
- and (screenPos.X >= 0)
- and (screenPos.Y < rci.viewPortSize.cy)
- and (screenPos.Y >= 0);
- end
- else
- flareInViewPort := False;
- dynamicSize := FDynamic and not (csDesigning in ComponentState);
- if dynamicSize then
- begin
- // make the glow appear/disappear progressively
- if flareInViewPort and FlareIsNotOccluded then
- begin
- FCurrSize := FCurrSize + FDeltaTime * 10 * Size;
- if FCurrSize > Size then
- FCurrSize := Size;
- end
- else
- begin
- FCurrSize := FCurrSize - FDeltaTime * 10 * Size;
- if FCurrSize < 0 then
- FCurrSize := 0;
- end;
- end
- else
- begin
- if flareInViewPort and FlareIsNotOccluded then
- FCurrSize := Size
- else
- FCurrSize := 0;
- end;
- // Prepare matrices
- gl.PushMatrix;
- gl.LoadMatrixf(@CurrentBuffer.BaseProjectionMatrix);
- gl.MatrixMode(GL_PROJECTION);
- gl.PushMatrix;
- projMatrix := IdentityHmgMatrix;
- projMatrix.V[0].X := 2 / rci.viewPortSize.cx;
- projMatrix.V[1].Y := 2 / rci.viewPortSize.cy;
- gl.LoadMatrixf(@projMatrix);
- MakeVector(posVector,
- screenPos.X - rci.viewPortSize.cx * 0.5,
- screenPos.Y - rci.viewPortSize.cy * 0.5,
- 0);
- if AutoZTest then
- begin
- if (dynamicSize and (GL.HP_occlusion_test or
- TGLOcclusionQueryHandle.IsSupported)) then
- begin
- // hardware-based occlusion test is possible
- FlareIsNotOccluded := True;
- rci.GLStates.SetColorMask([]);
- rci.GLStates.Disable(stAlphaTest);
- rci.GLStates.DepthWriteMask := False;
- rci.GLStates.Enable(stDepthTest);
- rci.GLStates.DepthFunc := cfLEqual;
- if TGLOcclusionQueryHandle.IsSupported then
- begin
- // preferred method, doesn't stall rendering too badly
- if not Assigned(FOcclusionQuery) then
- FOcclusionQuery := TGLOcclusionQueryHandle.Create;
- FOcclusionQuery.AllocateHandle;
- if FOcclusionQuery.IsDataNeedUpdate then
- FOcclusionQuery.NotifyDataUpdated
- else
- FlareIsNotOccluded := (FOcclusionQuery.PixelCount <> 0);
- FOcclusionQuery.BeginQuery;
- end
- else
- begin
- // occlusion_test, stalls rendering a bit
- gl.Enable(GL_OCCLUSION_TEST_HP);
- end;
- gl.Begin_(GL_QUADS);
- gl.Vertex3f(posVector.X + 2, posVector.Y, 1);
- gl.Vertex3f(posVector.X, posVector.Y + 2, 1);
- gl.Vertex3f(posVector.X - 2, posVector.Y, 1);
- gl.Vertex3f(posVector.X, posVector.Y - 2, 1);
- gl.End_;
- if TGLOcclusionQueryHandle.IsSupported then
- FOcclusionQuery.EndQuery
- else
- begin
- gl.Disable(GL_OCCLUSION_TEST_HP);
- gl.GetBooleanv(GL_OCCLUSION_TEST_RESULT_HP, @FFlareIsNotOccluded)
- end;
- rci.GLStates.DepthFunc := cfLEqual;
- rci.GLStates.SetColorMask(cAllColorComponents);
- end
- else
- begin
- //Compares the distance to the lensflare, to the z-buffer depth.
- //This prevents the flare from being occluded by objects BEHIND the light.
- (*
- depth := CurrentBuffer.PixelToDistance(Round(ScreenPos.X),
- Round(rci.viewPortSize.cy - ScreenPos.Y));
- dist := VectorDistance(rci.cameraPosition, self.AbsolutePosition);
- FlareIsNotOccluded := ((dist - depth) < 1);
- *)
- end;
- end;
- if FCurrSize >= 0 then
- begin
- // Random seed must be backed up, could be used for other purposes
- // (otherwise we essentially reset the random generator at each frame)
- oldSeed := RandSeed;
- RandSeed := Seed;
- SetupRenderingOptions(rci.GLStates);
- if [feGlow, feStreaks, feRays, feRing] * Elements <> [] then
- begin
- gl.Translatef(posVector.X, posVector.Y, posVector.Z);
- // Glow (a circle with transparent edges):
- if feGlow in Elements then
- begin
- gl.Begin_(GL_TRIANGLE_FAN);
- gl.Color4fv(GlowGradient.FromColor.AsAddress);
- gl.Vertex2f(0, 0);
- gl.Color4fv(GlowGradient.ToColor.AsAddress);
- for i := 0 to Resolution - 1 do
- gl.Vertex2f(FCurrSize * FCosRes[i],
- Squeeze * FCurrSize * FSinRes[i]);
- gl.End_;
- end;
- if feStreaks in Elements then
- RenderStreaks(rci.GLStates);
- // Rays (random-length lines from the origin):
- if feRays in Elements then
- begin
- if FTexRays.Handle <> 0 then
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL.GREMEDY_string_marker then
- GL.StringMarkerGREMEDY(19, 'LensFlare.RaysQuad');
- {$ENDIF}
- rci.GLStates.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
- rci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
- gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- gl.Begin_(GL_QUADS);
- gl.TexCoord2f(0, 0);
- gl.Vertex2f(-FCurrSize, -FCurrSize);
- gl.TexCoord2f(1, 0);
- gl.Vertex2f(FCurrSize, -FCurrSize);
- gl.TexCoord2f(1, 1);
- gl.Vertex2f(FCurrSize, FCurrSize);
- gl.TexCoord2f(0, 1);
- gl.Vertex2f(-FCurrSize, FCurrSize);
- gl.End_;
- rci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
- end
- else
- RenderRays(rci.GLStates, FCurrSize);
- end;
- if feRing in Elements then
- RenderRing;
- gl.LoadMatrixf(@projMatrix);
- end;
- if feSecondaries in Elements then
- RenderSecondaries(posVector);
- RandSeed := oldSeed;
- end;
- gl.PopMatrix;
- gl.MatrixMode(GL_MODELVIEW);
- gl.PopMatrix;
- if Count > 0 then
- Self.RenderChildren(0, Count - 1, rci);
- end;
- procedure TGLLensFlare.DoProgress(const progressTime: TGLProgressTimes);
- begin
- inherited;
- FDeltaTime := progressTime.deltaTime;
- end;
- procedure TGLLensFlare.PreRender(activeBuffer: TGLSceneBuffer);
- var
- i, texSize, maxSize: Integer;
- stateCache: TGLStateCache;
- begin
- if FTexRays.Handle <> 0 then
- Exit;
- with activeBuffer.RenderingContext do
- begin
- stateCache := GLStates;
- PipelineTransformation.Push;
- PipelineTransformation.SetProjectionMatrix(CreateOrthoMatrix(0, activeBuffer.Width, 0, activeBuffer.Height, -1, 1));
- PipelineTransformation.SetViewMatrix(IdentityHmgMatrix);
- end;
- SetupRenderingOptions(stateCache);
- texSize := RoundUpToPowerOf2(Size);
- if texSize < Size * 1.5 then
- texSize := texSize * 2;
- gl.GetIntegerv(GL_MAX_TEXTURE_SIZE, @maxSize);
- if texSize > maxSize then
- texSize := maxSize;
- stateCache.Disable(stBlend);
- gl.Color4f(0, 0, 0, 0);
- gl.Begin_(GL_QUADS);
- gl.Vertex2f(0, 0);
- gl.Vertex2f(texSize + 4, 0);
- gl.Vertex2f(texSize + 4, texSize + 4);
- gl.Vertex2f(0, texSize + 4);
- gl.End_;
- stateCache.Enable(stBlend);
- gl.Translatef(texSize * 0.5 + 2, texSize * 0.5 + 2, 0);
- RenderRays(stateCache, texSize * 0.5);
- FTexRays.AllocateHandle;
- stateCache.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
- if gl.EXT_texture_edge_clamp then
- i := GL_CLAMP_TO_EDGE
- else
- i := GL_CLAMP;
- gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, i);
- gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, i);
- gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl.CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, texSize, texSize, 0);
- activeBuffer.RenderingContext.PipelineTransformation.Pop;
- gl.CheckError;
- end;
- procedure TGLLensFlare.SetGlowGradient(const val: TGLFlareGradient);
- begin
- FGlowGradient.Assign(val);
- StructureChanged;
- end;
- procedure TGLLensFlare.SetRingGradient(const val: TGLFlareGradient);
- begin
- FRingGradient.Assign(val);
- StructureChanged;
- end;
- procedure TGLLensFlare.SetStreaksGradient(const val: TGLFlareGradient);
- begin
- FStreaksGradient.Assign(val);
- StructureChanged;
- end;
- procedure TGLLensFlare.SetRaysGradient(const val: TGLFlareGradient);
- begin
- FRaysGradient.Assign(val);
- StructureChanged;
- end;
- procedure TGLLensFlare.SetSecondariesGradient(const val: TGLFlareGradient);
- begin
- FSecondariesGradient.Assign(val);
- StructureChanged;
- end;
- procedure TGLLensFlare.SetSize(aValue: Integer);
- begin
- FSize := aValue;
- StructureChanged;
- end;
- procedure TGLLensFlare.SetSeed(aValue: Integer);
- begin
- FSeed := aValue;
- StructureChanged;
- end;
- procedure TGLLensFlare.SetSqueeze(aValue: Single);
- begin
- FSqueeze := aValue;
- StructureChanged;
- end;
- function TGLLensFlare.StoreSqueeze: Boolean;
- begin
- Result := (FSqueeze <> 1);
- end;
- procedure TGLLensFlare.SetNumStreaks(aValue: Integer);
- begin
- FNumStreaks := aValue;
- StructureChanged;
- end;
- procedure TGLLensFlare.SetStreakWidth(aValue: Single);
- begin
- FStreakWidth := aValue;
- StructureChanged;
- end;
- function TGLLensFlare.StoreStreakWidth: Boolean;
- begin
- Result := (FStreakWidth <> 2);
- end;
- procedure TGLLensFlare.SetStreakAngle(aValue: Single);
- begin
- FStreakAngle := aValue;
- StructureChanged;
- end;
- procedure TGLLensFlare.SetNumSecs(aValue: Integer);
- begin
- FNumSecs := aValue;
- StructureChanged;
- end;
- procedure TGLLensFlare.SetResolution(aValue: Integer);
- begin
- if FResolution <> aValue then
- begin
- FResolution := aValue;
- StructureChanged;
- SetLength(FSin20Res, 20 * FResolution);
- SetLength(FCos20Res, 20 * FResolution);
- PrepareSinCosCache(FSin20Res, FCos20Res, 0, 360);
- SetLength(FSinRes, FResolution);
- SetLength(FCosRes, FResolution);
- PrepareSinCosCache(FSinRes, FCosRes, 0, 360);
- end;
- end;
- procedure TGLLensFlare.SetAutoZTest(aValue: Boolean);
- begin
- if FAutoZTest <> aValue then
- begin
- FAutoZTest := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLLensFlare.SetElements(aValue: TGLFlareElements);
- begin
- if FElements <> aValue then
- begin
- FElements := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLLensFlare.SetDynamic(aValue: Boolean);
- begin
- if aValue <> FDynamic then
- begin
- FDynamic := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TGLLensFlare.SetPreRenderPoint(const val: TGLRenderPoint);
- begin
- if val <> FPreRenderPoint then
- begin
- if Assigned(FPreRenderPoint) then
- FPreRenderPoint.UnRegisterCallBack(Self.PreRenderEvent);
- FPreRenderPoint := val;
- if Assigned(FPreRenderPoint) then
- FPreRenderPoint.RegisterCallBack(Self.PreRenderEvent,
- Self.PreRenderPointFreed);
- end;
- end;
- procedure TGLLensFlare.PreRenderEvent(Sender: TObject; var rci:
- TGLRenderContextInfo);
- begin
- PreRender(rci.buffer as TGLSceneBuffer);
- end;
- procedure TGLLensFlare.PreRenderPointFreed(Sender: TObject);
- begin
- FPreRenderPoint := nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClasses([TGLLensFlare]);
- end.
|