123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.LensFlare;
- (* Lens flare object *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- System.Math,
- Stage.VectorTypes,
- Stage.VectorGeometry,
- Stage.Utils,
- GXS.PersistentClasses,
- GXS.BaseClasses,
- GXS.Scene,
- GXS.Objects,
- Stage.PipelineTransform,
- GXS.Context,
- GXS.Color,
- GXS.RenderContextInfo,
- GXS.State,
- GXS.ImageUtils,
- Stage.TextureFormat;
- type
- TFlareElement = (feGlow, feRing, feStreaks, feRays, feSecondaries);
- TFlareElements = set of TFlareElement;
- { 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. }
- TgxFlareGradient = class(TgxUpdateAbleObject)
- private
- FFromColor: TgxColor;
- FToColor: TgxColor;
- protected
- procedure SetFromColor(const val: TgxColor);
- procedure SetToColor(const val: TgxColor);
- public
- constructor Create(AOwner: TPersistent); override;
- constructor CreateInitialized(AOwner: TPersistent; const fromColor, toColor: TgxColorVector);
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- published
- property fromColor: TgxColor read FFromColor write SetFromColor;
- property toColor: TgxColor read FToColor write SetToColor;
- end;
- const
- cDefaultFlareElements = [feGlow, feRing, feStreaks, feRays, feSecondaries];
- type
- TgxLensFlare = class(TgxBaseSceneObject)
- private
- FSize: Integer;
- FDeltaTime: Single;
- FCurrSize: Single;
- FSeed: Integer;
- FSqueeze: Single;
- FNumStreaks: Integer;
- FStreakWidth, FStreakAngle: Single;
- FNumSecs: Integer;
- FResolution: Integer;
- FAutoZTest: Boolean;
- FElements: TFlareElements;
- FSin20Res, FCos20Res: array of Single;
- FSinRes, FCosRes: array of Single;
- FTexRays: TgxTextureHandle;
- FFlareIsNotOccluded: Boolean;
- FOcclusionQuery: TgxOcclusionQueryHandle;
- FGlowGradient: TgxFlareGradient;
- FRingGradient: TgxFlareGradient;
- FStreaksGradient: TgxFlareGradient;
- FRaysGradient: TgxFlareGradient;
- FSecondariesGradient: TgxFlareGradient;
- FDynamic: Boolean;
- FPreRenderPoint: TgxRenderPoint;
- protected
- procedure SetGlowGradient(const val: TgxFlareGradient);
- procedure SetRingGradient(const val: TgxFlareGradient);
- procedure SetStreaksGradient(const val: TgxFlareGradient);
- procedure SetRaysGradient(const val: TgxFlareGradient);
- procedure SetSecondariesGradient(const val: TgxFlareGradient);
- 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: TFlareElements);
- procedure SetDynamic(aValue: Boolean);
- procedure SetPreRenderPoint(const val: TgxRenderPoint);
- procedure PreRenderEvent(Sender: TObject; var rci: TgxRenderContextInfo);
- 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: TgxStateCache);
- procedure RenderRays(StateCache: TgxStateCache; const size: Single);
- procedure RenderStreaks(StateCache: TgxStateCache);
- 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: TgxRenderContextInfo); override;
- procedure DoProgress(const progressTime: TgxProgressTimes); 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: TgxSceneBuffer);
- { 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: TgxFlareGradient read FGlowGradient write SetGlowGradient;
- property RingGradient: TgxFlareGradient read FRingGradient;
- property StreaksGradient: TgxFlareGradient read FStreaksGradient;
- property RaysGradient: TgxFlareGradient read FRaysGradient;
- property SecondariesGradient: TgxFlareGradient 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: TFlareElements 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: TgxRenderPoint read FPreRenderPoint write SetPreRenderPoint;
- property ObjectsSorting;
- property Position;
- property Visible;
- property OnProgress;
- property Behaviours;
- property Effects;
- end;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- // ------------------
- // ------------------ TgxFlareGradient ------------------
- // ------------------
- constructor TgxFlareGradient.Create(AOwner: TPersistent);
- begin
- inherited;
- FFromColor := TgxColor.Create(Self);
- FToColor := TgxColor.Create(Self);
- end;
- constructor TgxFlareGradient.CreateInitialized(AOwner: TPersistent; const fromColor, toColor: TgxColorVector);
- begin
- Create(AOwner);
- FFromColor.Initialize(fromColor);
- FToColor.Initialize(toColor);
- end;
- destructor TgxFlareGradient.Destroy;
- begin
- FToColor.Free;
- FFromColor.Free;
- inherited;
- end;
- procedure TgxFlareGradient.Assign(Source: TPersistent);
- begin
- if Source is TgxFlareGradient then
- begin
- fromColor := TgxFlareGradient(Source).fromColor;
- toColor := TgxFlareGradient(Source).toColor;
- end;
- inherited;
- end;
- procedure TgxFlareGradient.SetFromColor(const val: TgxColor);
- begin
- FFromColor.Assign(val);
- end;
- procedure TgxFlareGradient.SetToColor(const val: TgxColor);
- begin
- FToColor.Assign(val);
- end;
- // ------------------
- // ------------------ TgxLensFlare ------------------
- // ------------------
- constructor TgxLensFlare.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 := TgxFlareGradient.CreateInitialized(Self, VectorMake(1, 1, 0.8, 0.3), VectorMake(1, 0.2, 0, 0));
- FRingGradient := TgxFlareGradient.CreateInitialized(Self, VectorMake(0.5, 0.2, 0, 0.1), VectorMake(0.5, 0.4, 0, 0.1));
- FStreaksGradient := TgxFlareGradient.CreateInitialized(Self, VectorMake(1, 1, 1, 0.2), VectorMake(0.2, 0, 1, 0));
- FRaysGradient := TgxFlareGradient.CreateInitialized(Self, VectorMake(1, 0.8, 0.5, 0.05), VectorMake(0.5, 0.2, 0, 0));
- FSecondariesGradient := TgxFlareGradient.CreateInitialized(Self, VectorMake(0, 0.2, 1, 0), VectorMake(0, 0.8, 0.2, 0.15));
- FTexRays := TgxTextureHandle.Create;
- end;
- destructor TgxLensFlare.Destroy;
- begin
- PreRenderPoint := nil;
- FGlowGradient.Free;
- FRingGradient.Free;
- FStreaksGradient.Free;
- FRaysGradient.Free;
- FSecondariesGradient.Free;
- FOcclusionQuery.Free;
- FTexRays.Free;
- inherited;
- end;
- procedure TgxLensFlare.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FPreRenderPoint) then
- PreRenderPoint := nil;
- inherited;
- end;
- procedure TgxLensFlare.SetupRenderingOptions(StateCache: TgxStateCache);
- begin
- with StateCache do
- begin
- Disable(stLighting);
- Disable(stDepthTest);
- Disable(stFog);
- Disable(stColorMaterial);
- Disable(stCullFace);
- DepthWriteMask := False;
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOne);
- Disable(stAlphaTest);
- PolygonMode := pmFill;
- end;
- end;
- procedure TgxLensFlare.RenderRays(StateCache: TgxStateCache; const size: Single);
- var
- i: Integer;
- rnd: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- glStringMarkerGREMEDY(14, 'LensFlare.Rays');
- {$ENDIF}
- with StateCache do
- begin
- LineWidth := 1;
- Disable(stLineSmooth);
- Disable(stLineStipple);
- end;
- glBegin(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;
- glColor4fv(@RaysGradient.fromColor.AsAddress^);
- glVertex2f(0, 0);
- glColor4fv(@RaysGradient.toColor.AsAddress^);
- glVertex2f(rnd * FCos20Res[i], rnd * FSin20Res[i] * Squeeze);
- end;
- glEnd;
- end;
- procedure TgxLensFlare.RenderStreaks(StateCache: TgxStateCache);
- var
- i: Integer;
- a, f, s, c: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- glStringMarkerGREMEDY(17, 'LensFlare.Streaks');
- {$ENDIF}
- StateCache.Enable(stLineSmooth);
- StateCache.LineWidth := StreakWidth;
- a := c2PI / NumStreaks;
- f := 1.5 * FCurrSize;
- glBegin(GL_LINES);
- for i := 0 to NumStreaks - 1 do
- begin
- SinCosine(StreakAngle * cPIdiv180 + a * i, f, s, c);
- glColor4fv(@StreaksGradient.fromColor.AsAddress^);
- glVertex3fv(@NullVector);
- glColor4fv(@StreaksGradient.toColor.AsAddress^);
- glVertex2f(c, Squeeze * s);
- end;
- glEnd;
- StateCache.Disable(stLineSmooth);
- end;
- procedure TgxLensFlare.RenderRing;
- var
- i: Integer;
- rW, s0, c0, s, c: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- glStringMarkerGREMEDY(14, 'LensFlare.Ring');
- {$ENDIF}
- rW := FCurrSize * (1 / 15); // Ring width
- glBegin(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;
- glColor4fv(@GlowGradient.toColor.AsAddress^);
- glVertex2f((FCurrSize - rW) * c, (FCurrSize - rW) * s);
- glColor4fv(@RingGradient.fromColor.AsAddress^);
- glVertex2f(FCurrSize * c, Squeeze * FCurrSize * s);
- glVertex2f(FCurrSize * c0, FCurrSize * s0);
- glColor4fv(@GlowGradient.toColor.AsAddress^);
- glVertex2f((FCurrSize - rW) * c0, (FCurrSize - rW) * s0);
- glColor4fv(@RingGradient.fromColor.AsAddress^);
- glVertex2f(FCurrSize * c, FCurrSize * s);
- glVertex2f(FCurrSize * c0, FCurrSize * s0);
- glColor4fv(@GlowGradient.toColor.AsAddress^);
- glVertex2f((FCurrSize + rW) * c0, (FCurrSize + rW) * s0);
- glVertex2f((FCurrSize + rW) * c, (FCurrSize + rW) * s);
- end;
- glEnd;
- end;
- procedure TgxLensFlare.RenderSecondaries(const posVector: TAffineVector);
- var
- i, j: Integer;
- rnd: Single;
- v: TAffineVector;
- grad: TgxFlareGradient;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- glStringMarkerGREMEDY(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;
- glBegin(GL_TRIANGLE_FAN);
- glColor4fv(@Grad.fromColor.AsAddress^);
- glVertex2f(v.X, v.Y);
- glColor4fv(@Grad.toColor.AsAddress^);
- for i := 0 to Resolution - 1 do
- glVertex2f(FCosRes[i] * rnd + v.X, FSinRes[i] * rnd + v.Y);
- glEnd;
- end;
- end;
- procedure TgxLensFlare.BuildList(var rci: TgxRenderContextInfo);
- var
- i: Integer;
- depth, dist: Single;
- posVector, v, rv: TAffineVector;
- screenPos: TAffineVector;
- flareInViewPort, dynamicSize: Boolean;
- oldSeed: LongInt;
- projMatrix: TMatrix4f;
- CurrentBuffer: TgxSceneBuffer;
- begin
- if (rci.drawState = dsPicking) then
- begin
- if Count <> 0 then
- Self.RenderChildren(0, Count - 1, rci);
- Exit;
- end;
- CurrentBuffer := TgxSceneBuffer(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
- glPushMatrix;
- glLoadMatrixf(@CurrentBuffer.BaseProjectionMatrix);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix;
- projMatrix := IdentityHmgMatrix;
- projMatrix.X.X := 2 / rci.viewPortSize.cx;
- projMatrix.Y.Y := 2 / rci.viewPortSize.cy;
- glLoadMatrixf(@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 (TgxOcclusionQueryHandle.IsSupported = True) then //GL_OCCLUSION_TEST_HP
- begin
- // hardware-based occlusion test is possible
- FlareIsNotOccluded := True;
- rci.gxStates.SetColorMask([]);
- rci.gxStates.Disable(stAlphaTest);
- rci.gxStates.DepthWriteMask := False;
- rci.gxStates.Enable(stDepthTest);
- rci.gxStates.DepthFunc := cfLEqual;
- if TgxOcclusionQueryHandle.IsSupported > False then
- begin
- // preferred method, doesn't stall rendering too badly
- if not Assigned(FOcclusionQuery) then
- FOcclusionQuery := TgxOcclusionQueryHandle.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
- glEnable(GL_OCCLUSION_TEST_HP);
- end;
- glBegin(GL_QUADS);
- glVertex3f(posVector.X + 2, posVector.Y, 1);
- glVertex3f(posVector.X, posVector.Y + 2, 1);
- glVertex3f(posVector.X - 2, posVector.Y, 1);
- glVertex3f(posVector.X, posVector.Y - 2, 1);
- glEnd;
- if TgxOcclusionQueryHandle.IsSupported > False then
- FOcclusionQuery.EndQuery
- else
- begin
- glDisable(GL_OCCLUSION_TEST_HP);
- glGetBooleanv(GL_OCCLUSION_TEST_RESULT_HP, @FFlareIsNotOccluded)
- end;
- rci.gxStates.DepthFunc := cfLEqual;
- rci.gxStates.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.gxStates);
- if [feGlow, feStreaks, feRays, feRing] * Elements <> [] then
- begin
- glTranslatef(posVector.X, posVector.Y, posVector.Z);
- // Glow (a circle with transparent edges):
- if feGlow in Elements then
- begin
- glBegin(GL_TRIANGLE_FAN);
- glColor4fv(@GlowGradient.fromColor.AsAddress^);
- glVertex2f(0, 0);
- glColor4fv(@GlowGradient.toColor.AsAddress^);
- for i := 0 to Resolution - 1 do
- glVertex2f(FCurrSize * FCosRes[i], Squeeze * FCurrSize * FSinRes[i]);
- glEnd;
- end;
- if feStreaks in Elements then
- RenderStreaks(rci.gxStates);
- // 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
- glStringMarkerGREMEDY(19, 'LensFlare.RaysQuad');
- {$ENDIF}
- rci.gxStates.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
- rci.gxStates.ActiveTextureEnabled[ttTexture2D] := True;
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(-FCurrSize, -FCurrSize);
- glTexCoord2f(1, 0);
- glVertex2f(FCurrSize, -FCurrSize);
- glTexCoord2f(1, 1);
- glVertex2f(FCurrSize, FCurrSize);
- glTexCoord2f(0, 1);
- glVertex2f(-FCurrSize, FCurrSize);
- glEnd;
- rci.gxStates.ActiveTextureEnabled[ttTexture2D] := False;
- end
- else
- RenderRays(rci.gxStates, FCurrSize);
- end;
- if feRing in Elements then
- RenderRing;
- glLoadMatrixf(@projMatrix);
- end;
- if feSecondaries in Elements then
- RenderSecondaries(posVector);
- RandSeed := oldSeed;
- end;
- glPopMatrix;
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix;
- if Count > 0 then
- Self.RenderChildren(0, Count - 1, rci);
- end;
- procedure TgxLensFlare.DoProgress(const progressTime: TgxProgressTimes);
- begin
- inherited;
- FDeltaTime := progressTime.deltaTime;
- end;
- procedure TgxLensFlare.PreRender(activeBuffer: TgxSceneBuffer);
- var
- texSize, maxSize: Integer;
- StateCache: TgxStateCache;
- begin
- if FTexRays.Handle <> 0 then
- Exit;
- with activeBuffer.RenderingContext do
- begin
- StateCache := gxStates;
- 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;
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, @maxSize);
- if texSize > maxSize then
- texSize := maxSize;
- StateCache.Disable(stBlend);
- glColor4f(0, 0, 0, 0);
- glBegin(GL_QUADS);
- glVertex2f(0, 0);
- glVertex2f(texSize + 4, 0);
- glVertex2f(texSize + 4, texSize + 4);
- glVertex2f(0, texSize + 4);
- glEnd;
- StateCache.Enable(stBlend);
- glTranslatef(texSize * 0.5 + 2, texSize * 0.5 + 2, 0);
- RenderRays(StateCache, texSize * 0.5);
- FTexRays.AllocateHandle;
- StateCache.TextureBinding[0, ttTexture2D] := FTexRays.Handle;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, texSize, texSize, 0);
- activeBuffer.RenderingContext.PipelineTransformation.Pop;
- /// CheckOpenGLError;
- end;
- procedure TgxLensFlare.SetGlowGradient(const val: TgxFlareGradient);
- begin
- FGlowGradient.Assign(val);
- StructureChanged;
- end;
- procedure TgxLensFlare.SetRingGradient(const val: TgxFlareGradient);
- begin
- FRingGradient.Assign(val);
- StructureChanged;
- end;
- procedure TgxLensFlare.SetStreaksGradient(const val: TgxFlareGradient);
- begin
- FStreaksGradient.Assign(val);
- StructureChanged;
- end;
- procedure TgxLensFlare.SetRaysGradient(const val: TgxFlareGradient);
- begin
- FRaysGradient.Assign(val);
- StructureChanged;
- end;
- procedure TgxLensFlare.SetSecondariesGradient(const val: TgxFlareGradient);
- begin
- FSecondariesGradient.Assign(val);
- StructureChanged;
- end;
- procedure TgxLensFlare.SetSize(aValue: Integer);
- begin
- FSize := aValue;
- StructureChanged;
- end;
- procedure TgxLensFlare.SetSeed(aValue: Integer);
- begin
- FSeed := aValue;
- StructureChanged;
- end;
- procedure TgxLensFlare.SetSqueeze(aValue: Single);
- begin
- FSqueeze := aValue;
- StructureChanged;
- end;
- function TgxLensFlare.StoreSqueeze: Boolean;
- begin
- Result := (FSqueeze <> 1);
- end;
- procedure TgxLensFlare.SetNumStreaks(aValue: Integer);
- begin
- FNumStreaks := aValue;
- StructureChanged;
- end;
- procedure TgxLensFlare.SetStreakWidth(aValue: Single);
- begin
- FStreakWidth := aValue;
- StructureChanged;
- end;
- function TgxLensFlare.StoreStreakWidth: Boolean;
- begin
- Result := (FStreakWidth <> 2);
- end;
- procedure TgxLensFlare.SetStreakAngle(aValue: Single);
- begin
- FStreakAngle := aValue;
- StructureChanged;
- end;
- procedure TgxLensFlare.SetNumSecs(aValue: Integer);
- begin
- FNumSecs := aValue;
- StructureChanged;
- end;
- procedure TgxLensFlare.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 TgxLensFlare.SetAutoZTest(aValue: Boolean);
- begin
- if FAutoZTest <> aValue then
- begin
- FAutoZTest := aValue;
- StructureChanged;
- end;
- end;
- procedure TgxLensFlare.SetElements(aValue: TFlareElements);
- begin
- if FElements <> aValue then
- begin
- FElements := aValue;
- StructureChanged;
- end;
- end;
- procedure TgxLensFlare.SetDynamic(aValue: Boolean);
- begin
- if aValue <> FDynamic then
- begin
- FDynamic := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLensFlare.SetPreRenderPoint(const val: TgxRenderPoint);
- 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 TgxLensFlare.PreRenderEvent(Sender: TObject; var rci: TgxRenderContextInfo);
- begin
- PreRender(rci.buffer as TgxSceneBuffer);
- end;
- procedure TgxLensFlare.PreRenderPointFreed(Sender: TObject);
- begin
- FPreRenderPoint := nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClasses([TgxLensFlare]);
- end.
|