aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Classes/UGraphicClasses.pas
diff options
context:
space:
mode:
Diffstat (limited to 'Game/Code/Classes/UGraphicClasses.pas')
-rw-r--r--Game/Code/Classes/UGraphicClasses.pas1351
1 files changed, 673 insertions, 678 deletions
diff --git a/Game/Code/Classes/UGraphicClasses.pas b/Game/Code/Classes/UGraphicClasses.pas
index f176d69c..629a92e5 100644
--- a/Game/Code/Classes/UGraphicClasses.pas
+++ b/Game/Code/Classes/UGraphicClasses.pas
@@ -1,678 +1,673 @@
-// notes:
-unit UGraphicClasses;
-
-interface
-
-{$IFDEF FPC}
- {$MODE Delphi}
-{$ENDIF}
-
-{$I switches.inc}
-
-uses UTexture,SDL;
-
-const DelayBetweenFrames : Cardinal = 60;
-type
-
- TParticleType=(GoldenNote, PerfectNote, NoteHitTwinkle, PerfectLineTwinkle, ColoredStar, Flare);
-
- TColour3f = Record
- r, g, b: Real;
- end;
-
- TParticle = Class
- X, Y : Real; //Position
- Screen : Integer;
- W, H : Cardinal; //dimensions of particle
- Col : array of TColour3f; // Colour(s) of particle
- Scale : array of Real; // Scaling factors of particle layers
- Frame : Byte; //act. Frame
- Tex : Cardinal; //Tex num from Textur Manager
- Live : Byte; //How many Cycles before Kill
- RecIndex : Integer; //To which rectangle this particle belongs (only GoldenNote)
- StarType : TParticleType; // GoldenNote | PerfectNote | NoteHitTwinkle | PerfectLineTwinkle
- Alpha : Real; // used for fading...
- mX, mY : Real; // movement-vector for PerfectLineTwinkle
- SizeMod : Real; // experimental size modifier
- SurviveSentenceChange : Boolean;
-
- Constructor Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
- Destructor Destroy(); override;
- procedure Draw;
- procedure LiveOn;
- end;
-
- RectanglePositions = Record
- xTop, yTop, xBottom, yBottom : Real;
- TotalStarCount : Integer;
- CurrentStarCount : Integer;
- Screen : Integer;
- end;
-
- PerfectNotePositions = Record
- xPos, yPos : Real;
- Screen : Integer;
- end;
-
- TEffectManager = Class
- Particle : array of TParticle;
- LastTime : Cardinal;
- RecArray : Array of RectanglePositions;
- TwinkleArray : Array[0..5] of Real; // store x-position of last twinkle for every player
- PerfNoteArray : Array of PerfectNotePositions;
-
- FlareTex: TTexture;
-
- constructor Create;
- destructor Destroy; override;
- procedure Draw;
- function Spawn(X, Y: Real;
- Screen: Integer;
- Live: Byte;
- StartFrame: Integer;
- RecArrayIndex: Integer; // this is only used with GoldenNotes
- StarType: TParticleType;
- Player: Cardinal // for PerfectLineTwinkle
- ): Cardinal;
- procedure SpawnRec();
- procedure Kill(index: Cardinal);
- procedure KillAll();
- procedure SentenceChange();
- procedure SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
- procedure SavePerfectNotePos(Xtop, Ytop: Real);
- procedure GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
- procedure SpawnPerfectLineTwinkle();
- end;
-
-var GoldenRec : TEffectManager;
-
-implementation
-
-uses sysutils,
- {$IFDEF win32}
- windows,
- {$ELSE}
- lclintf,
- {$ENDIF}
- OpenGl12,
- UIni,
- UMain,
- UThemes,
- USkins,
- UGraphic,
- UDrawTexture,
- UCommon,
- math;
-
-//TParticle
-Constructor TParticle.Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
-begin
- inherited Create;
- // in this constructor we set all initial values for our particle
- X := cX;
- Y := cY;
- Screen := cScreen;
- Live := cLive;
- Frame:= cFrame;
- RecIndex := cRecArrayIndex;
- StarType := cStarType;
- Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
- SetLength(Scale,1);
- Scale[0] := 1;
- SurviveSentenceChange := False;
- SizeMod := 1;
- case cStarType of
- GoldenNote:
- begin
- Tex := Tex_Note_Star.TexNum;
- W := 20;
- H := 20;
- SetLength(Scale,4);
- Scale[1]:=0.8;
- Scale[2]:=0.4;
- Scale[3]:=0.3;
- SetLength(Col,4);
- Col[0].r := 1;
- Col[0].g := 0.7;
- Col[0].b := 0.1;
-
- Col[1].r := 1;
- Col[1].g := 1;
- Col[1].b := 0.4;
-
- Col[2].r := 1;
- Col[2].g := 1;
- Col[2].b := 1;
-
- Col[3].r := 1;
- Col[3].g := 1;
- Col[3].b := 1;
- end;
- PerfectNote:
- begin
- Tex := Tex_Note_Perfect_Star.TexNum;
- W := 30;
- H := 30;
- SetLength(Col,1);
- Col[0].r := 1;
- Col[0].g := 1;
- Col[0].b := 0.95;
- end;
- NoteHitTwinkle:
- begin
- Tex := Tex_Note_Star.TexNum;
- Alpha := (Live/16); // linear fade-out
- W := 15;
- H := 15;
- Setlength(Col,1);
- Col[0].r := 1;
- Col[0].g := 1;
- Col[0].b := RandomRange(10*Live,100)/90; //0.9;
- end;
- PerfectLineTwinkle:
- begin
- Tex := Tex_Note_Star.TexNum;
- W := RandomRange(10,20);
- H := W;
- SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
- SurviveSentenceChange:=True;
- // assign colours according to player given
- SetLength(Scale,3);
- Scale[1]:=0.3;
- Scale[2]:=0.2;
- SetLength(Col,3);
- case Player of
- 0: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
- 1: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P2Light');
- 2: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P3Light');
- 3: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P4Light');
- 4: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P5Light');
- 5: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P6Light');
- else LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
- end;
- Col[1].r := 1;
- Col[1].g := 1;
- Col[1].b := 0.4;
- Col[2].r:=Col[0].r+0.5;
- Col[2].g:=Col[0].g+0.5;
- Col[2].b:=Col[0].b+0.5;
- mX := RandomRange(-5,5);
- mY := RandomRange(-5,5);
- end;
- ColoredStar:
- begin
- Tex := Tex_Note_Star.TexNum;
- W := RandomRange(10,20);
- H := W;
- SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
- SurviveSentenceChange:=True;
- // assign colours according to player given
- SetLength(Scale,1);
- SetLength(Col,1);
- Col[0].b := (Player and $ff)/255;
- Col[0].g := ((Player shr 8) and $ff)/255;
- Col[0].r := ((Player shr 16) and $ff)/255;
- mX := 0;
- mY := 0;
- end;
- Flare:
- begin
- Tex := Tex_Note_Star.TexNum;
- W := 7;
- H := 7;
- SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
- mX := RandomRange(-5,5);
- mY := RandomRange(-5,5);
- SetLength(Scale,4);
- Scale[1]:=0.8;
- Scale[2]:=0.4;
- Scale[3]:=0.3;
- SetLength(Col,4);
- Col[0].r := 1;
- Col[0].g := 0.7;
- Col[0].b := 0.1;
-
- Col[1].r := 1;
- Col[1].g := 1;
- Col[1].b := 0.4;
-
- Col[2].r := 1;
- Col[2].g := 1;
- Col[2].b := 1;
-
- Col[3].r := 1;
- Col[3].g := 1;
- Col[3].b := 1;
-
- end;
- else // just some random default values
- begin
- Tex := Tex_Note_Star.TexNum;
- Alpha := 1;
- W := 20;
- H := 20;
- SetLength(Col,1);
- Col[0].r := 1;
- Col[0].g := 1;
- Col[0].b := 1;
- end;
- end;
-end;
-
-Destructor TParticle.Destroy();
-begin
- SetLength(Scale,0);
- SetLength(Col,0);
- inherited;
-end;
-
-procedure TParticle.LiveOn;
-begin
- //Live = 0 => Live forever <blindy> ?? but if this is 0 they would be killed in the Manager at Draw
- if (Live > 0) then
- Dec(Live);
-
- // animate frames
- Frame := ( Frame + 1 ) mod 16;
-
- // make our particles do funny stuff (besides being animated)
- // changes of any particle-values throughout its life are done here
- case StarType of
- GoldenNote:
- begin
- Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
- end;
- PerfectNote:
- begin
- Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
- end;
- NoteHitTwinkle:
- begin
- Alpha := (Live/10); // linear fade-out
- end;
- PerfectLineTwinkle:
- begin
- Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
- SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
- // move around
- X := X + mX;
- Y := Y + mY;
- end;
- ColoredStar:
- begin
- Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
- end;
- Flare:
- begin
- Alpha := (-cos((Frame+1)/16*1.7*pi+0.3*pi)+1); // neat fade-in-and-out
- SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
- // move around
- X := X + mX;
- Y := Y + mY;
- mY:=mY+1.8;
-// mX:=mX/2;
- end;
- end;
-end;
-
-procedure TParticle.Draw;
-var L: Cardinal;
-begin
- if ScreenAct = Screen then
- // this draws (multiple) texture(s) of our particle
- for L:=0 to High(Col) do
- begin
- glColor4f(Col[L].r, Col[L].g, Col[L].b, Alpha);
-
- glBindTexture(GL_TEXTURE_2D, Tex);
- glEnable(GL_TEXTURE_2D);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
-
- begin
- glBegin(GL_QUADS);
- glTexCoord2f((1/16) * Frame, 0); glVertex2f(X-W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
- glTexCoord2f((1/16) * Frame + (1/16), 0); glVertex2f(X-W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
- glTexCoord2f((1/16) * Frame + (1/16), 1); glVertex2f(X+W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
- glTexCoord2f((1/16) * Frame, 1); glVertex2f(X+W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
- glEnd;
- end;
- end;
- glcolor4f(1,1,1,1);
-end;
-// end of TParticle
-
-// TEffectManager
-
-constructor TEffectManager.Create;
-var c: Cardinal;
-begin
- inherited;
- LastTime := SDL_GetTicks();
- for c:=0 to 5 do
- begin
- TwinkleArray[c] := 0;
- end;
-end;
-
-destructor TEffectManager.Destroy;
-begin
- Killall;
- inherited;
-end;
-
-
-procedure TEffectManager.Draw;
-var
- I: Integer;
- CurrentTime: Cardinal;
-//const
-// DelayBetweenFrames : Cardinal = 100;
-begin
-
- CurrentTime := SDL_GetTicks();
- //Manage particle life
- if (CurrentTime - LastTime) > DelayBetweenFrames then
- begin
- LastTime := CurrentTime;
- for I := 0 to high(Particle) do
- Particle[I].LiveOn;
- end;
-
- I := 0;
- //Kill dead particles
- while (I <= High(Particle)) do
- begin
- if (Particle[I].Live <= 0) then
- begin
- kill(I);
- end
- else
- begin
- inc(I);
- end;
- end;
-
- //Draw
- for I := 0 to high(Particle) do
- begin
- Particle[I].Draw;
- end;
-end;
-
-// this method creates just one particle
-function TEffectManager.Spawn(X, Y: Real; Screen: Integer; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : TParticleType; Player: Cardinal): Cardinal;
-begin
- Result := Length(Particle);
- SetLength(Particle, (Result + 1));
- Particle[Result] := TParticle.Create(X, Y, Screen, Live, StartFrame, RecArrayIndex, StarType, Player);
-end;
-
-// manage Sparkling of GoldenNote Bars
-procedure TEffectManager.SpawnRec();
-Var
- Xkatze, Ykatze : Real;
- RandomFrame : Integer;
- P : Integer; // P as seen on TV as Positionman
-begin
-//Spawn a random amount of stars within the given coordinates
-//RandomRange(0,14) <- this one starts at a random frame, 16 is our last frame - would be senseless to start a particle with 16, cause it would be dead at the next frame
-for P:= 0 to high(RecArray) do
- begin
- while (RecArray[P].TotalStarCount > RecArray[P].CurrentStarCount) do
- begin
- Xkatze := RandomRange(Ceil(RecArray[P].xTop), Ceil(RecArray[P].xBottom));
- Ykatze := RandomRange(Ceil(RecArray[P].yTop), Ceil(RecArray[P].yBottom));
- RandomFrame := RandomRange(0,14);
- // Spawn a GoldenNote Particle
- Spawn(Xkatze, Ykatze, RecArray[P].Screen, 16 - RandomFrame, RandomFrame, P, GoldenNote, 0);
- inc(RecArray[P].CurrentStarCount);
- end;
- end;
- draw;
-end;
-
-// kill one particle (with given index in our particle array)
-procedure TEffectManager.Kill(Index: Cardinal);
-var
- LastParticleIndex : Integer;
-begin
-// delete particle indexed by Index,
-// overwrite it's place in our particle-array with the particle stored at the last array index,
-// shorten array
- LastParticleIndex := high(Particle);
- if not(LastParticleIndex = -1) then // is there still a particle to delete?
- begin
- if not(Particle[Index].RecIndex = -1) then // if it is a GoldenNote particle...
- dec(RecArray[Particle[Index].RecIndex].CurrentStarCount); // take care of its associated GoldenRec
- // now get rid of that particle
- Particle[Index].Destroy;
- Particle[Index] := Particle[LastParticleIndex];
- SetLength(Particle, LastParticleIndex);
- end;
-end;
-
-// clean up all particles and management structures
-procedure TEffectManager.KillAll();
-var c: Cardinal;
-begin
-//It's the kill all kennies rotuine
- while Length(Particle) > 0 do // kill all existing particles
- Kill(0);
- SetLength(RecArray,0); // remove GoldenRec positions
- SetLength(PerfNoteArray,0); // remove PerfectNote positions
- for c:=0 to 5 do
- begin
- TwinkleArray[c] := 0; // reset GoldenNoteHit memory
- end;
-end;
-
-procedure TEffectManager.SentenceChange();
-var c: Cardinal;
-begin
- c:=0;
- while c <= High(Particle) do
- begin
- if Particle[c].SurviveSentenceChange then
- inc(c)
- else
- Kill(c);
- end;
- SetLength(RecArray,0); // remove GoldenRec positions
- SetLength(PerfNoteArray,0); // remove PerfectNote positions
- for c:=0 to 5 do
- begin
- TwinkleArray[c] := 0; // reset GoldenNoteHit memory
- end;
-end;
-
-procedure TeffectManager.GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
-//Twinkle stars while golden note hit
-// this is called from UDraw.pas, SingDrawPlayerCzesc
-var
- C, P, XKatze, YKatze, LKatze: Integer;
- H: Real;
-begin
- // make sure we spawn only one time at one position
- if (TwinkleArray[Player] < Right) then
- For P := 0 to high(RecArray) do // Are we inside a GoldenNoteRectangle?
- begin
- H := (Top+Bottom)/2; // helper...
- with RecArray[P] do
- if ((xBottom >= Right) and (xTop <= Right) and
- (yTop <= H) and (yBottom >= H))
- and (Screen = ScreenAct) then
- begin
- TwinkleArray[Player] := Right; // remember twinkle position for this player
- for C := 1 to 10 do
- begin
- Ykatze := RandomRange(ceil(Top) , ceil(Bottom));
- XKatze := RandomRange(-7,3);
- LKatze := RandomRange(7,13);
- Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
- end;
- for C := 1 to 3 do
- begin
- Ykatze := RandomRange(ceil(Top)-6 , ceil(Top));
- XKatze := RandomRange(-5,1);
- LKatze := RandomRange(4,7);
- Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
- end;
- for C := 1 to 3 do
- begin
- Ykatze := RandomRange(ceil(Bottom), ceil(Bottom)+6);
- XKatze := RandomRange(-5,1);
- LKatze := RandomRange(4,7);
- Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
- end;
- for C := 1 to 3 do
- begin
- Ykatze := RandomRange(ceil(Top)-10 , ceil(Top)-6);
- XKatze := RandomRange(-5,1);
- LKatze := RandomRange(1,4);
- Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
- end;
- for C := 1 to 3 do
- begin
- Ykatze := RandomRange(ceil(Bottom)+6 , ceil(Bottom)+10);
- XKatze := RandomRange(-5,1);
- LKatze := RandomRange(1,4);
- Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
- end;
-
- exit; // found a matching GoldenRec, did spawning stuff... done
- end;
- end;
-end;
-
-procedure TEffectManager.SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
-var
- P : Integer; // P like used in Positions
- NewIndex : Integer;
-begin
- For P := 0 to high(RecArray) do // Do we already have that "new" position?
- begin
- if (ceil(RecArray[P].xTop) = ceil(Xtop)) and
- (ceil(RecArray[P].yTop) = ceil(Ytop)) and
- (ScreenAct = RecArray[p].Screen) then
- exit; // it's already in the array, so we don't have to create a new one
- end;
-
- // we got a new position, add the new positions to our array
- NewIndex := Length(RecArray);
- SetLength(RecArray, NewIndex + 1);
- RecArray[NewIndex].xTop := Xtop;
- RecArray[NewIndex].yTop := Ytop;
- RecArray[NewIndex].xBottom := Xbottom;
- RecArray[NewIndex].yBottom := Ybottom;
- RecArray[NewIndex].TotalStarCount := ceil(Xbottom - Xtop) div 12 + 3;
- RecArray[NewIndex].CurrentStarCount := 0;
- RecArray[NewIndex].Screen := ScreenAct;
-end;
-
-procedure TEffectManager.SavePerfectNotePos(Xtop, Ytop: Real);
-var
- P : Integer; // P like used in Positions
- NewIndex : Integer;
- RandomFrame : Integer;
- Xkatze, Ykatze : Integer;
-begin
- For P := 0 to high(PerfNoteArray) do // Do we already have that "new" position?
- begin
- with PerfNoteArray[P] do
- if (ceil(xPos) = ceil(Xtop)) and (ceil(yPos) = ceil(Ytop)) and
- (Screen = ScreenAct) then
- exit; // it's already in the array, so we don't have to create a new one
- end; //for
-
- // we got a new position, add the new positions to our array
- NewIndex := Length(PerfNoteArray);
- SetLength(PerfNoteArray, NewIndex + 1);
- PerfNoteArray[NewIndex].xPos := Xtop;
- PerfNoteArray[NewIndex].yPos := Ytop;
- PerfNoteArray[NewIndex].Screen := ScreenAct;
-
- for P:= 0 to 2 do
- begin
- Xkatze := RandomRange(ceil(Xtop) - 5 , ceil(Xtop) + 10);
- Ykatze := RandomRange(ceil(Ytop) - 5 , ceil(Ytop) + 10);
- RandomFrame := RandomRange(0,14);
- Spawn(Xkatze, Ykatze, ScreenAct, 16 - RandomFrame, RandomFrame, -1, PerfectNote, 0);
- end; //for
-
-end;
-
-procedure TEffectManager.SpawnPerfectLineTwinkle();
-var
- P,I,Life: Cardinal;
- Left, Right, Top, Bottom: Cardinal;
- cScreen: Integer;
-begin
-// calculation of coordinates done with hardcoded values like in UDraw.pas
-// might need to be adjusted if drawing of SingScreen is modified
-// coordinates may still be a bit weird and need adjustment
- if Ini.SingWindow = 0 then begin
- Left := 130;
- end else begin
- Left := 30;
- end;
- Right := 770;
- // spawn effect for every player with a perfect line
- for P:=0 to PlayersPlay-1 do
- if Player[P].LastSentencePerfect then
- begin
- // calculate area where notes of this player are drawn
- case PlayersPlay of
- 1: begin
- Bottom:=Skin_P2_NotesB+10;
- Top:=Bottom-105;
- cScreen:=1;
- end;
- 2,4: begin
- case P of
- 0,2: begin
- Bottom:=Skin_P1_NotesB+10;
- Top:=Bottom-105;
- end;
- else begin
- Bottom:=Skin_P2_NotesB+10;
- Top:=Bottom-105;
- end;
- end;
- case P of
- 0,1: cScreen:=1;
- else cScreen:=2;
- end;
- end;
- 3,6: begin
- case P of
- 0,3: begin
- Top:=130;
- Bottom:=Top+85;
- end;
- 1,4: begin
- Top:=255;
- Bottom:=Top+85;
- end;
- 2,5: begin
- Top:=380;
- Bottom:=Top+85;
- end;
- end;
- case P of
- 0,1,2: cScreen:=1;
- else cScreen:=2;
- end;
- end;
- end;
- // spawn Sparkling Stars inside calculated coordinates
- for I:= 0 to 80 do
- begin
- Life:=RandomRange(8,16);
- Spawn(RandomRange(Left,Right), RandomRange(Top,Bottom), cScreen, Life, 16-Life, -1, PerfectLineTwinkle, P);
- end;
- end;
-end;
-
-end.
-
+// notes:
+unit UGraphicClasses;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses UTexture,SDL;
+
+const DelayBetweenFrames : Cardinal = 60;
+type
+
+ TParticleType=(GoldenNote, PerfectNote, NoteHitTwinkle, PerfectLineTwinkle, ColoredStar, Flare);
+
+ TColour3f = Record
+ r, g, b: Real;
+ end;
+
+ TParticle = Class
+ X, Y : Real; //Position
+ Screen : Integer;
+ W, H : Cardinal; //dimensions of particle
+ Col : array of TColour3f; // Colour(s) of particle
+ Scale : array of Real; // Scaling factors of particle layers
+ Frame : Byte; //act. Frame
+ Tex : Cardinal; //Tex num from Textur Manager
+ Live : Byte; //How many Cycles before Kill
+ RecIndex : Integer; //To which rectangle this particle belongs (only GoldenNote)
+ StarType : TParticleType; // GoldenNote | PerfectNote | NoteHitTwinkle | PerfectLineTwinkle
+ Alpha : Real; // used for fading...
+ mX, mY : Real; // movement-vector for PerfectLineTwinkle
+ SizeMod : Real; // experimental size modifier
+ SurviveSentenceChange : Boolean;
+
+ Constructor Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
+ Destructor Destroy(); override;
+ procedure Draw;
+ procedure LiveOn;
+ end;
+
+ RectanglePositions = Record
+ xTop, yTop, xBottom, yBottom : Real;
+ TotalStarCount : Integer;
+ CurrentStarCount : Integer;
+ Screen : Integer;
+ end;
+
+ PerfectNotePositions = Record
+ xPos, yPos : Real;
+ Screen : Integer;
+ end;
+
+ TEffectManager = Class
+ Particle : array of TParticle;
+ LastTime : Cardinal;
+ RecArray : Array of RectanglePositions;
+ TwinkleArray : Array[0..5] of Real; // store x-position of last twinkle for every player
+ PerfNoteArray : Array of PerfectNotePositions;
+
+ FlareTex: TTexture;
+
+ constructor Create;
+ destructor Destroy; override;
+ procedure Draw;
+ function Spawn(X, Y: Real;
+ Screen: Integer;
+ Live: Byte;
+ StartFrame: Integer;
+ RecArrayIndex: Integer; // this is only used with GoldenNotes
+ StarType: TParticleType;
+ Player: Cardinal // for PerfectLineTwinkle
+ ): Cardinal;
+ procedure SpawnRec();
+ procedure Kill(index: Cardinal);
+ procedure KillAll();
+ procedure SentenceChange();
+ procedure SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
+ procedure SavePerfectNotePos(Xtop, Ytop: Real);
+ procedure GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
+ procedure SpawnPerfectLineTwinkle();
+ end;
+
+var GoldenRec : TEffectManager;
+
+implementation
+
+uses sysutils,
+ OpenGl12,
+ UIni,
+ UMain,
+ UThemes,
+ USkins,
+ UGraphic,
+ UDrawTexture,
+ UCommon,
+ math;
+
+//TParticle
+Constructor TParticle.Create(cX,cY: Real; cScreen: Integer; cLive: Byte; cFrame : integer; cRecArrayIndex : Integer; cStarType : TParticleType; Player: Cardinal);
+begin
+ inherited Create;
+ // in this constructor we set all initial values for our particle
+ X := cX;
+ Y := cY;
+ Screen := cScreen;
+ Live := cLive;
+ Frame:= cFrame;
+ RecIndex := cRecArrayIndex;
+ StarType := cStarType;
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ SetLength(Scale,1);
+ Scale[0] := 1;
+ SurviveSentenceChange := False;
+ SizeMod := 1;
+ case cStarType of
+ GoldenNote:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := 20;
+ H := 20;
+ SetLength(Scale,4);
+ Scale[1]:=0.8;
+ Scale[2]:=0.4;
+ Scale[3]:=0.3;
+ SetLength(Col,4);
+ Col[0].r := 1;
+ Col[0].g := 0.7;
+ Col[0].b := 0.1;
+
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+
+ Col[2].r := 1;
+ Col[2].g := 1;
+ Col[2].b := 1;
+
+ Col[3].r := 1;
+ Col[3].g := 1;
+ Col[3].b := 1;
+ end;
+ PerfectNote:
+ begin
+ Tex := Tex_Note_Perfect_Star.TexNum;
+ W := 30;
+ H := 30;
+ SetLength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := 0.95;
+ end;
+ NoteHitTwinkle:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ Alpha := (Live/16); // linear fade-out
+ W := 15;
+ H := 15;
+ Setlength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := RandomRange(10*Live,100)/90; //0.9;
+ end;
+ PerfectLineTwinkle:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := RandomRange(10,20);
+ H := W;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ SurviveSentenceChange:=True;
+ // assign colours according to player given
+ SetLength(Scale,3);
+ Scale[1]:=0.3;
+ Scale[2]:=0.2;
+ SetLength(Col,3);
+ case Player of
+ 0: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
+ 1: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P2Light');
+ 2: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P3Light');
+ 3: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P4Light');
+ 4: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P5Light');
+ 5: LoadColor(Col[0].r,Col[0].g,Col[0].b,'P6Light');
+ else LoadColor(Col[0].r,Col[0].g,Col[0].b,'P1Light');
+ end;
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+ Col[2].r:=Col[0].r+0.5;
+ Col[2].g:=Col[0].g+0.5;
+ Col[2].b:=Col[0].b+0.5;
+ mX := RandomRange(-5,5);
+ mY := RandomRange(-5,5);
+ end;
+ ColoredStar:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := RandomRange(10,20);
+ H := W;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ SurviveSentenceChange:=True;
+ // assign colours according to player given
+ SetLength(Scale,1);
+ SetLength(Col,1);
+ Col[0].b := (Player and $ff)/255;
+ Col[0].g := ((Player shr 8) and $ff)/255;
+ Col[0].r := ((Player shr 16) and $ff)/255;
+ mX := 0;
+ mY := 0;
+ end;
+ Flare:
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ W := 7;
+ H := 7;
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ mX := RandomRange(-5,5);
+ mY := RandomRange(-5,5);
+ SetLength(Scale,4);
+ Scale[1]:=0.8;
+ Scale[2]:=0.4;
+ Scale[3]:=0.3;
+ SetLength(Col,4);
+ Col[0].r := 1;
+ Col[0].g := 0.7;
+ Col[0].b := 0.1;
+
+ Col[1].r := 1;
+ Col[1].g := 1;
+ Col[1].b := 0.4;
+
+ Col[2].r := 1;
+ Col[2].g := 1;
+ Col[2].b := 1;
+
+ Col[3].r := 1;
+ Col[3].g := 1;
+ Col[3].b := 1;
+
+ end;
+ else // just some random default values
+ begin
+ Tex := Tex_Note_Star.TexNum;
+ Alpha := 1;
+ W := 20;
+ H := 20;
+ SetLength(Col,1);
+ Col[0].r := 1;
+ Col[0].g := 1;
+ Col[0].b := 1;
+ end;
+ end;
+end;
+
+Destructor TParticle.Destroy();
+begin
+ SetLength(Scale,0);
+ SetLength(Col,0);
+ inherited;
+end;
+
+procedure TParticle.LiveOn;
+begin
+ //Live = 0 => Live forever <blindy> ?? but if this is 0 they would be killed in the Manager at Draw
+ if (Live > 0) then
+ Dec(Live);
+
+ // animate frames
+ Frame := ( Frame + 1 ) mod 16;
+
+ // make our particles do funny stuff (besides being animated)
+ // changes of any particle-values throughout its life are done here
+ case StarType of
+ GoldenNote:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ PerfectNote:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ NoteHitTwinkle:
+ begin
+ Alpha := (Live/10); // linear fade-out
+ end;
+ PerfectLineTwinkle:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ // move around
+ X := X + mX;
+ Y := Y + mY;
+ end;
+ ColoredStar:
+ begin
+ Alpha := (-cos((Frame+1)*2*pi/16)+1); // neat fade-in-and-out
+ end;
+ Flare:
+ begin
+ Alpha := (-cos((Frame+1)/16*1.7*pi+0.3*pi)+1); // neat fade-in-and-out
+ SizeMod := (-cos((Frame+1)*5*2*pi/16)*0.5+1.1);
+ // move around
+ X := X + mX;
+ Y := Y + mY;
+ mY:=mY+1.8;
+// mX:=mX/2;
+ end;
+ end;
+end;
+
+procedure TParticle.Draw;
+var L: Cardinal;
+begin
+ if ScreenAct = Screen then
+ // this draws (multiple) texture(s) of our particle
+ for L:=0 to High(Col) do
+ begin
+ glColor4f(Col[L].r, Col[L].g, Col[L].b, Alpha);
+
+ glBindTexture(GL_TEXTURE_2D, Tex);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ begin
+ glBegin(GL_QUADS);
+ glTexCoord2f((1/16) * Frame, 0); glVertex2f(X-W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame + (1/16), 0); glVertex2f(X-W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame + (1/16), 1); glVertex2f(X+W*Scale[L]*SizeMod, Y+H*Scale[L]*SizeMod);
+ glTexCoord2f((1/16) * Frame, 1); glVertex2f(X+W*Scale[L]*SizeMod, Y-H*Scale[L]*SizeMod);
+ glEnd;
+ end;
+ end;
+ glcolor4f(1,1,1,1);
+end;
+// end of TParticle
+
+// TEffectManager
+
+constructor TEffectManager.Create;
+var c: Cardinal;
+begin
+ inherited;
+ LastTime := SDL_GetTicks();
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0;
+ end;
+end;
+
+destructor TEffectManager.Destroy;
+begin
+ Killall;
+ inherited;
+end;
+
+
+procedure TEffectManager.Draw;
+var
+ I: Integer;
+ CurrentTime: Cardinal;
+//const
+// DelayBetweenFrames : Cardinal = 100;
+begin
+
+ CurrentTime := SDL_GetTicks();
+ //Manage particle life
+ if (CurrentTime - LastTime) > DelayBetweenFrames then
+ begin
+ LastTime := CurrentTime;
+ for I := 0 to high(Particle) do
+ Particle[I].LiveOn;
+ end;
+
+ I := 0;
+ //Kill dead particles
+ while (I <= High(Particle)) do
+ begin
+ if (Particle[I].Live <= 0) then
+ begin
+ kill(I);
+ end
+ else
+ begin
+ inc(I);
+ end;
+ end;
+
+ //Draw
+ for I := 0 to high(Particle) do
+ begin
+ Particle[I].Draw;
+ end;
+end;
+
+// this method creates just one particle
+function TEffectManager.Spawn(X, Y: Real; Screen: Integer; Live: Byte; StartFrame : Integer; RecArrayIndex : Integer; StarType : TParticleType; Player: Cardinal): Cardinal;
+begin
+ Result := Length(Particle);
+ SetLength(Particle, (Result + 1));
+ Particle[Result] := TParticle.Create(X, Y, Screen, Live, StartFrame, RecArrayIndex, StarType, Player);
+end;
+
+// manage Sparkling of GoldenNote Bars
+procedure TEffectManager.SpawnRec();
+Var
+ Xkatze, Ykatze : Real;
+ RandomFrame : Integer;
+ P : Integer; // P as seen on TV as Positionman
+begin
+//Spawn a random amount of stars within the given coordinates
+//RandomRange(0,14) <- this one starts at a random frame, 16 is our last frame - would be senseless to start a particle with 16, cause it would be dead at the next frame
+for P:= 0 to high(RecArray) do
+ begin
+ while (RecArray[P].TotalStarCount > RecArray[P].CurrentStarCount) do
+ begin
+ Xkatze := RandomRange(Ceil(RecArray[P].xTop), Ceil(RecArray[P].xBottom));
+ Ykatze := RandomRange(Ceil(RecArray[P].yTop), Ceil(RecArray[P].yBottom));
+ RandomFrame := RandomRange(0,14);
+ // Spawn a GoldenNote Particle
+ Spawn(Xkatze, Ykatze, RecArray[P].Screen, 16 - RandomFrame, RandomFrame, P, GoldenNote, 0);
+ inc(RecArray[P].CurrentStarCount);
+ end;
+ end;
+ draw;
+end;
+
+// kill one particle (with given index in our particle array)
+procedure TEffectManager.Kill(Index: Cardinal);
+var
+ LastParticleIndex : Integer;
+begin
+// delete particle indexed by Index,
+// overwrite it's place in our particle-array with the particle stored at the last array index,
+// shorten array
+ LastParticleIndex := high(Particle);
+ if not(LastParticleIndex = -1) then // is there still a particle to delete?
+ begin
+ if not(Particle[Index].RecIndex = -1) then // if it is a GoldenNote particle...
+ dec(RecArray[Particle[Index].RecIndex].CurrentStarCount); // take care of its associated GoldenRec
+ // now get rid of that particle
+ Particle[Index].Destroy;
+ Particle[Index] := Particle[LastParticleIndex];
+ SetLength(Particle, LastParticleIndex);
+ end;
+end;
+
+// clean up all particles and management structures
+procedure TEffectManager.KillAll();
+var c: Cardinal;
+begin
+//It's the kill all kennies rotuine
+ while Length(Particle) > 0 do // kill all existing particles
+ Kill(0);
+ SetLength(RecArray,0); // remove GoldenRec positions
+ SetLength(PerfNoteArray,0); // remove PerfectNote positions
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0; // reset GoldenNoteHit memory
+ end;
+end;
+
+procedure TEffectManager.SentenceChange();
+var c: Cardinal;
+begin
+ c:=0;
+ while c <= High(Particle) do
+ begin
+ if Particle[c].SurviveSentenceChange then
+ inc(c)
+ else
+ Kill(c);
+ end;
+ SetLength(RecArray,0); // remove GoldenRec positions
+ SetLength(PerfNoteArray,0); // remove PerfectNote positions
+ for c:=0 to 5 do
+ begin
+ TwinkleArray[c] := 0; // reset GoldenNoteHit memory
+ end;
+end;
+
+procedure TeffectManager.GoldenNoteTwinkle(Top,Bottom,Right: Real; Player: Integer);
+//Twinkle stars while golden note hit
+// this is called from UDraw.pas, SingDrawPlayerCzesc
+var
+ C, P, XKatze, YKatze, LKatze: Integer;
+ H: Real;
+begin
+ // make sure we spawn only one time at one position
+ if (TwinkleArray[Player] < Right) then
+ For P := 0 to high(RecArray) do // Are we inside a GoldenNoteRectangle?
+ begin
+ H := (Top+Bottom)/2; // helper...
+ with RecArray[P] do
+ if ((xBottom >= Right) and (xTop <= Right) and
+ (yTop <= H) and (yBottom >= H))
+ and (Screen = ScreenAct) then
+ begin
+ TwinkleArray[Player] := Right; // remember twinkle position for this player
+ for C := 1 to 10 do
+ begin
+ Ykatze := RandomRange(ceil(Top) , ceil(Bottom));
+ XKatze := RandomRange(-7,3);
+ LKatze := RandomRange(7,13);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Top)-6 , ceil(Top));
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(4,7);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Bottom), ceil(Bottom)+6);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(4,7);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Top)-10 , ceil(Top)-6);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(1,4);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+ for C := 1 to 3 do
+ begin
+ Ykatze := RandomRange(ceil(Bottom)+6 , ceil(Bottom)+10);
+ XKatze := RandomRange(-5,1);
+ LKatze := RandomRange(1,4);
+ Spawn(Ceil(Right)+XKatze, YKatze, ScreenAct, LKatze, 0, -1, NoteHitTwinkle, 0);
+ end;
+
+ exit; // found a matching GoldenRec, did spawning stuff... done
+ end;
+ end;
+end;
+
+procedure TEffectManager.SaveGoldenStarsRec(Xtop, Ytop, Xbottom, Ybottom: Real);
+var
+ P : Integer; // P like used in Positions
+ NewIndex : Integer;
+begin
+ For P := 0 to high(RecArray) do // Do we already have that "new" position?
+ begin
+ if (ceil(RecArray[P].xTop) = ceil(Xtop)) and
+ (ceil(RecArray[P].yTop) = ceil(Ytop)) and
+ (ScreenAct = RecArray[p].Screen) then
+ exit; // it's already in the array, so we don't have to create a new one
+ end;
+
+ // we got a new position, add the new positions to our array
+ NewIndex := Length(RecArray);
+ SetLength(RecArray, NewIndex + 1);
+ RecArray[NewIndex].xTop := Xtop;
+ RecArray[NewIndex].yTop := Ytop;
+ RecArray[NewIndex].xBottom := Xbottom;
+ RecArray[NewIndex].yBottom := Ybottom;
+ RecArray[NewIndex].TotalStarCount := ceil(Xbottom - Xtop) div 12 + 3;
+ RecArray[NewIndex].CurrentStarCount := 0;
+ RecArray[NewIndex].Screen := ScreenAct;
+end;
+
+procedure TEffectManager.SavePerfectNotePos(Xtop, Ytop: Real);
+var
+ P : Integer; // P like used in Positions
+ NewIndex : Integer;
+ RandomFrame : Integer;
+ Xkatze, Ykatze : Integer;
+begin
+ For P := 0 to high(PerfNoteArray) do // Do we already have that "new" position?
+ begin
+ with PerfNoteArray[P] do
+ if (ceil(xPos) = ceil(Xtop)) and (ceil(yPos) = ceil(Ytop)) and
+ (Screen = ScreenAct) then
+ exit; // it's already in the array, so we don't have to create a new one
+ end; //for
+
+ // we got a new position, add the new positions to our array
+ NewIndex := Length(PerfNoteArray);
+ SetLength(PerfNoteArray, NewIndex + 1);
+ PerfNoteArray[NewIndex].xPos := Xtop;
+ PerfNoteArray[NewIndex].yPos := Ytop;
+ PerfNoteArray[NewIndex].Screen := ScreenAct;
+
+ for P:= 0 to 2 do
+ begin
+ Xkatze := RandomRange(ceil(Xtop) - 5 , ceil(Xtop) + 10);
+ Ykatze := RandomRange(ceil(Ytop) - 5 , ceil(Ytop) + 10);
+ RandomFrame := RandomRange(0,14);
+ Spawn(Xkatze, Ykatze, ScreenAct, 16 - RandomFrame, RandomFrame, -1, PerfectNote, 0);
+ end; //for
+
+end;
+
+procedure TEffectManager.SpawnPerfectLineTwinkle();
+var
+ P,I,Life: Cardinal;
+ Left, Right, Top, Bottom: Cardinal;
+ cScreen: Integer;
+begin
+// calculation of coordinates done with hardcoded values like in UDraw.pas
+// might need to be adjusted if drawing of SingScreen is modified
+// coordinates may still be a bit weird and need adjustment
+ if Ini.SingWindow = 0 then begin
+ Left := 130;
+ end else begin
+ Left := 30;
+ end;
+ Right := 770;
+ // spawn effect for every player with a perfect line
+ for P:=0 to PlayersPlay-1 do
+ if Player[P].LastSentencePerfect then
+ begin
+ // calculate area where notes of this player are drawn
+ case PlayersPlay of
+ 1: begin
+ Bottom:=Skin_P2_NotesB+10;
+ Top:=Bottom-105;
+ cScreen:=1;
+ end;
+ 2,4: begin
+ case P of
+ 0,2: begin
+ Bottom:=Skin_P1_NotesB+10;
+ Top:=Bottom-105;
+ end;
+ else begin
+ Bottom:=Skin_P2_NotesB+10;
+ Top:=Bottom-105;
+ end;
+ end;
+ case P of
+ 0,1: cScreen:=1;
+ else cScreen:=2;
+ end;
+ end;
+ 3,6: begin
+ case P of
+ 0,3: begin
+ Top:=130;
+ Bottom:=Top+85;
+ end;
+ 1,4: begin
+ Top:=255;
+ Bottom:=Top+85;
+ end;
+ 2,5: begin
+ Top:=380;
+ Bottom:=Top+85;
+ end;
+ end;
+ case P of
+ 0,1,2: cScreen:=1;
+ else cScreen:=2;
+ end;
+ end;
+ end;
+ // spawn Sparkling Stars inside calculated coordinates
+ for I:= 0 to 80 do
+ begin
+ Life:=RandomRange(8,16);
+ Spawn(RandomRange(Left,Right), RandomRange(Top,Bottom), cScreen, Life, 16-Life, -1, PerfectLineTwinkle, P);
+ end;
+ end;
+end;
+
+end.
+