{* UltraStar Deluxe - Karaoke Game
*
* UltraStar Deluxe is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*}
unit UScreenCredits;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses
SysUtils,
SDL,
SDL_Image,
gl,
UMenu,
UDisplay,
UTexture,
UMusic,
UFiles,
UThemes,
UPath,
UGraphicClasses;
{ beat detection constants and types }
const
SubChannelCount = 32;
HistoryLength = 44;
SamplesPerChannel = (FFTSize div 2) div SubChannelCount;
BeatEnergyModifier = 80; // modifies detected energy
// higher values equal a more sensitive detection
type
TEnergyHistory = array [0..HistoryLength-1] of single;
TSubchannelHistory = array [0..SubChannelCount-1] of TEnergyHistory;
type
TCreditsStages=(InitialDelay, Intro, MainPart, Outro);
TScreenCredits = class(TMenu)
private
CreditsPath: IPath;
Credits_X: real;
Credits_Time: cardinal;
CTime_hold: cardinal;
credits_bg_tex: TTexture;
credits_bg_ovl: TTexture;
//credits_bg_logo: TTexture;
credits_names: array of TTexture;
intro_layer01: TTexture;
intro_layer02: TTexture;
intro_layer03: TTexture;
intro_layer04: TTexture;
intro_layer05: TTexture;
intro_layer06: TTexture;
intro_layer07: TTexture;
intro_layer08: TTexture;
intro_layer09: TTexture;
outro_bg: TTexture;
outro_esc: TTexture;
outro_exd: TTexture;
CurrentScrollStart, CurrentScrollEnd: integer;
CRDTS_Stage: TCreditsStages;
{ beat detection }
SubChannelHistory: TSubchannelHistory;
{ mouse movement easter eggs: }
MouseMoved: boolean;
MouseX, MouseY: double;
{ saves last x and y angle for easter egg }
LogoAngleX, LogoAngleY: single;
procedure LoadNameTextures;
{ draw different stages }
procedure DrawInitialDelay;
{ Intro }
procedure DrawIntro;
procedure DrawLayeredLogo(Separation, Scale, AngleX, AngleY, AngleZ: single);
{ Main }
procedure DrawMain;
procedure DrawMainBG;
procedure DrawFunkyText;
procedure DrawMainFG;
procedure DrawNames;
procedure DoLogoBling;
{ Outro }
procedure DrawOutro;
{ beat detection }
procedure DetectBeat;
protected
{ beat detection stuff
protected cause we need this information for "on beat
effect"}
LastBeatTime: cardinal;
BeatDetected: boolean;
CTime: cardinal;
public
Fadeout: boolean;
constructor Create; override;
function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; override;
procedure OnShow; override;
procedure OnHide; override;
function Draw: boolean; override;
end;
const
Funky_Text: string =
'Grandma Deluxe has arrived! Thanks to Corvus5 for the massive work on UltraStar, Wome for the nice tune you are hearing, '+
'all the people who put massive effort and work in new songs (do not forget UltraStar w/o songs would be nothing), ppl from '+
'irc helping us - eBandit and Gabari, scene ppl who really helped instead of compiling and running away. Greetings to DennisTheMenace for betatesting, '+
'Demoscene.tv, pouet.net, KakiArts, Sourceforge,..';
{ texture names (loaded from gameshared/resources/credits}
CRDTS_BG_FILE = 'credits_v5_bg.png';
CRDTS_OVL_FILE = 'credits_v5_overlay.png';
INTRO_L01_FILE = 'intro-l-01.png';
INTRO_L02_FILE = 'intro-l-02.png';
INTRO_L03_FILE = 'intro-l-03.png';
INTRO_L04_FILE = 'intro-l-04.png';
INTRO_L05_FILE = 'intro-l-05.png';
INTRO_L06_FILE = 'intro-l-06.png';
INTRO_L07_FILE = 'intro-l-07.png';
INTRO_L08_FILE = 'intro-l-08.png';
INTRO_L09_FILE = 'intro-l-09.png';
OUTRO_BG_FILE = 'outro-bg.png';
OUTRO_ESC_FILE = 'outro-esc.png';
OUTRO_EXD_FILE = 'outro-exit-dark.png';
{ some timings }
Delay_Before_Start = 20;
Intro_Flare_Start = 60;
Intro_Zoom_End = 149;
Intro_Stand_End = 155;
Intro_Separation_End = 170;
Intro_FadeToWhite_Start = 261;
Intro_Zoomout_Start = 271;
Main_Start = 271;
Main_OnBeatTwinkle_Start = 280;
Main_Names_Start = 359;
Main_Names_End = 2833;
Main_FadeOut_Start = 3096;
Tune_End = 3366;
{ cosntants for developer names }
type
TFadeEffect = procedure (const Tex: TTexture; Progress: double);
TCRTZ_Developer = record
Name: string; // developer name for texture loading (names_"devel".png)
Twinkle: boolean; // should there be twinkles on show
FadeIn: TFadeEffect; // fade in effect
Draw: TFadeEffect; // effect during draw
FadeOut: TFadeEffect; // fade out effect
end;
{ effects are called with blending, texture and matrix prepared }
procedure Effect_Draw (const Tex: TTexture; Progress: double);
procedure Effect_OnBeatJitter (const Tex: TTexture; Progress: double);
procedure Effect_Rotate_Left_Top (const Tex: TTexture; Progress: double);
procedure Effect_Rotate_Right_Bot (const Tex: TTexture; Progress: double);
procedure Effect_ZoomIn_Rotate (const Tex: TTexture; Progress: double);
procedure Effect_ZoomOut_Shift (const Tex: TTexture; Progress: double);
procedure Effect_Shift_Left (const Tex: TTexture; Progress: double);
procedure Effect_Shift_Right_Top (const Tex: TTexture; Progress: double);
procedure Effect_Flip_Bot (const Tex: TTexture; Progress: double);
procedure Effect_Flip_Right_Top (const Tex: TTexture; Progress: double);
procedure Effect_Flip_Right (const Tex: TTexture; Progress: double);
procedure Effect_Flip_Right_Bot (const Tex: TTexture; Progress: double);
procedure Effect_Rotate_Right_Top (const Tex: TTexture; Progress: double);
procedure Effect_Shift_Weird (const Tex: TTexture; Progress: double);
procedure Effect_Shift_Right_Bot (const Tex: TTexture; Progress: double);
procedure Effect_Rotate_Right_Top2(const Tex: TTexture; Progress: double);
procedure Effect_Flip_Left_Bot (const Tex: TTexture; Progress: double);
procedure Effect_Flip_Right_Top2 (const Tex: TTexture; Progress: double);
procedure Effect_Twinkle_Down (const Tex: TTexture; Progress: double);
const
Developers: array[0..10] of TCRTZ_Developer = (
(Name: 'alexanders'; Twinkle: true; FadeIn: Effect_Rotate_Left_Top; Draw: Effect_OnBeatJitter; FadeOut: Effect_Rotate_Right_Bot),
(Name: 'blindy'; Twinkle: true; FadeIn: Effect_ZoomIn_Rotate; Draw: Effect_OnBeatJitter; FadeOut: Effect_ZoomOut_Shift),
(Name: 'brunzel'; Twinkle: true; FadeIn: Effect_Shift_Left; Draw: Effect_Draw; FadeOut: Effect_Shift_Right_Top),
(Name: 'canni'; Twinkle: true; FadeIn: Effect_Flip_Bot; Draw: Effect_Draw; FadeOut: Effect_Flip_Right_Top),
(Name: 'hennymcc'; Twinkle: true; FadeIn: Effect_Flip_Right; Draw: Effect_OnBeatJitter; FadeOut: Effect_Flip_Right_Bot),
(Name: 'jaybinks'; Twinkle: true; FadeIn: Effect_Rotate_Right_Top; Draw: Effect_OnBeatJitter; FadeOut: Effect_Shift_Weird),
(Name: 'krueger'; Twinkle: true; FadeIn: Effect_Shift_Right_Bot; Draw: Effect_OnBeatJitter; FadeOut: Effect_Rotate_Right_Top2),
(Name: 'mezzox'; Twinkle: true; FadeIn: Effect_Flip_Left_Bot; Draw: Effect_OnBeatJitter; FadeOut: Effect_Flip_Right_Top),
(Name: 'mischi'; Twinkle: true; FadeIn: Effect_Shift_Weird; Draw: Effect_OnBeatJitter; FadeOut: Effect_Flip_Bot),
(Name: 'mog'; Twinkle: false; FadeIn: Effect_Twinkle_Down; Draw: Effect_OnBeatJitter; FadeOut: Effect_ZoomIn_Rotate),
(Name: 'whiteshark'; Twinkle: true; FadeIn: Effect_Rotate_Right_Top2; Draw: Effect_OnBeatJitter; FadeOut: Effect_Shift_Left)
);
{ name specific times }
TimePerName = (Main_Names_End - Main_Names_Start) div Length(Developers);
NameFadeTime = 12; // duration of fade in/out in 1/100 secs
NameWaitTime = 5; // delay between fade out and fade in of the next devel in 1/100 secs
NameTwinkleTime = 2; // duration of star effects in 1/100 secs
BeatJitterTime = 3; // duration of on beat jitter effect
{ position at which the names show up
note: due to use of translate this is the center
of the names not the upper left corner as usual }
NameX = 223;
NameY = 329;
NameW = 326;
NameH = 258;
implementation
uses
Math,
ULog,
UGraphic,
UMain,
UIni,
USongs,
Textgl,
ULanguage,
UCommon,
UPathUtils;
function TScreenCredits.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
begin
Result := true;
if (PressedDown) then
begin // Key Down
case PressedKey of
SDLK_ESCAPE,
SDLK_BACKSPACE,
SDLK_RETURN :
begin
FadeTo(@ScreenMain);
AudioPlayback.PlaySound(SoundLib.Back);
end;
{
SDLK_SPACE:
begin
setlength(CTime_hold,length(CTime_hold)+1);
CTime_hold[high(CTime_hold)]:=CTime;
end;
}
end; // esac
end; // fi
end;
function TScreenCredits.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean;
begin
Result := inherited ParseMouse(MouseButton, BtnDown, X, Y);
{ calculate mouse coordinates from -1 to 1
relative to screen center }
MouseX := (X - (ScreenW / Screens) / 2) / ((ScreenW / Screens) / 2);
MouseY := (Y - ScreenH / 2) / (ScreenH / 2);
MouseMoved := true;
end;
procedure TScreenCredits.LoadNameTextures;
var I: integer;
begin
SetLength(credits_names, Length(Developers));
for I := 0 to High(Developers) do
begin
credits_names[I] := Texture.LoadTexture(CreditsPath.Append('names_' + Developers[I].Name + '.png'), TEXTURE_TYPE_TRANSPARENT, 0);
end;
end;
constructor TScreenCredits.Create;
begin
inherited Create;
CreditsPath := ResourcesPath.Append('credits', pdAppend);
credits_bg_tex := Texture.LoadTexture(CreditsPath.Append(CRDTS_BG_FILE), TEXTURE_TYPE_PLAIN, 0);
credits_bg_ovl := Texture.LoadTexture(CreditsPath.Append(CRDTS_OVL_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
LoadNameTextures;
intro_layer01 := Texture.LoadTexture(CreditsPath.Append(INTRO_L01_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer02 := Texture.LoadTexture(CreditsPath.Append(INTRO_L02_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer03 := Texture.LoadTexture(CreditsPath.Append(INTRO_L03_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer04 := Texture.LoadTexture(CreditsPath.Append(INTRO_L04_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer05 := Texture.LoadTexture(CreditsPath.Append(INTRO_L05_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer06 := Texture.LoadTexture(CreditsPath.Append(INTRO_L06_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer07 := Texture.LoadTexture(CreditsPath.Append(INTRO_L07_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer08 := Texture.LoadTexture(CreditsPath.Append(INTRO_L08_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
intro_layer09 := Texture.LoadTexture(CreditsPath.Append(INTRO_L09_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
outro_bg := Texture.LoadTexture(CreditsPath.Append(OUTRO_BG_FILE), TEXTURE_TYPE_PLAIN, 0);
outro_esc := Texture.LoadTexture(CreditsPath.Append(OUTRO_ESC_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
outro_exd := Texture.LoadTexture(CreditsPath.Append(OUTRO_EXD_FILE), TEXTURE_TYPE_TRANSPARENT, 0);
CRDTS_Stage:=InitialDelay;
end;
procedure TScreenCredits.OnShow;
begin
inherited;
{ pause background music }
SoundLib.PauseBgMusic;
CRDTS_Stage := InitialDelay;
CTime := 0;
Credits_X := 580;
{ open credits tune, we play it after initial delay }
AudioPlayback.Open(soundpath.Append('wome-credits-tune.mp3')); // thank you wetue
{ reset twinkling stars }
GoldenRec.KillAll;
{ reset mouse coords }
MouseMoved := false;
MouseX := 0;
MouseY := 0;
{ hide cursor }
Display.SetCursor;
end;
procedure TScreenCredits.OnHide;
begin
AudioPlayback.Stop;
{ show cursor }
Display.SetCursor;
SoundLib.StartBgMusic;
end;
function TScreenCredits.Draw: boolean;
var
T: cardinal;
begin
Result := true;
// reset beat detection
BeatDetected := false;
T := SDL_GetTicks() div 33;
if T <> Credits_Time then
begin
Credits_Time := T;
inc(CTime);
inc(CTime_hold);
Credits_X := Credits_X-2;
if (CRDTS_Stage = InitialDelay) and (CTime >= Delay_Before_Start) then
begin
CRDTS_Stage := Intro;
CTime := 0;
AudioPlayback.Play;
end
else if (CRDTS_Stage = Intro) and (CTime >= Main_Start) then
begin
CRDTS_Stage := MainPart;
end
else if (CRDTS_Stage = MainPart) and (CTime >= Tune_End) then
begin
CRDTS_Stage := Outro;
end;
// dis does teh muiwk y0r to be translated :-)
DetectBeat;
end;
case CRDTS_Stage of
InitialDelay: DrawInitialDelay;
Intro: DrawIntro;
MainPart: DrawMain;
Outro: DrawOutro;
end;
// make the stars shine
GoldenRec.Draw;
end;
procedure TScreenCredits.DrawInitialDelay;
begin
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;
procedure TScreenCredits.DrawIntro;
var
Separation, Scale,
AngleX, AngleY, AngleZ: single;
FlareX, FlareY: single;
I: integer;
begin
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
{ rotate logo anti clockwise and make it grow }
if (CTime >= Intro_Separation_End) then
begin
Separation := 1;
Scale := 1 + sqr(CTime - Intro_Separation_End) / (32 * (Main_Start - Intro_Separation_End));
AngleX := 0;
AngleY := 0;
AngleZ := 20 * sqr(CTime - Intro_Separation_End) / sqr((Main_Start - Intro_Separation_End) / 2);
end
{ separate layers }
else if (CTime >= Intro_Stand_End) then
begin
Separation := 0.5 + 0.5 * (CTime - Intro_Stand_End) / (Intro_Separation_End - Intro_Stand_End);
Scale := 1;
AngleX := 0;
AngleY := 0;
AngleZ := 0;
end
{ stand still }
else if (CTime >= Intro_Zoom_End) then
begin
Separation := 0.5;
Scale := 1;
AngleX := 0;
AngleY := 0;
AngleZ := 0;
end
{ rotate left }
else
begin
Separation := 0.5 + 0.5 * (Intro_Zoom_End - CTime) / (Intro_Zoom_End);
Scale := 1;
AngleX := 10 * (Intro_Zoom_End - CTime) / (Intro_Zoom_End);
AngleY := 20 * (Intro_Zoom_End - CTime) / (Intro_Zoom_End);
AngleZ := 0;
end;
{ the user moved the mouse, overwrite X and Y angle with
according to mouse position }
if (MouseMoved) then
begin
// calculate destination angle
AngleX := 30 * MouseY;
AngleY := 30 * MouseX;
{ move angle towards destination }
if not SameValue(LogoAngleX, AngleX, 0.001) then
AngleX := LogoAngleX + 0.05 * (AngleX - LogoAngleX);
if not SameValue(LogoAngleY, AngleY, 0.001) then
AngleY := LogoAngleY + 0.05 * (AngleY - LogoAngleY);
end;
// save last angle
LogoAngleX := AngleX;
LogoAngleY := AngleY;
DrawLayeredLogo(Separation, Scale, AngleX, AngleY, AngleZ);
{ do some sparkling effects }
if (CTime < Intro_Zoom_End) and (CTime > Intro_Flare_Start) then
begin
for I := 1 to 3 do
begin
FlareX := 410 + Floor((CTime - Intro_Flare_Start) / (Intro_Zoom_End - Intro_Flare_Start) * (536 - 410)) + RandomRange(-5, 5);
FlareY := Floor((Intro_Zoom_End - CTime) / 22) + RandomRange(285, 301);
GoldenRec.Spawn(FlareX, FlareY, 1, 16, 0, -1, Flare, 0);
end;
end;
{ fade to white at end }
if Ctime > Intro_FadeToWhite_Start then
begin
glColor4f(1, 1, 1, sqr(CTime - Intro_FadeToWhite_Start) * (CTime - Intro_FadeToWhite_Start) / sqr(Main_Start - Intro_FadeToWhite_Start));
glEnable(GL_BLEND);
glBegin(GL_QUADS);
glVertex2f( 0, 0);
glVertex2f( 0, 600);
glVertex2f(800, 600);
glVertex2f(800, 0);
glEnd;
glDisable(GL_BLEND);
end;
end;
procedure Start3D;
begin
glMatrixMode(GL_PROJECTION);
glPushMatrix;
glLoadIdentity;
glFrustum(-0.3 * 4 / 3, 0.3 * 4 / 3, -0.3, 0.3, 1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
end;
procedure End3D;
begin
glMatrixMode(GL_PROJECTION);
glPopMatrix;
glMatrixMode(GL_MODELVIEW);
end;
procedure TScreenCredits.DrawLayeredLogo(Separation, Scale, AngleX, AngleY, AngleZ: single);
var
TotalAngle: single;
begin
Start3D;
glPushMatrix;
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTranslatef(0, 0, -5 + 0.5 * Separation);
TotalAngle := Abs(AngleX) + Abs(AngleY) + Abs(AngleZ);
if not isZero(TotalAngle) then
glRotatef(TotalAngle, AngleX / TotalAngle, AngleY / TotalAngle, AngleZ / TotalAngle);
glScalef(Scale, Scale, 1);
glScalef(4/3, -1, 1);
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, intro_layer01.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.4 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, -0.4 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, -0.4 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, -0.4 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer02.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.3 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, -0.3 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, -0.3 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, -0.3 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer03.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.2 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, -0.2 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, -0.2 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, -0.2 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer04.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, -0.1 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, -0.1 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, -0.1 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, -0.1 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer05.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, 0 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, 0 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, 0 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, 0 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer06.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, 0.1 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, 0.1 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, 0.1 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, 0.1 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer07.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, 0.2 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, 0.2 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, 0.2 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, 0.2 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer08.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, 0.3 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, 0.3 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, 0.3 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, 0.3 * Separation);
glEnd;
glBindTexture(GL_TEXTURE_2D, intro_layer09.TexNum);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex3f(-1, -1, 0.22 * Separation);
glTexCoord2f(0, 1); glVertex3f(-1, 1, 0.22 * Separation);
glTexCoord2f(1, 1); glVertex3f( 1, 1, 0.22 * Separation);
glTexCoord2f(1, 0); glVertex3f( 1, -1, 0.22 * Separation);
glEnd;
glDisable(Gl_Texture_2D);
glDisable(GL_BLEND);
glPopMatrix;
End3D;
end;
procedure TScreenCredits.DrawMain;
begin
DrawMainBG;
DrawFunkyText;
DrawNames;
DrawMainFG;
DoLogoBling;
// fade out at end of main part
if (Ctime > Main_FadeOut_Start) then
begin
glColor4f(0, 0, 0, (CTime - Main_FadeOut_Start) / (Tune_End - Main_FadeOut_Start));
glEnable(GL_BLEND);
glBegin(GL_QUADS);
glVertex2f( 0, 0);
glVertex2f( 0, 600);
glVertex2f(800, 600);
glVertex2f(800, 0);
glEnd;
glDisable(GL_BLEND);
end;
end;
procedure TScreenCredits.DrawMainBG;
begin
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, credits_bg_tex.TexNum);
glBegin(Gl_Quads);
glTexCoord2f( 0, 0); glVertex2f( 0, 0);
glTexCoord2f( 0, 600/1024); glVertex2f( 0, RenderH);
glTexCoord2f(800/1024, 600/1024); glVertex2f(RenderW, RenderH);
glTexCoord2f(800/1024, 0); glVertex2f(RenderW, 0);
glEnd;
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
end;
procedure TScreenCredits.DrawFunkyText;
var
S: integer;
X, Y, A: real;
visibleText: string;
begin
SetFontSize(30);
// init ScrollingText
if (CTime = Main_Start) then
begin
// set position of text
Credits_X := 600;
CurrentScrollStart := 1;
CurrentScrollEnd := 1;
end;
if (CTime > Main_Start) and
(CurrentScrollStart < length(Funky_Text)) then
begin
X := 0;
visibleText := Copy(Funky_Text, CurrentScrollStart, CurrentScrollEnd);
for S := 1 to length(visibleText) do
begin
Y := abs(sin((Credits_X + X) * 0.93 { * (((Credits_X + X)) / 1200) } / 100 * pi));
SetFontPos(Credits_X + X, 538 - Y * (Credits_X + X) * (Credits_X + X) * (Credits_X + X) / 1000000);
if (Credits_X + X > 32) then
A := 17
else if (Credits_X + X >= 15) then
A := Credits_X + X - 15
else
A := 0;
glColor4f(230 / 255 - 40 / 255 + Y * (Credits_X + X)/ 900,
200 / 255 - 30 / 255 + Y * (Credits_X + X)/ 1000,
155 / 255 - 20 / 255 + Y * (Credits_X + X)/ 1100,
A / 17);
glPrint(visibleText[S]);
X := X + glTextWidth(visibleText[S]);
end;
if (Credits_X < 0) and (CurrentScrollStart < length(Funky_Text)) then
begin
Credits_X := Credits_X + glTextWidth(Funky_Text[CurrentScrollStart]);
inc(CurrentScrollStart);
end;
visibleText := Copy(Funky_Text, CurrentScrollStart, CurrentScrollEnd);
if (Credits_X + glTextWidth(visibleText) < 600) and
(CurrentScrollEnd < length(Funky_Text)) then
begin
inc(CurrentScrollEnd);
end;
end;
{
// timing hack
X:=5;
SetFontStyle(2);
SetFontItalic(false);
SetFontSize(27);
glColor4f(1, 1, 1, 1);
for S := 0 to high(CTime_hold) do
begin
visibleText := inttostr(CTime_hold[S]);
SetFontPos (500, X);
glPrint(visibleText[0]);
X := X + 20;
end;
}
end;
procedure TScreenCredits.DrawNames;
var
Dev: integer;
Ticks: integer;
DevTicks: integer;
TwinkleW, TwinkleH: integer;
begin
Ticks := (CTime - Main_Names_Start);
Dev := Ticks div TimePerName;
DevTicks := Ticks mod TimePerName;
{// debug stuff
SetFontPos(20, 20);
glPrint('Ticks: ' + IntToStr(Ticks));
SetFontPos(20, 45);
glPrint('Dev: ' + IntToStr(Dev));
SetFontPos(20, 70);
glPrint('DevTicks: ' + IntToStr(DevTicks)); //}
if (Ticks >= 0) and (Dev <= High(Developers)) then
begin
{ spawn twinkling stars }
if (Developers[Dev].Twinkle) and (DevTicks >= NameFadeTime) and (DevTicks <= NameFadeTime + NameTwinkleTime) then
begin
TwinkleW := Round(NameW * 0.6);
TwinkleH := Round(NameH * 0.6);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 5);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 5);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-TwinkleW, TwinkleW), NameY + RandomRange(-TwinkleH, TwinkleH), 1, 16, 0, -1, PerfectLineTwinkle, 5);
end;
{ prepare drawing }
glPushMatrix;
glTranslatef(NameX, NameY, 0);
glBindTexture(GL_TEXTURE_2D, credits_names[Dev].TexNum);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
// calculate progress and call effect
if (DevTicks <= NameFadeTime) then
Developers[Dev].FadeIn(credits_names[Dev], DevTicks / NameFadeTime)
else if (DevTicks >= TimePerName - NameFadeTime - NameWaitTime) then
begin
if (DevTicks < TimePerName - NameWaitTime) then
Developers[Dev].FadeOut(credits_names[Dev], ((TimePerName - NameWaitTime) - DevTicks) / NameFadeTime);
end
else
Developers[Dev].Draw(credits_names[Dev], (DevTicks - NameFadeTime) / (TimePerName - NameFadeTime * 2 - NameWaitTime));
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glPopMatrix;
end;
end;
procedure TScreenCredits.DrawMainFG;
begin
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, credits_bg_ovl.TexNum);
glBegin(gl_Quads);
glTexCoord2f( 0, 0); glVertex2f(800-393, 0);
glTexCoord2f( 0, 600/1024); glVertex2f(800-393, 600);
glTexCoord2f(393/512, 600/1024); glVertex2f(800, 600);
glTexCoord2f(393/512, 0); glVertex2f(800, 0);
glEnd;
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
end;
procedure TScreenCredits.DoLogoBling;
const
myLogoCoords: array[0..27,0..1] of cardinal = (
( 39,32),( 84,32),(100,16),(125,24),
(154,31),(156,58),(168,32),(203,36),
(258,34),(251,50),(274,93),(294,84),
(232,54),(278,62),(319,34),(336,92),
(347,23),(374,32),(377,58),(361,83),
(385,91),(405,91),(429,35),(423,51),
(450,32),(485,34),(444,91),(486,93)
);
var
Coords: integer;
StartFrame: integer;
begin
if (CTime > Main_OnBeatTwinkle_Start ) and
(CTime < Main_FadeOut_Start) then
begin
{ spawn stars only in frames where a beat was detected }
if BeatDetected then
begin
StartFrame := RandomRange(6, 16);
Coords := RandomRange(0, 27);
GoldenRec.Spawn(myLogoCoords[Coords,0], myLogoCoords[Coords,1], 16-StartFrame, StartFrame, 0, -1, PerfectNote, 0);
end;
end;
end;
procedure TScreenCredits.DrawOutro;
begin
if CTime = Tune_End then
begin
CTime_hold := 0;
AudioPlayback.Stop;
AudioPlayback.Open(SoundPath.Append('credits-outro-tune.mp3'));
AudioPlayback.SetVolume(0.2);
AudioPlayback.SetLoop(true);
AudioPlayback.Play;
end;
if CTime_hold > 231 then
begin
AudioPlayback.Play;
Ctime_hold := 0;
end;
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
// do something useful
// outro background
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, outro_bg.TexNum);
glBegin(gl_quads);
glTexCoord2f( 0, 0); glVertex2f( 0, 0);
glTexCoord2f( 0, 600/1024); glVertex2f( 0, 600);
glTexCoord2f(800/1024, 600/1024); glVertex2f(800, 600);
glTexCoord2f(800/1024, 0); glVertex2f(800, 0);
glEnd;
// outro overlays
glColor4f(1, 1, 1, (2 + sin(CTime / 15)) / 3);
glBindTexture(GL_TEXTURE_2D, outro_esc.TexNum);
glBegin(Gl_Quads);
glTexCoord2f( 0, 0); glVertex2f( 0, 0);
glTexCoord2f( 0, 223/256); glVertex2f( 0, 223);
glTexCoord2f(487/512, 223/256); glVertex2f(487, 223);
glTexCoord2f(487/512, 0); glVertex2f(487, 0);
glEnd;
if (RandomRange(0,20) <= 18) then
begin
glColor4f(1, 1, 1, 1);
glBindTexture(GL_TEXTURE_2D, outro_exd.TexNum);
glBegin(Gl_Quads);
glTexCoord2f( 0, 0); glVertex2f(800-310, 600-247);
glTexCoord2f( 0, 247/256); glVertex2f(800-310, 600 );
glTexCoord2f(310/512, 247/256); glVertex2f(800, 600 );
glTexCoord2f(310/512, 0); glVertex2f(800, 600-247);
glEnd;
end;
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
// outro scrollers?
// ...
end;
{ name effects }
{ effects are called with blending texture and matrix prepared }
procedure Effect_Draw (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, 1);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_OnBeatJitter (const Tex: TTexture; Progress: double);
var
Diff: cardinal;
Alpha: double;
begin
Diff := ScreenCredits.CTime - ScreenCredits.LastBeatTime;
if (Diff < BeatJitterTime) then
Alpha := 0.5 + 0.5 * Diff / BeatJitterTime
else
Alpha := 1;
glColor4f(1, 1, 1, Alpha);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Rotate_Left_Top (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
gltranslatef(-NameX, 0, 0);
glrotatef(Progress * 90 + 270, 0, 0, 1);
gltranslatef(NameX, 0, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Rotate_Right_Bot (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
gltranslatef(NameX, 0, 0);
glrotatef((Progress - 1) * 90, 0, 0, 1);
gltranslatef(-NameX, 0, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_ZoomIn_Rotate (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glscalef(sqr(Progress), sqr(Progress), sqr(Progress));
glrotatef(Progress * 360, 0, 0, 1);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_ZoomOut_Shift (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := (1 - Progress);
gltranslatef(X * 300, -X * 100, 0);
glscalef(1 + X, 1 + X, 1 + X);
glrotatef(X * 90, 0, 0, 1);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Shift_Left (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glTranslatef((Progress - 1) * 210, 0, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Shift_Right_Top (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glTranslatef((1 - Progress) * 210, (Progress - 1) * 105, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Flip_Bot (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := NameH * (1 - Progress);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2 - 1.5 * X, -NameH/2 + 1.5 * X);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2 + 1.5 * X, -NameH/2 + 1.5 * X);
glEnd;
end;
procedure Effect_Flip_Right_Top (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := NameW * (1 - Progress);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2 + X, -NameH/2 - X/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2 + X, NameH/2 - (X * 1.5 * NameH / NameW));
glTexCoord2f(1, 1); glVertex2f( NameW/2 + X, NameH/2 + X / 4);
glTexCoord2f(1, 0); glVertex2f( NameW/2 + X, -NameH/2 - X / 4);
glEnd;
end;
procedure Effect_Flip_Right (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := NameW * (1 - Progress);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2 - X, NameH/2 + X * 1.5);
glTexCoord2f(1, 0); glVertex2f( NameW/2 - X, -NameH/2 - X * 1.5);
glEnd;
end;
procedure Effect_Flip_Right_Bot (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := NameW * (1 - Progress);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2 + X * 1.5, -NameH/2 + X * 1.5);
glTexCoord2f(0, 1); glVertex2f(-NameW/2 + X * 1.2, NameH/2 + X);
glTexCoord2f(1, 1); glVertex2f( NameW/2 + X / 2, NameH/2 + X / 4);
glTexCoord2f(1, 0); glVertex2f( NameW/2 + X * 1.5, -NameH/2);
glEnd;
end;
procedure Effect_Rotate_Right_Top (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glTranslatef(NameX, 0, 0);
glrotatef((1 - Progress) * 90, 0, 0, 1);
glTranslatef(-NameX, 0, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Shift_Weird (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := (Progress - 1);
glTranslatef(X * 200, X * 100, 0);
glScalef(Progress, Progress, Progress);
glRotatef(X * 90, 0, 0, 1);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Shift_Right_Bot (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glTranslatef((1 - Progress) * 200, (1 - Progress) * 100, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Rotate_Right_Top2 (const Tex: TTexture; Progress: double);
begin
glColor4f(1, 1, 1, Progress);
glTranslatef(0, -NameX, 0);
glRotatef((Progress - 1) * 90, 0, 0, 1);
glTranslatef(0, NameX, 0);
glRotatef((1 - Progress) * 90, 0, 0, 1);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH/2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2, NameH/2);
glTexCoord2f(1, 1); glVertex2f( NameW/2, NameH/2);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH/2);
glEnd;
end;
procedure Effect_Flip_Left_Bot (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := (1 - Progress) * NameW;
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2 - X, -NameH/2 + X / 4);
glTexCoord2f(0, 1); glVertex2f(-NameW/2 - X / 4, NameH/2 + X / 4);
glTexCoord2f(1, 1); glVertex2f( NameW/2 - X * 1.2, NameH/2 + X / 2);
glTexCoord2f(1, 0); glVertex2f( NameW/2 - X * 1.5, -NameH/2 + X * 1.5);
glEnd;
end;
procedure Effect_Flip_Right_Top2 (const Tex: TTexture; Progress: double);
var
X: double;
begin
glColor4f(1, 1, 1, Progress);
X := (1 - Progress) * NameW;
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2 + X, -NameH/2 - X / 2);
glTexCoord2f(0, 1); glVertex2f(-NameW/2 + X, NameH/2 + X / 2);
glTexCoord2f(1, 1); glVertex2f( NameW/2 + X / 4, NameH/2 - X / 4);
glTexCoord2f(1, 0); glVertex2f( NameW/2 + X / 4, -NameH/2 + X / 4);
glEnd;
end;
procedure Effect_Twinkle_Down (const Tex: TTexture; Progress: double);
begin
// draw name
glColor4f(1, 1, 1, 1);
glTranslatef(0, NameH/2, 0);
glBegin(gl_Quads);
glTexCoord2f(0, 0); glVertex2f(-NameW/2, -NameH * Progress);
glTexCoord2f(0, Progress); glVertex2f(-NameW/2, 0);
glTexCoord2f(1, Progress); glVertex2f( NameW/2, 0);
glTexCoord2f(1, 0); glVertex2f( NameW/2, -NameH * Progress);
glEnd;
//spawn some stars on the edge
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 5);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 5);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 0);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 1);
GoldenRec.Spawn(NameX + RandomRange(-NameW div 2, NameW div 2), NameY - NameH/2 + (1 - Progress) * NameH, 1, 16, 0, -1, PerfectLineTwinkle, 5);
end;
{ beat detection algorithm
based on a tutorial from Fr�d�ric Patin on gamedev.net
http://www.gamedev.net/reference/programming/features/beatdetection/default.asp }
{ calculates average value of a history buffer }
function Average(History: TEnergyHistory): single;
var I: integer;
begin
Result := 0;
for I := 0 to HistoryLength - 1 do
Result := Result + History[I];
Result := Result / HistoryLength;
end;
{ calculates variance value of a history buffer }
function Variance(History: TEnergyHistory; Average: single): single;
var I: integer;
begin
Result := 0;
for I := 0 to HistoryLength - 1 do
Result := Result + sqr(History[I] - Average);
Result := Result / HistoryLength;
end;
{ shifts all values of the history to the right and
adds the new value at the front }
procedure AddHistory(Value: single; var History: TEnergyHistory);
var I: integer;
begin
for I := HistoryLength - 1 downto 1 do
History[I] := History[I-1];
History[0] := Value;
end;
{ calculates instant energy from FFT data for a specific
subchannel (0..SubChannelCount - 1) }
function CalculateInstantEnergy(SubChannel: integer; Data: TFFTData): single;
var I: integer;
begin
Result := 0;
for I := SubChannel * SamplesPerChannel to (SubChannel + 1) * SamplesPerChannel - 1 do
Result := Result + Data[I] * BeatEnergyModifier;
Result := Result / SamplesPerChannel;
end;
procedure TScreenCredits.DetectBeat;
var
Data: TFFTData;
I: integer;
Instant: single;
C, E, V: single;
begin
AudioPlayback.GetFFTData(Data);
// do beatdetection for every subchannel
for I := 0 to SubChannelCount - 1 do
begin
Instant := CalculateInstantEnergy(I, Data);
E := Average(SubchannelHistory[I]);
V := Variance(SubchannelHistory[I], E);
C := (-0.0025714 * V) + 1.5142857;
AddHistory(Instant, SubChannelHistory[I]);
if (Instant > 2) and (Instant > C * E) then
begin
// beat detected
BeatDetected := true;
LastBeatTime := CTime;
end;
end;
end;
end.