123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.ThorFX;
- (* ThorFX for Scene *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- System.Classes,
- System.SysUtils,
- System.Math,
- GXS.XCollection,
- GXS.Scene,
- Stage.PipelineTransform,
- Stage.VectorGeometry,
- GXS.Context,
- GXS.VectorLists,
- Stage.VectorTypes,
- GXS.Cadencer,
- GXS.Color,
- GXS.BaseClasses,
- GXS.Coordinates,
- GXS.RenderContextInfo,
- Stage.Manager,
- GXS.State,
- Stage.TextureFormat;
- type
- PThorpoint = ^TThorpoint;
- TThorpoint = record
- Position: TVector4f; // Position
- Size: single; // particle size
- end;
- PThorpointArray = ^TThorpointArray;
- TThorpointArray = array [0 .. MAXINT shr 6] of TThorpoint;
- TgxBThorFX = class;
- TCalcPointEvent = procedure(Sender: TObject; PointNo: integer; var x: single;
- var y: single; var z: single) of object;
- // Thor special effect manager.
- TgxThorFXManager = class(TgxCadenceAbleComponent)
- private
- FClients: TList;
- FThorpoints: PThorpointArray;
- FTarget: TgxCoordinates;
- FCadencer: TgxCadencer;
- FMaxpoints: integer;
- FGlowSize: single;
- FVibrate: single;
- FWildness: single;
- NP: integer;
- FInnerColor, FOuterColor, FCoreColor: TgxColor;
- FDisabled, FCore, FGlow: boolean;
- FOnCalcPoint: TCalcPointEvent;
- protected
- procedure RegisterClient(aClient: TgxBThorFX);
- procedure DeRegisterClient(aClient: TgxBThorFX);
- procedure DeRegisterAllClients;
- procedure SetTarget(const val: TgxCoordinates);
- procedure SetCadencer(const val: TgxCadencer);
- procedure SetMaxpoints(const val: integer);
- function StoreGlowSize: boolean;
- function StoreVibrate: boolean;
- procedure SetInnerColor(const val: TgxColor);
- procedure SetOuterColor(const val: TgxColor);
- procedure SetCoreColor(const val: TgxColor);
- procedure Notification(AComponent: TComponent;
- Operation: TOperation); override;
- procedure ThorInit;
- procedure CalcThor;
- procedure CalcFrac(left, right: integer; lh, rh: single; xyz: integer);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoProgress(const progressTime: TgxProgressTimes); override;
- published
- property Target: TgxCoordinates read FTarget write SetTarget;
- property Cadencer: TgxCadencer read FCadencer write SetCadencer;
- property Maxpoints: integer read FMaxpoints write SetMaxpoints default 256;
- property GlowSize: single read FGlowSize write FGlowSize
- stored StoreGlowSize;
- property Vibrate: single read FVibrate write FVibrate stored StoreVibrate;
- property InnerColor: TgxColor read FInnerColor write SetInnerColor;
- property OuterColor: TgxColor read FOuterColor write SetOuterColor;
- // default clrWhite;
- property CoreColor: TgxColor read FCoreColor write SetCoreColor;
- // default clrWhite;
- property Disabled: boolean read FDisabled write FDisabled;
- property Core: boolean read FCore write FCore;
- property Glow: boolean read FGlow write FGlow;
- property Wildness: single read FWildness write FWildness;
- property OnCalcPoint: TCalcPointEvent read FOnCalcPoint write FOnCalcPoint;
- end;
- // Thor special effect
- TgxBThorFX = class(TgxObjectPostEffect)
- private
- FManager: TgxThorFXManager;
- FManagerName: String; // NOT persistent, temporarily used for persistence
- FTarget: TgxCoordinates;
- protected
- procedure SetManager(const val: TgxThorFXManager);
- procedure WriteToFiler(writer: TWriter); override;
- procedure ReadFromFiler(reader: TReader); override;
- procedure Loaded; override;
- procedure SetTarget(const val: TgxCoordinates);
- public
- constructor Create(AOwner: TXCollection); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- class function FriendlyName: String; override;
- class function FriendlyDescription: String; override;
- procedure Render(var rci: TgxRenderContextInfo); override;
- published
- { Refers the collision manager. }
- property Manager: TgxThorFXManager read FManager write SetManager;
- end;
- { Returns or creates the TgxBThorFX within the given object's effects. }
- function GetOrCreateThorFX(obj: TgxBaseSceneObject; const name: String = '')
- : TgxBThorFX;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- // ------------------
- // ------------------ TgxThorFXManager ------------------
- // ------------------
- constructor TgxThorFXManager.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FClients := TList.Create;
- RegisterManager(Self);
- FTarget := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 1, 0));
- FTarget.Style := csPoint;
- FMaxpoints := 64;
- FGlowSize := 0.2;
- FVibrate := 0;
- FWildness := 1;
- FInnerColor := TgxColor.Create(Self);
- FInnerColor.Initialize(clrWhite);
- FOuterColor := TgxColor.Create(Self);
- FOuterColor.Initialize(clrBlue);
- FOuterColor.Alpha := 0;
- FCoreColor := TgxColor.Create(Self);
- FCoreColor.Initialize(clrWhite);
- FCore := True;
- FGlow := True;
- ThorInit;
- end;
- destructor TgxThorFXManager.Destroy;
- begin
- DeRegisterAllClients;
- DeRegisterManager(Self);
- FreeMem(FThorpoints);
- FreeAndNil(FClients);
- FreeAndNil(FInnerColor);
- FreeAndNil(FOuterColor);
- FreeAndNil(FCoreColor);
- FreeAndNil(FTarget);
- inherited Destroy;
- end;
- procedure TgxThorFXManager.RegisterClient(aClient: TgxBThorFX);
- begin
- if Assigned(aClient) then
- if FClients.IndexOf(aClient) < 0 then
- begin
- FClients.Add(aClient);
- aClient.FManager := Self;
- end;
- end;
- procedure TgxThorFXManager.DeRegisterClient(aClient: TgxBThorFX);
- begin
- if Assigned(aClient) then
- begin
- aClient.FManager := nil;
- FClients.Remove(aClient);
- end;
- end;
- procedure TgxThorFXManager.DeRegisterAllClients;
- var
- i: integer;
- begin
- // Fast deregistration
- for i := 0 to FClients.Count - 1 do
- TgxBThorFX(FClients[i]).FManager := nil;
- FClients.Clear;
- end;
- procedure TgxThorFXManager.SetTarget(const val: TgxCoordinates);
- begin
- FTarget.Assign(val);
- ThorInit;
- end;
- procedure TgxThorFXManager.SetCadencer(const val: TgxCadencer);
- begin
- if FCadencer <> val then
- begin
- if Assigned(FCadencer) then
- FCadencer.UnSubscribe(Self);
- FCadencer := val;
- if Assigned(FCadencer) then
- FCadencer.Subscribe(Self);
- end;
- end;
- procedure TgxThorFXManager.SetMaxpoints(const val: integer);
- begin
- if FMaxpoints <> val then
- begin
- FMaxpoints := val;
- ThorInit;
- end;
- end;
- function TgxThorFXManager.StoreGlowSize: boolean;
- begin
- Result := (FGlowSize <> 1);
- end;
- function TgxThorFXManager.StoreVibrate: boolean;
- begin
- Result := (FVibrate <> 1);
- end;
- procedure TgxThorFXManager.SetInnerColor(const val: TgxColor);
- begin
- if FInnerColor <> val then
- begin
- FInnerColor.color := val.color;
- ThorInit;
- end;
- end;
- procedure TgxThorFXManager.SetOuterColor(const val: TgxColor);
- begin
- if FOuterColor <> val then
- begin
- FOuterColor.color := val.color;
- ThorInit;
- end;
- end;
- procedure TgxThorFXManager.SetCoreColor(const val: TgxColor);
- begin
- if FCoreColor <> val then
- begin
- FCoreColor.color := val.color;
- ThorInit;
- end;
- end;
- procedure TgxThorFXManager.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FCadencer) then
- Cadencer := nil;
- inherited;
- end;
- procedure TgxThorFXManager.DoProgress(const progressTime: TgxProgressTimes);
- var
- i: integer;
- begin
- if not FDisabled then
- CalcThor;
- // Invalidate all clients
- for i := 0 to FClients.Count - 1 do
- TgxBThorFX(FClients[i]).OwnerBaseSceneObject.NotifyChange
- (TgxBThorFX(FClients[i]));
- end;
- procedure TgxThorFXManager.ThorInit;
- begin
- ReallocMem(FThorpoints, FMaxpoints * Sizeof(TThorpoint));
- end;
- procedure TgxThorFXManager.CalcThor;
- var
- N: integer;
- vec, axs, nvec: TVector4f;
- dist: single;
- a, b: single;
- len: single;
- begin
- // initialise all points with valid data
- for N := 0 to Maxpoints - 1 do
- SetVector(FThorpoints^[N].Position, 0, 0, 0);
- // ------------------Calculate fractal (wildness)---------------
- // SetVector(FThorpoints[0].Position,0,0,0);
- SetVector(FThorpoints^[Maxpoints - 1].Position, 0, 0, 0);
- CalcFrac(0, Maxpoints - 1, 0, 0, 0);
- CalcFrac(0, Maxpoints - 1, 0, 0, 1);
- // CalcFrac(0,maxpoints-1,0,FTarget.z,2);
- // ---------------Rotate Vector to target-------------
- SetVector(nvec, FTarget.x, FTarget.y, FTarget.z);
- len := VectorLength(nvec);
- NormalizeVector(nvec);
- a := ArcCos(nvec.Z);
- b := ArcTan2(nvec.X, nvec.Y);
- N := 0;
- While (N < Maxpoints) do
- begin
- dist := N / Maxpoints * len;
- vec := FThorpoints^[N].Position;
- vec.Z := dist;
- if Assigned(OnCalcPoint) then
- OnCalcPoint(Self, N, vec.X, vec.Y, vec.Z);
- // Let user mess around with point position
- SetVector(axs, 1, 0, 0); // Rotate up
- RotateVector(vec, axs, a);
- SetVector(axs, 0, 0, 1); // Rotate to the sides
- RotateVector(vec, axs, b);
- FThorpoints^[N].Position := vec;
- inc(N);
- end;
- // ----------------------------------------------------
- NP := Maxpoints;
- end;
- procedure TgxThorFXManager.CalcFrac(left, right: integer; lh, rh: single;
- xyz: integer);
- var
- midh: single;
- mid: integer;
- res: integer;
- fracScale: single;
- begin
- mid := (left + right) div 2;
- res := (left + right) mod 2;
- fracScale := (right - left) / Maxpoints;
- midh := (lh + rh) / 2 + (fracScale * FWildness * random) -
- (fracScale * FWildness) / 2;
- FThorpoints^[mid].Position.V[xyz] := midh +
- (FVibrate * random - (FVibrate / 2));
- // if res=1 then FThorpoints[right-1].Position[xyz]:=
- // (FThorpoints[right].Position[xyz]+midh)/(right-mid)*(right-mid-1);
- if res = 1 then
- FThorpoints^[right - 1].Position.V[xyz] := FThorpoints^[right].Position.V[xyz];
- if (mid - left) > 1 then
- CalcFrac(left, mid, lh, midh, xyz);
- if (right - mid) > 1 then
- CalcFrac(mid, right, midh, rh, xyz);
- end;
- // ------------------
- // ------------------ TgxBThorFX ------------------
- // ------------------
- constructor TgxBThorFX.Create(AOwner: TXCollection);
- begin
- inherited Create(AOwner);
- FTarget := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 1, 0));
- FTarget.Style := csPoint;
- end;
- destructor TgxBThorFX.Destroy;
- begin
- Manager := nil;
- FreeAndNil(FTarget);
- inherited Destroy;
- end;
- class function TgxBThorFX.FriendlyName: String;
- begin
- Result := 'ThorFX';
- end;
- class function TgxBThorFX.FriendlyDescription: String;
- begin
- Result := 'Thor FX';
- end;
- procedure TgxBThorFX.WriteToFiler(writer: TWriter);
- begin
- with writer do
- begin
- // ArchiveVersion 1, added inherited call
- WriteInteger(1);
- inherited;
- if Assigned(FManager) then
- WriteString(FManager.GetNamePath)
- else
- WriteString('');
- end;
- end;
- procedure TgxBThorFX.ReadFromFiler(reader: TReader);
- var
- archiveVersion: integer;
- begin
- with reader do
- begin
- archiveVersion := ReadInteger;
- Assert(archiveVersion in [0 .. 1]);
- if archiveVersion >= 1 then
- inherited;
- FManagerName := ReadString;
- Manager := nil;
- end;
- end;
- // Loaded
- //
- procedure TgxBThorFX.Loaded;
- var
- mng: TComponent;
- begin
- inherited;
- if FManagerName <> '' then
- begin
- mng := FindManager(TgxThorFXManager, FManagerName);
- if Assigned(mng) then
- Manager := TgxThorFXManager(mng);
- FManagerName := '';
- end;
- end;
- procedure TgxBThorFX.Assign(Source: TPersistent);
- begin
- if Source is TgxBThorFX then
- begin
- Manager := TgxBThorFX(Source).Manager;
- end;
- inherited Assign(Source);
- end;
- procedure TgxBThorFX.SetTarget(const val: TgxCoordinates);
- begin
- FTarget.Assign(val);
- end;
- procedure TgxBThorFX.SetManager(const val: TgxThorFXManager);
- begin
- if val <> FManager then
- begin
- if Assigned(FManager) then
- FManager.DeRegisterClient(Self);
- if Assigned(val) then
- val.RegisterClient(Self);
- end;
- end;
- procedure TgxBThorFX.Render(var rci: TgxRenderContextInfo);
- var
- N: integer;
- i: integer;
- // absPos :TVector4f;
- InnerColor: TVector4f;
- distList: TgxSingleList;
- objList: TList;
- fp: PThorpoint;
- mat: TMatrix4f;
- vx, vy: TVector4f;
- m: integer;
- Icol, Ocol, Ccol: TgxColorVector;
- Ppos, Ppos2: TAffineVector;
- begin
- if Manager = nil then
- Exit;
- rci.PipelineTransformation.Push;
- // we get the object position and apply translation...
- // absPos:=OwnerBaseSceneObject.AbsolutePosition;
- // ...should be removed when absolute coords will be handled directly
- // in the point system (and will also make a better flame effect)
- rci.gxStates.Disable(stCullFace);
- rci.gxStates.ActiveTextureEnabled[ttTexture2D] := False;
- rci.gxStates.Disable(stLighting);
- rci.gxStates.SetBlendFunc(bfSrcAlpha, bfOne);
- rci.gxStates.Enable(stBlend);
- N := Manager.NP;
- if N > 1 then
- begin
- distList := TgxSingleList.Create;
- objList := TList.Create;
- for i := 0 to N - 1 do
- begin
- fp := @(Manager.FThorpoints[i]);
- distList.Add(VectorDotProduct(rci.cameraDirection, fp^.Position));
- objList.Add(fp);
- end;
- QuickSortLists(0, N - 1, distList, objList);
- mat := rci.PipelineTransformation.ModelViewMatrix^;
- for m := 0 to 2 do
- begin
- vx.V[m] := mat.V[m].X * Manager.GlowSize;
- vy.V[m] := mat.V[m].Y * Manager.GlowSize;
- end;
- SetVector(InnerColor, Manager.FInnerColor.color);
- // ---------------
- rci.gxStates.SetBlendFunc(bfSrcAlpha, bfOne);
- rci.gxStates.Enable(stBlend);
- rci.gxStates.Enable(stLineSmooth);
- rci.gxStates.Disable(stLighting);
- // Stops particles at same distanceform overwriting each-other
- rci.gxStates.DepthFunc := cfLEqual;
- rci.gxStates.LineWidth := 3;
- Icol := Manager.FInnerColor.color;
- Ocol := Manager.FOuterColor.color;
- Ccol := Manager.FCoreColor.color;
- // ---Core Line---
- if Manager.FCore then
- begin
- rci.gxStates.Disable(stBlend);
- glColor4fv(@Ccol);
- glBegin(GL_LINE_STRIP);
- for i := 0 to N - 1 do
- begin
- fp := @(Manager.FThorpoints[i]);
- SetVector(Ppos, fp^.Position);
- glVertex3f(Ppos.X, Ppos.Y, Ppos.Z);
- end;
- glEnd;
- end; // Core;
- // ---Point Glow---
- if Manager.FGlow then
- begin
- rci.gxStates.Enable(stBlend);
- for i := N - 1 downto 0 do
- begin
- fp := PThorpoint(objList[i]);
- SetVector(Ppos, fp^.Position);
- fp := @(Manager.FThorpoints[i]);
- SetVector(Ppos2, fp^.Position);
- glBegin(GL_TRIANGLE_FAN);
- glColor4fv(@Icol);
- glVertex3f(Ppos.X, Ppos.Y, Ppos.Z); // middle1
- glColor4fv(@Ocol);
- glVertex3f(Vx.X + Vy.X + Ppos.X,
- Vx.Y + Vy.Y + Ppos.Y, Vx.Z + Vy.Z +
- Ppos.Z); // TopRight
- glVertex3f(Vx.X * 1.4 + Ppos.X,
- Vx.Y * 1.4 + Ppos.Y, Vx.Z * 1.4 + Ppos.Z);
- // Right1
- glVertex3f(Vx.X - Vy.X + Ppos.X,
- Vx.Y - Vy.Y + Ppos.Y, Vx.Z - Vy.Z +
- Ppos.Z); // BottomRight
- glVertex3f(-Vy.X * 1.4 + Ppos.X,
- -Vy.Y * 1.4 + Ppos.Y, -Vy.Z * 1.4 + Ppos.Z
- ); // bottom1
- glVertex3f(-Vx.X - Vy.X + Ppos.X,
- -Vx.Y - Vy.Y + Ppos.Y, -Vx.Z - Vy.Z
- + Ppos.Z); // BottomLeft
- glVertex3f(-Vx.X * 1.4 + Ppos.X,
- -Vx.Y * 1.4 + Ppos.Y, -Vx.Z * 1.4 + Ppos.Z); // left1
- glVertex3f(-Vx.X + Vy.X + Ppos.X,
- -Vx.Y + Vy.Y + Ppos.Y, -Vx.Z + Vy.Z
- + Ppos.Z); // TopLeft
- glVertex3f(Vy.X * 1.4 + Ppos.X,
- Vy.Y * 1.4 + Ppos.Y, Vy.Z * 1.4 + Ppos.Z);
- // top1
- glVertex3f(Vx.X + Vy.X + Ppos.X,
- Vx.Y + Vy.Y + Ppos.Y, Vx.Z + Vy.Z +
- Ppos.Z); // TopRight
- glEnd;
- end; // Glow
- end;
- objList.Free;
- distList.Free;
- end;
- rci.PipelineTransformation.Pop;
- end;
- function GetOrCreateThorFX(obj: TgxBaseSceneObject; const name: String = '')
- : TgxBThorFX;
- var
- i: integer;
- begin
- with obj.Effects do
- begin
- if name = '' then
- begin
- i := IndexOfClass(TgxBThorFX);
- if i >= 0 then
- Result := TgxBThorFX(Items[i])
- else
- Result := TgxBThorFX.Create(obj.Effects);
- end
- else
- begin
- i := IndexOfName(name);
- if i >= 0 then
- Result := (Items[i] as TgxBThorFX)
- else
- begin
- Result := TgxBThorFX.Create(obj.Effects);
- Result.name := name;
- end;
- end;
- end;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterXCollectionItemClass(TgxBThorFX);
- finalization
- UnregisterXCollectionItemClass(TgxBThorFX);
- end.
|