aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2010-04-21 18:27:36 +0000
committertobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2010-04-21 18:27:36 +0000
commit868ce765441473e7d1fec9b3ad22a707f121a637 (patch)
tree8f67a0e6ff2c306603ef37ec0bc8cc0e042eb5d2
parent62c665cb863914c2d5e07bf4b8bd07c1c45be7ac (diff)
downloadusdx-868ce765441473e7d1fec9b3ad22a707f121a637.tar.gz
usdx-868ce765441473e7d1fec9b3ad22a707f121a637.tar.xz
usdx-868ce765441473e7d1fec9b3ad22a707f121a637.zip
- add video loop option
- allow multiple instances of a video git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@2260 b956fd51-792f-4845-bead-9b4dfca2ff2c
-rw-r--r--src/base/UMusic.pas39
-rw-r--r--src/media/UMedia_dummy.pas200
-rw-r--r--src/media/UVideo.pas162
-rw-r--r--src/media/UVisualizer.pas230
-rw-r--r--src/menu/UMenuBackgroundVideo.pas39
-rw-r--r--src/screens/UScreenSing.pas69
6 files changed, 459 insertions, 280 deletions
diff --git a/src/base/UMusic.pas b/src/base/UMusic.pas
index 5d816c9a..e349bd1f 100644
--- a/src/base/UMusic.pas
+++ b/src/base/UMusic.pas
@@ -324,28 +324,33 @@ type
IGenericPlayback = Interface
['{63A5EBC3-3F4D-4F23-8DFB-B5165FCE33DD}']
function GetName: String;
+ end;
- function Open(const Filename: IPath): boolean; // true if succeed
- procedure Close;
-
+ IVideo = interface
+ ['{58DFC674-9168-41EA-B59D-A61307242B80}']
procedure Play;
procedure Pause;
procedure Stop;
+ procedure SetLoop(Enable: boolean);
+ function GetLoop(): boolean;
+
procedure SetPosition(Time: real);
function GetPosition: real;
+ procedure GetFrame(Time: Extended);
+ procedure DrawGL(Screen: integer);
+
+ property Loop: boolean read GetLoop write SetLoop;
property Position: real read GetPosition write SetPosition;
end;
IVideoPlayback = Interface( IGenericPlayback )
['{3574C40C-28AE-4201-B3D1-3D1F0759B131}']
- function Init(): boolean;
- function Finalize: boolean;
-
- procedure GetFrame(Time: Extended); // WANT TO RENAME THESE TO BE MORE GENERIC
- procedure DrawGL(Screen: integer); // WANT TO RENAME THESE TO BE MORE GENERIC
+ function Init(): boolean;
+ function Finalize: boolean;
+ function Open(const FileName : IPath): IVideo;
end;
IVideoVisualization = Interface( IVideoPlayback )
@@ -370,6 +375,18 @@ type
function Finished: boolean;
function Length: real;
+ function Open(const Filename: IPath): boolean; // true if succeed
+ procedure Close;
+
+ procedure Play;
+ procedure Pause;
+ procedure Stop;
+
+ procedure SetPosition(Time: real);
+ function GetPosition: real;
+
+ property Position: real read GetPosition write SetPosition;
+
// Sounds
// TODO:
// add a TMediaDummyPlaybackStream implementation that will
@@ -814,12 +831,6 @@ begin
if (AudioInput <> nil) then
AudioInput.CaptureStop;
- if (VideoPlayback <> nil) then
- VideoPlayback.Close;
-
- if (Visualization <> nil) then
- Visualization.Close;
-
UnloadMediaModules();
end;
diff --git a/src/media/UMedia_dummy.pas b/src/media/UMedia_dummy.pas
index 25e94724..35b8bd70 100644
--- a/src/media/UMedia_dummy.pas
+++ b/src/media/UMedia_dummy.pas
@@ -42,17 +42,17 @@ uses
UPath;
type
- TMedia_dummy = class( TInterfacedObject, IVideoPlayback, IVideoVisualization, IAudioPlayback, IAudioInput )
+ TAudio_Dummy = class( TInterfacedObject, IAudioPlayback, IAudioInput )
private
DummyOutputDeviceList: TAudioOutputDeviceList;
public
constructor Create();
- function GetName: string;
+ function GetName: string;
function Init(): boolean;
function Finalize(): boolean;
- function Open(const aFileName: IPath): boolean; // true if succeed
+ function Open(const aFileName: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -64,9 +64,6 @@ type
procedure SetSyncSource(SyncSource: TSyncSource);
- procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
-
// IAudioInput
function InitializeRecord: boolean;
function FinalizeRecord: boolean;
@@ -83,9 +80,11 @@ type
procedure FadeIn(Time: real; TargetVolume: single);
procedure SetAppVolume(Volume: single);
procedure SetVolume(Volume: single);
- procedure SetLoop(Enabled: boolean);
procedure Rewind;
+ procedure SetLoop(Enabled: boolean);
+ function GetLoop(): boolean;
+
function Finished: boolean;
function Length: real;
@@ -98,98 +97,122 @@ type
procedure CloseVoiceStream(var VoiceStream: TAudioVoiceStream);
end;
-function TMedia_dummy.GetName: string;
-begin
- Result := 'dummy';
-end;
+ TVideo_Dummy = class( TInterfacedObject, IVideo )
+ public
+ procedure Close;
-procedure TMedia_dummy.GetFrame(Time: Extended);
-begin
-end;
+ procedure Play;
+ procedure Pause;
+ procedure Stop;
+
+ procedure SetLoop(Enable: boolean);
+ function GetLoop(): boolean;
+
+ procedure SetPosition(Time: real);
+ function GetPosition: real;
+
+ procedure GetFrame(Time: Extended);
+ procedure DrawGL(Screen: integer);
+
+ property Loop: boolean read GetLoop write SetLoop;
+ property Position: real read GetPosition write SetPosition;
+ end;
-procedure TMedia_dummy.DrawGL(Screen: integer);
+ TVideoPlayback_Dummy = class( TInterfacedObject, IVideoPlayback, IVideoVisualization )
+ public
+ constructor Create();
+ function GetName: string;
+
+ function Init(): boolean;
+ function Finalize(): boolean;
+
+ function Open(const FileName: IPath): IVideo;
+ end;
+
+function TAudio_Dummy.GetName: string;
begin
+ Result := 'AudioDummy';
end;
-constructor TMedia_dummy.Create();
+constructor TAudio_Dummy.Create();
begin
inherited;
end;
-function TMedia_dummy.Init(): boolean;
+function TAudio_Dummy.Init(): boolean;
begin
Result := true;
end;
-function TMedia_dummy.Finalize(): boolean;
+function TAudio_Dummy.Finalize(): boolean;
begin
Result := true;
end;
-function TMedia_dummy.Open(const aFileName : IPath): boolean; // true if succeed
+function TAudio_Dummy.Open(const aFileName : IPath): boolean; // true if succeed
begin
Result := false;
end;
-procedure TMedia_dummy.Close;
+procedure TAudio_Dummy.Close;
begin
end;
-procedure TMedia_dummy.Play;
+procedure TAudio_Dummy.Play;
begin
end;
-procedure TMedia_dummy.Pause;
+procedure TAudio_Dummy.Pause;
begin
end;
-procedure TMedia_dummy.Stop;
+procedure TAudio_Dummy.Stop;
begin
end;
-procedure TMedia_dummy.SetPosition(Time: real);
+procedure TAudio_Dummy.SetPosition(Time: real);
begin
end;
-function TMedia_dummy.GetPosition: real;
+function TAudio_Dummy.GetPosition: real;
begin
Result := 0;
end;
-procedure TMedia_dummy.SetSyncSource(SyncSource: TSyncSource);
+procedure TAudio_Dummy.SetSyncSource(SyncSource: TSyncSource);
begin
end;
// IAudioInput
-function TMedia_dummy.InitializeRecord: boolean;
+function TAudio_Dummy.InitializeRecord: boolean;
begin
Result := true;
end;
-function TMedia_dummy.FinalizeRecord: boolean;
+function TAudio_Dummy.FinalizeRecord: boolean;
begin
Result := true;
end;
-procedure TMedia_dummy.CaptureStart;
+procedure TAudio_Dummy.CaptureStart;
begin
end;
-procedure TMedia_dummy.CaptureStop;
+procedure TAudio_Dummy.CaptureStop;
begin
end;
-procedure TMedia_dummy.GetFFTData(var data: TFFTData);
+procedure TAudio_Dummy.GetFFTData(var data: TFFTData);
begin
end;
-function TMedia_dummy.GetPCMData(var data: TPCMData): Cardinal;
+function TAudio_Dummy.GetPCMData(var data: TPCMData): Cardinal;
begin
Result := 0;
end;
// IAudioPlayback
-function TMedia_dummy.InitializePlayback: boolean;
+function TAudio_Dummy.InitializePlayback: boolean;
begin
SetLength(DummyOutputDeviceList, 1);
DummyOutputDeviceList[0] := TAudioOutputDevice.Create();
@@ -197,73 +220,152 @@ begin
Result := true;
end;
-function TMedia_dummy.FinalizePlayback: boolean;
+function TAudio_Dummy.FinalizePlayback: boolean;
begin
Result := true;
end;
-function TMedia_dummy.GetOutputDeviceList(): TAudioOutputDeviceList;
+function TAudio_Dummy.GetOutputDeviceList(): TAudioOutputDeviceList;
begin
Result := DummyOutputDeviceList;
end;
-procedure TMedia_dummy.SetAppVolume(Volume: single);
+procedure TAudio_Dummy.SetAppVolume(Volume: single);
+begin
+end;
+
+procedure TAudio_Dummy.SetVolume(Volume: single);
begin
end;
-procedure TMedia_dummy.SetVolume(Volume: single);
+procedure TAudio_Dummy.SetLoop(Enabled: boolean);
begin
end;
-procedure TMedia_dummy.SetLoop(Enabled: boolean);
+function TAudio_Dummy.GetLoop(): boolean;
begin
+ Result := false;
end;
-procedure TMedia_dummy.FadeIn(Time: real; TargetVolume: single);
+procedure TAudio_Dummy.FadeIn(Time: real; TargetVolume: single);
begin
end;
-procedure TMedia_dummy.Rewind;
+procedure TAudio_Dummy.Rewind;
begin
end;
-function TMedia_dummy.Finished: boolean;
+function TAudio_Dummy.Finished: boolean;
begin
Result := false;
end;
-function TMedia_dummy.Length: real;
+function TAudio_Dummy.Length: real;
begin
Result := 60;
end;
-function TMedia_dummy.OpenSound(const Filename: IPath): TAudioPlaybackStream;
+function TAudio_Dummy.OpenSound(const Filename: IPath): TAudioPlaybackStream;
begin
Result := nil;
end;
-procedure TMedia_dummy.CloseSound(var PlaybackStream: TAudioPlaybackStream);
+procedure TAudio_Dummy.CloseSound(var PlaybackStream: TAudioPlaybackStream);
begin
end;
-procedure TMedia_dummy.PlaySound(stream: TAudioPlaybackStream);
+procedure TAudio_Dummy.PlaySound(stream: TAudioPlaybackStream);
begin
end;
-procedure TMedia_dummy.StopSound(stream: TAudioPlaybackStream);
+procedure TAudio_Dummy.StopSound(stream: TAudioPlaybackStream);
begin
end;
-function TMedia_dummy.CreateVoiceStream(Channel: integer; FormatInfo: TAudioFormatInfo): TAudioVoiceStream;
+function TAudio_Dummy.CreateVoiceStream(Channel: integer; FormatInfo: TAudioFormatInfo): TAudioVoiceStream;
begin
Result := nil;
end;
-procedure TMedia_dummy.CloseVoiceStream(var VoiceStream: TAudioVoiceStream);
+procedure TAudio_Dummy.CloseVoiceStream(var VoiceStream: TAudioVoiceStream);
+begin
+end;
+
+
+{ TVideoPlayback_Dummy }
+
+procedure TVideo_Dummy.Close;
begin
end;
+procedure TVideo_Dummy.Play;
+begin
+end;
+
+procedure TVideo_Dummy.Pause;
+begin
+end;
+
+procedure TVideo_Dummy.Stop;
+begin
+end;
+
+procedure TVideo_Dummy.SetLoop(Enable: boolean);
+begin
+end;
+
+function TVideo_Dummy.GetLoop(): boolean;
+begin
+ Result := false;
+end;
+
+procedure TVideo_Dummy.SetPosition(Time: real);
+begin
+end;
+
+function TVideo_Dummy.GetPosition: real;
+begin
+ Result := 0;
+end;
+
+procedure TVideo_Dummy.GetFrame(Time: Extended);
+begin
+end;
+
+procedure TVideo_Dummy.DrawGL(Screen: integer);
+begin
+end;
+
+
+{ TVideoPlayback_Dummy }
+
+constructor TVideoPlayback_Dummy.Create();
+begin
+end;
+
+function TVideoPlayback_Dummy.GetName: string;
+begin
+ Result := 'VideoDummy';
+end;
+
+function TVideoPlayback_Dummy.Init(): boolean;
+begin
+ Result := true;
+end;
+
+function TVideoPlayback_Dummy.Finalize(): boolean;
+begin
+ Result := true;
+end;
+
+function TVideoPlayback_Dummy.Open(const FileName: IPath): IVideo;
+begin
+ Result := TVideo_Dummy.Create;
+end;
+
+
initialization
- MediaManager.Add(TMedia_dummy.Create);
+ MediaManager.Add(TAudio_Dummy.Create);
+ MediaManager.Add(TVideoPlayback_Dummy.Create);
end.
diff --git a/src/media/UVideo.pas b/src/media/UVideo.pas
index 27f29f7e..fd3c7e2a 100644
--- a/src/media/UVideo.pas
+++ b/src/media/UVideo.pas
@@ -107,11 +107,15 @@ type
Upper, Lower: double;
end;
- TVideoPlayback_FFmpeg = class( TInterfacedObject, IVideoPlayback )
+ IVideo_FFmpeg = interface (IVideo)
+ ['{E640E130-C8C0-4399-AF02-67A3569313AB}']
+ function Open(const FileName: IPath): boolean;
+ end;
+
+ TVideo_FFmpeg = class( TInterfacedObject, IVideo_FFmpeg )
private
fOpened: boolean; //**< stream successfully opened
fPaused: boolean; //**< stream paused
- fInitialized: boolean;
fEOF: boolean; //**< end-of-file state
fLoop: boolean; //**< looping enabled
@@ -150,23 +154,37 @@ type
procedure ShowDebugInfo();
public
- function GetName: String;
+ constructor Create;
+ destructor Destroy; override;
+
+ function Open(const FileName: IPath): boolean;
+ procedure Close;
- function Init(): boolean;
- function Finalize: boolean;
+ procedure Play;
+ procedure Pause;
+ procedure Stop;
+
+ procedure SetLoop(Enable: boolean);
+ function GetLoop(): boolean;
+
+ procedure SetPosition(Time: real);
+ function GetPosition: real;
+
+ procedure GetFrame(Time: Extended);
+ procedure DrawGL(Screen: integer);
+ end;
- function Open(const FileName : IPath): boolean; // true if succeed
- procedure Close;
+ TVideoPlayback_FFmpeg = class( TInterfacedObject, IVideoPlayback )
+ private
+ fInitialized: boolean;
- procedure Play;
- procedure Pause;
- procedure Stop;
+ public
+ function GetName: String;
- procedure SetPosition(Time: real);
- function GetPosition: real;
+ function Init(): boolean;
+ function Finalize: boolean;
- procedure GetFrame(Time: Extended);
- procedure DrawGL(Screen: integer);
+ function Open(const FileName : IPath): IVideo;
end;
var
@@ -219,47 +237,46 @@ begin
FFmpegCore := TMediaCore_FFmpeg.GetInstance();
- Reset();
av_register_all();
- glGenTextures(1, PGLuint(@fFrameTex));
end;
function TVideoPlayback_FFmpeg.Finalize(): boolean;
begin
- Close();
- glDeleteTextures(1, PGLuint(@fFrameTex));
Result := true;
end;
-procedure TVideoPlayback_FFmpeg.Reset();
+function TVideoPlayback_FFmpeg.Open(const FileName : IPath): IVideo;
+var
+ Video: IVideo_FFmpeg;
begin
- // close previously opened video
- Close();
+ Video := TVideo_FFmpeg.Create;
+ if Video.Open(FileName) then
+ Result := Video
+ else
+ Result := nil;
+end;
- fOpened := False;
- fPaused := False;
- fTimeBase := 0;
- fTime := 0;
- fStream := nil;
- fStreamIndex := -1;
- fFrameTexValid := false;
- fEOF := false;
+{* TVideo_FFmpeg *}
- // TODO: do we really want this by default?
- fLoop := true;
- fLoopTime := 0;
+constructor TVideo_FFmpeg.Create;
+begin
+ glGenTextures(1, PGLuint(@fFrameTex));
+ Reset();
+end;
- fAspectCorrection := acoCrop;
+destructor TVideo_FFmpeg.Destroy;
+begin
+ Close();
+ glDeleteTextures(1, PGLuint(@fFrameTex));
end;
-function TVideoPlayback_FFmpeg.Open(const FileName : IPath): boolean; // true if succeed
+function TVideo_FFmpeg.Open(const FileName : IPath): boolean;
var
errnum: Integer;
AudioStreamIndex: integer;
begin
Result := false;
-
Reset();
// use custom 'ufile' protocol for UTF-8 support
@@ -408,6 +425,7 @@ begin
end;
{$ENDIF}
+
fTexWidth := Round(Power(2, Ceil(Log2(fCodecContext^.width))));
fTexHeight := Round(Power(2, Ceil(Log2(fCodecContext^.height))));
@@ -420,11 +438,32 @@ begin
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- fOpened := True;
+ fOpened := true;
Result := true;
end;
-procedure TVideoPlayback_FFmpeg.Close;
+procedure TVideo_FFmpeg.Reset();
+begin
+ // close previously opened video
+ Close();
+
+ fOpened := False;
+ fPaused := False;
+ fTimeBase := 0;
+ fTime := 0;
+ fStream := nil;
+ fStreamIndex := -1;
+ fFrameTexValid := false;
+
+ fEOF := false;
+
+ fLoop := false;
+ fLoopTime := 0;
+
+ fAspectCorrection := acoCrop;
+end;
+
+procedure TVideo_FFmpeg.Close;
begin
if (fFrameBuffer <> nil) then
av_free(fFrameBuffer);
@@ -457,7 +496,7 @@ begin
fOpened := False;
end;
-procedure TVideoPlayback_FFmpeg.SynchronizeTime(Frame: PAVFrame; var pts: double);
+procedure TVideo_FFmpeg.SynchronizeTime(Frame: PAVFrame; var pts: double);
var
FrameDelay: double;
begin
@@ -484,7 +523,7 @@ end;
* @param pts will be updated to the presentation time of the decoded frame.
* returns true if a frame could be decoded. False if an error or EOF occured.
*}
-function TVideoPlayback_FFmpeg.DecodeFrame(): boolean;
+function TVideo_FFmpeg.DecodeFrame(): boolean;
var
FrameFinished: Integer;
VideoPktPts: int64;
@@ -522,7 +561,10 @@ begin
// check for errors
if (url_ferror(pbIOCtx) <> 0) then
+ begin
+ Log.LogError('Video decoding file error', 'TVideoPlayback_FFmpeg.DecodeFrame');
Exit;
+ end;
// url_feof() does not detect an EOF for some mov-files (e.g. deluxe.mov)
// so we have to do it this way.
@@ -533,18 +575,9 @@ begin
Exit;
end;
- // no error -> wait for user input
-{
- SDL_Delay(100); // initial version, left for documentation
- continue;
-}
-
- // Patch by Hawkear:
- // Why should this function loop in an endless loop if there is an error?
- // This runs in the main thread, so it halts the whole program
- // Therefore, it is better to exit when an error occurs
+ // error occured, log and exit
+ Log.LogError('Video decoding error', 'TVideoPlayback_FFmpeg.DecodeFrame');
Exit;
-
end;
// if we got a packet from the video stream, then decode it
@@ -593,7 +626,7 @@ begin
Result := true;
end;
-procedure TVideoPlayback_FFmpeg.GetFrame(Time: Extended);
+procedure TVideo_FFmpeg.GetFrame(Time: Extended);
var
errnum: Integer;
NewTime: Extended;
@@ -749,7 +782,7 @@ begin
{$ENDIF}
end;
-procedure TVideoPlayback_FFmpeg.GetVideoRect(var ScreenRect, TexRect: TRectCoords);
+procedure TVideo_FFmpeg.GetVideoRect(var ScreenRect, TexRect: TRectCoords);
var
ScreenAspect: double; // aspect of screen resolution
ScaledVideoWidth, ScaledVideoHeight: double;
@@ -799,7 +832,7 @@ begin
TexRect.Lower := fCodecContext^.height / fTexHeight;
end;
-procedure TVideoPlayback_FFmpeg.DrawGL(Screen: integer);
+procedure TVideo_FFmpeg.DrawGL(Screen: integer);
var
ScreenRect: TRectCoords;
TexRect: TRectCoords;
@@ -862,7 +895,7 @@ begin
{$IFEND}
end;
-procedure TVideoPlayback_FFmpeg.ShowDebugInfo();
+procedure TVideo_FFmpeg.ShowDebugInfo();
begin
{$IFDEF Info}
if (fTime+fTimeBase < 0) then
@@ -899,17 +932,28 @@ begin
{$ENDIF}
end;
-procedure TVideoPlayback_FFmpeg.Play;
+procedure TVideo_FFmpeg.Play;
begin
end;
-procedure TVideoPlayback_FFmpeg.Pause;
+procedure TVideo_FFmpeg.Pause;
begin
fPaused := not fPaused;
end;
-procedure TVideoPlayback_FFmpeg.Stop;
+procedure TVideo_FFmpeg.Stop;
+begin
+end;
+
+procedure TVideo_FFmpeg.SetLoop(Enable: boolean);
+begin
+ fLoop := Enable;
+ fLoopTime := 0;
+end;
+
+function TVideo_FFmpeg.GetLoop(): boolean;
begin
+ Result := fLoop;
end;
{**
@@ -920,7 +964,7 @@ end;
* actual frame time when GetFrame() is called the next time.
* @param Time new position in seconds
*}
-procedure TVideoPlayback_FFmpeg.SetPosition(Time: real);
+procedure TVideo_FFmpeg.SetPosition(Time: real);
var
SeekFlags: integer;
begin
@@ -955,7 +999,7 @@ begin
avcodec_flush_buffers(fCodecContext);
end;
-function TVideoPlayback_FFmpeg.GetPosition: real;
+function TVideo_FFmpeg.GetPosition: real;
begin
Result := fTime;
end;
diff --git a/src/media/UVisualizer.pas b/src/media/UVisualizer.pas
index b25d68a9..4f553521 100644
--- a/src/media/UVisualizer.pas
+++ b/src/media/UVisualizer.pas
@@ -60,12 +60,17 @@ interface
{$I switches.inc}
+{.$DEFINE UseTexture}
+
uses
SDL,
UGraphicClasses,
textgl,
math,
gl,
+ {$IFDEF UseTexture}
+ glu,
+ {$ENDIF}
SysUtils,
UIni,
projectM,
@@ -91,31 +96,29 @@ const
{$IFEND}
type
+ TProjectMState = ( pmPlay, pmStop, pmPause );
+
+type
TGLMatrix = array[0..3, 0..3] of GLdouble;
TGLMatrixStack = array of TGLMatrix;
type
- TVideoPlayback_ProjectM = class( TInterfacedObject, IVideoPlayback, IVideoVisualization )
+ TVideo_ProjectM = class( TInterfacedObject, IVideo )
private
- pm: TProjectM;
- ProjectMPath : string;
- Initialized: boolean;
-
- VisualizerStarted: boolean;
- VisualizerPaused: boolean;
+ fPm: TProjectM;
+ fProjectMPath : string;
- VisualTex: GLuint;
- PCMData: TPCMData;
- RndPCMcount: integer;
+ fState: TProjectMState;
- ModelviewMatrixStack: TGLMatrixStack;
- ProjectionMatrixStack: TGLMatrixStack;
- TextureMatrixStack: TGLMatrixStack;
+ fVisualTex: GLuint;
+ fPCMData: TPCMData;
+ fRndPCMcount: integer;
- procedure VisualizerStart;
- procedure VisualizerStop;
+ fModelviewMatrixStack: TGLMatrixStack;
+ fProjectionMatrixStack: TGLMatrixStack;
+ fTextureMatrixStack: TGLMatrixStack;
- procedure VisualizerTogglePause;
+ procedure InitProjectM;
function GetRandomPCMData(var Data: TPCMData): Cardinal;
@@ -126,12 +129,9 @@ type
procedure RestoreOpenGLState();
public
- function GetName: String;
+ constructor Create;
+ destructor Destroy; override;
- function Init(): boolean;
- function Finalize(): boolean;
-
- function Open(const aFileName: IPath): boolean; // true if succeed
procedure Close;
procedure Play;
@@ -141,10 +141,28 @@ type
procedure SetPosition(Time: real);
function GetPosition: real;
+ procedure SetLoop(Enable: boolean);
+ function GetLoop(): boolean;
+
procedure GetFrame(Time: Extended);
procedure DrawGL(Screen: integer);
end;
+ TVideoPlayback_ProjectM = class( TInterfacedObject, IVideoVisualization )
+ private
+ fInitialized: boolean;
+
+ public
+ function GetName: String;
+
+ function Init(): boolean;
+ function Finalize(): boolean;
+
+ function Open(const aFileName: IPath): IVideo;
+ end;
+
+
+{ TVideoPlayback_ProjectM }
function TVideoPlayback_ProjectM.GetName: String;
begin
@@ -154,76 +172,100 @@ end;
function TVideoPlayback_ProjectM.Init(): boolean;
begin
Result := true;
-
- if (Initialized) then
+ if (fInitialized) then
Exit;
- Initialized := true;
+ fInitialized := true;
+end;
- RndPCMcount := 0;
+function TVideoPlayback_ProjectM.Finalize(): boolean;
+begin
+ Result := true;
+end;
+
+function TVideoPlayback_ProjectM.Open(const aFileName: IPath): IVideo;
+begin
+ Result := TVideo_ProjectM.Create;
+end;
- ProjectMPath := ProjectM_DataDir + PathDelim;
- VisualizerStarted := False;
- VisualizerPaused := False;
+{ TVideo_ProjectM }
+
+constructor TVideo_ProjectM.Create;
+begin
+ fRndPCMcount := 0;
+
+ fProjectMPath := ProjectM_DataDir + PathDelim;
+
+ fState := pmStop;
{$IFDEF UseTexture}
- glGenTextures(1, PglUint(@VisualTex));
- glBindTexture(GL_TEXTURE_2D, VisualTex);
+ glGenTextures(1, PglUint(@fVisualTex));
+ glBindTexture(GL_TEXTURE_2D, fVisualTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
{$ENDIF}
+
+ InitProjectM();
end;
-function TVideoPlayback_ProjectM.Finalize(): boolean;
+destructor TVideo_ProjectM.Destroy;
begin
- VisualizerStop();
+ Close();
{$IFDEF UseTexture}
- glDeleteTextures(1, PglUint(@VisualTex));
+ glDeleteTextures(1, PglUint(@fVisualTex));
{$ENDIF}
- Result := true;
end;
-function TVideoPlayback_ProjectM.Open(const aFileName: IPath): boolean; // true if succeed
+procedure TVideo_ProjectM.Close;
begin
- Result := false;
+ FreeAndNil(fPm);
end;
-procedure TVideoPlayback_ProjectM.Close;
+procedure TVideo_ProjectM.Play;
begin
- VisualizerStop();
+ if (fState = pmStop) and (assigned(fPm)) then
+ fPm.RandomPreset();
+ fState := pmPlay;
end;
-procedure TVideoPlayback_ProjectM.Play;
+procedure TVideo_ProjectM.Pause;
begin
- VisualizerStart();
+ if (fState = pmPlay) then
+ fState := pmPause
+ else if (fState = pmPause) then
+ fState := pmPlay;
end;
-procedure TVideoPlayback_ProjectM.Pause;
+procedure TVideo_ProjectM.Stop;
begin
- VisualizerTogglePause();
+ fState := pmStop;
end;
-procedure TVideoPlayback_ProjectM.Stop;
+procedure TVideo_ProjectM.SetPosition(Time: real);
begin
- VisualizerStop();
+ if assigned(fPm) then
+ fPm.RandomPreset();
end;
-procedure TVideoPlayback_ProjectM.SetPosition(Time: real);
+function TVideo_ProjectM.GetPosition: real;
begin
- if assigned(pm) then
- pm.RandomPreset();
+ Result := 0;
end;
-function TVideoPlayback_ProjectM.GetPosition: real;
+procedure TVideo_ProjectM.SetLoop(Enable: boolean);
begin
- Result := 0;
+end;
+
+function TVideo_ProjectM.GetLoop(): boolean;
+begin
+ Result := true;
end;
{**
* Returns the stack depth of the given OpenGL matrix mode stack.
*}
-function TVideoPlayback_ProjectM.GetMatrixStackDepth(MatrixMode: GLenum): GLint;
+function TVideo_ProjectM.GetMatrixStackDepth(MatrixMode: GLenum): GLint;
begin
// get number of matrices on stack
case (MatrixMode) of
@@ -253,7 +295,7 @@ end;
* By saving the whole stack we are on the safe side, so a nasty bug in the
* visualizer does not corrupt USDX.
*}
-procedure TVideoPlayback_ProjectM.SaveMatrixStack(MatrixMode: GLenum;
+procedure TVideo_ProjectM.SaveMatrixStack(MatrixMode: GLenum;
var MatrixStack: TGLMatrixStack);
var
I: integer;
@@ -289,7 +331,7 @@ end;
{**
* Restores the OpenGL matrix stack stored with SaveMatrixStack.
*}
-procedure TVideoPlayback_ProjectM.RestoreMatrixStack(MatrixMode: GLenum;
+procedure TVideo_ProjectM.RestoreMatrixStack(MatrixMode: GLenum;
var MatrixStack: TGLMatrixStack);
var
I: integer;
@@ -325,15 +367,15 @@ end;
* - Modelview-matrix is pushed to the Modelview-stack
* - the OpenGL error-state (glGetError) is cleared
*}
-procedure TVideoPlayback_ProjectM.SaveOpenGLState();
+procedure TVideo_ProjectM.SaveOpenGLState();
begin
// save all OpenGL state-machine attributes
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
- SaveMatrixStack(GL_PROJECTION, ProjectionMatrixStack);
- SaveMatrixStack(GL_MODELVIEW, ModelviewMatrixStack);
- SaveMatrixStack(GL_TEXTURE, TextureMatrixStack);
+ SaveMatrixStack(GL_PROJECTION, fProjectionMatrixStack);
+ SaveMatrixStack(GL_MODELVIEW, fModelviewMatrixStack);
+ SaveMatrixStack(GL_TEXTURE, fTextureMatrixStack);
glMatrixMode(GL_MODELVIEW);
@@ -345,15 +387,15 @@ end;
* Restores the OpenGL state saved by SaveOpenGLState()
* and resets the error-state.
*}
-procedure TVideoPlayback_ProjectM.RestoreOpenGLState();
+procedure TVideo_ProjectM.RestoreOpenGLState();
begin
// reset OpenGL error-state
glGetError();
// restore matrix stacks
- RestoreMatrixStack(GL_PROJECTION, ProjectionMatrixStack);
- RestoreMatrixStack(GL_MODELVIEW, ModelviewMatrixStack);
- RestoreMatrixStack(GL_TEXTURE, TextureMatrixStack);
+ RestoreMatrixStack(GL_PROJECTION, fProjectionMatrixStack);
+ RestoreMatrixStack(GL_MODELVIEW, fModelviewMatrixStack);
+ RestoreMatrixStack(GL_TEXTURE, fTextureMatrixStack);
// restore all OpenGL state-machine attributes
// (also restores the matrix mode)
@@ -361,22 +403,19 @@ begin
glPopAttrib();
end;
-procedure TVideoPlayback_ProjectM.VisualizerStart;
+procedure TVideo_ProjectM.InitProjectM;
begin
- if VisualizerStarted then
- Exit;
-
// the OpenGL state must be saved before TProjectM.Create is called
SaveOpenGLState();
try
try
{$IF PROJECTM_VERSION >= 1000000} // >= 1.0
- pm := TProjectM.Create(ProjectMPath + 'config.inp');
+ fPm := TProjectM.Create(fProjectMPath + 'config.inp');
{$ELSE}
- pm := TProjectM.Create(
+ fPm := TProjectM.Create(
meshX, meshY, fps, textureSize, ScreenW, ScreenH,
- ProjectMPath + 'presets', ProjectMPath + 'fonts');
+ fProjectMPath + 'presets', fProjectMPath + 'fonts');
{$IFEND}
except on E: Exception do
begin
@@ -387,72 +426,51 @@ begin
end;
// initialize OpenGL
- pm.ResetGL(ScreenW, ScreenH);
+ fPm.ResetGL(ScreenW, ScreenH);
// skip projectM default-preset
- pm.RandomPreset();
+ fPm.RandomPreset();
// projectM >= 1.0 uses the OpenGL FramebufferObject (FBO) extension.
// Unfortunately it does NOT reset the framebuffer-context after
// TProjectM.Create. Either glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) for
// a manual reset or TProjectM.RenderFrame() must be called.
// We use the latter so we do not need to load the FBO extension in USDX.
- pm.RenderFrame();
-
- VisualizerPaused := false;
- VisualizerStarted := true;
+ fPm.RenderFrame();
finally
RestoreOpenGLState();
end;
end;
-procedure TVideoPlayback_ProjectM.VisualizerStop;
-begin
- if VisualizerStarted then
- begin
- VisualizerPaused := false;
- VisualizerStarted := false;
- FreeAndNil(pm);
- end;
-end;
-
-procedure TVideoPlayback_ProjectM.VisualizerTogglePause;
-begin
- VisualizerPaused := not VisualizerPaused;
-end;
-
-procedure TVideoPlayback_ProjectM.GetFrame(Time: Extended);
+procedure TVideo_ProjectM.GetFrame(Time: Extended);
var
nSamples: cardinal;
begin
- if not VisualizerStarted then
- Exit;
-
- if VisualizerPaused then
+ if (fState <> pmPlay) then
Exit;
// get audio data
- nSamples := AudioPlayback.GetPCMData(PcmData);
+ nSamples := AudioPlayback.GetPCMData(fPCMData);
// generate some data if non is available
if (nSamples = 0) then
- nSamples := GetRandomPCMData(PcmData);
+ nSamples := GetRandomPCMData(fPCMData);
// send audio-data to projectM
if (nSamples > 0) then
- pm.AddPCM16Data(PSmallInt(@PcmData), nSamples);
+ fPm.AddPCM16Data(PSmallInt(@fPCMData), nSamples);
// store OpenGL state (might be messed up otherwise)
SaveOpenGLState();
try
// setup projectM's OpenGL state
- pm.ResetGL(ScreenW, ScreenH);
+ fPm.ResetGL(ScreenW, ScreenH);
// let projectM render a frame
- pm.RenderFrame();
+ fPm.RenderFrame();
{$IFDEF UseTexture}
- glBindTexture(GL_TEXTURE_2D, VisualTex);
+ glBindTexture(GL_TEXTURE_2D, fVisualTex);
glFlush();
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, VisualWidth, VisualHeight, 0);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, fVisualWidth, fVisualHeight, 0);
{$ENDIF}
finally
// restore USDX OpenGL state
@@ -467,7 +485,7 @@ end;
* Draws the current frame to screen.
* TODO: this is not used yet. Data is directly drawn on GetFrame().
*}
-procedure TVideoPlayback_ProjectM.DrawGL(Screen: integer);
+procedure TVideo_ProjectM.DrawGL(Screen: integer);
begin
{$IFDEF UseTexture}
// have a nice black background to draw on
@@ -478,7 +496,7 @@ begin
end;
// exit if there's nothing to draw
- if not VisualizerStarted then
+ if (fState <> pmPlay) then
Exit;
// setup display
@@ -497,7 +515,7 @@ begin
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glBindTexture(GL_TEXTURE_2D, VisualTex);
+ glBindTexture(GL_TEXTURE_2D, fVisualTex);
glColor4f(1, 1, 1, 1);
// draw projectM frame
@@ -524,12 +542,12 @@ end;
* Produces random "sound"-data in case no audio-data is available.
* Otherwise the visualization will look rather boring.
*}
-function TVideoPlayback_ProjectM.GetRandomPCMData(var Data: TPCMData): Cardinal;
+function TVideo_ProjectM.GetRandomPCMData(var Data: TPCMData): Cardinal;
var
i: integer;
begin
// Produce some fake PCM data
- if (RndPCMcount mod 500 = 0) then
+ if (fRndPCMcount mod 500 = 0) then
begin
FillChar(Data, SizeOf(TPCMData), 0);
end
@@ -541,7 +559,7 @@ begin
Data[i][1] := Random(High(Word)+1);
end;
end;
- Inc(RndPCMcount);
+ Inc(fRndPCMcount);
Result := 512;
end;
diff --git a/src/menu/UMenuBackgroundVideo.pas b/src/menu/UMenuBackgroundVideo.pas
index 9d265764..006c45e0 100644
--- a/src/menu/UMenuBackgroundVideo.pas
+++ b/src/menu/UMenuBackgroundVideo.pas
@@ -36,6 +36,7 @@ interface
uses
UThemes,
UMenuBackground,
+ UMusic,
UVideo,
UPath;
@@ -84,6 +85,7 @@ type }
TMenuBackgroundVideo = class (TMenuBackground)
private
fFilename: IPath;
+ fBgVideo: IVideo;
public
constructor Create(const ThemedSettings: TThemeBackground); override;
procedure OnShow; override;
@@ -102,7 +104,6 @@ implementation
uses
gl,
glext,
- UMusic,
SysUtils,
UTime,
USkins,
@@ -116,42 +117,48 @@ begin
raise EMenuBackgroundError.Create('TMenuBackgroundVideo: No video filename present');
fFileName := Skin.GetTextureFileName(ThemedSettings.Tex);
- if fFilename.IsFile and VideoPlayback.Open(fFileName) then
- begin
- VideoBGTimer.SetTime(0);
- VideoPlayback.Play;
- end
- else
+ if (not fFilename.IsFile) then
raise EMenuBackgroundError.Create('TMenuBackgroundVideo: Can''t load background video: ' + fFilename.ToNative);
end;
destructor TMenuBackgroundVideo.Destroy;
begin
-
end;
-procedure TMenuBackgroundVideo.OnShow;
+procedure TMenuBackgroundVideo.OnShow;
begin
- if VideoPlayback.Open( fFileName ) then
+ fBgVideo := VideoPlayback.Open(fFileName);
+ if (fBgVideo <> nil) then
begin
VideoBGTimer.SetTime(0);
- VideoPlayback.Play;
+ fBgVideo.Loop := true;
+ fBgVideo.Play;
end;
end;
procedure TMenuBackgroundVideo.OnFinish;
begin
-
+ // unload video
+ fBgVideo := nil;
end;
-procedure TMenuBackgroundVideo.Draw;
+procedure TMenuBackgroundVideo.Draw;
begin
- If (ScreenAct = 1) then //Clear just once when in dual screen mode
+ // clear just once when in dual screen mode
+ if (ScreenAct = 1) then
+ begin
glClear(GL_DEPTH_BUFFER_BIT);
+ // video failure -> draw blank background
+ if (fBgVideo = nil) then
+ glClear(GL_COLOR_BUFFER_BIT);
+ end;
- VideoPlayback.GetFrame(VideoBGTimer.GetTime());
+ if (fBgVideo <> nil) then
+ begin
+ fBgVideo.GetFrame(VideoBGTimer.GetTime());
// FIXME: why do we draw on screen 2? Seems to be wrong.
- VideoPlayback.DrawGL(2);
+ fBgVideo.DrawGL(2);
+ end;
end;
// Implementation of TBGVideo
diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas
index 74c09b4f..5f39ec49 100644
--- a/src/screens/UScreenSing.pas
+++ b/src/screens/UScreenSing.pas
@@ -105,7 +105,8 @@ type
SungToEnd: boolean;
fShowVisualization: boolean;
- fCurrentVideoPlaybackEngine: IVideoPlayback;
+ fCurrentVideo: IVideo;
+ fVideoClip: IVideo;
// some settings to be set by plugins
settings: record
@@ -179,13 +180,14 @@ begin
fShowVisualization := not fShowVisualization;
if fShowVisualization then
- fCurrentVideoPlaybackEngine := Visualization
+ begin
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ fCurrentVideo.play;
+ end
else
- fCurrentVideoPlaybackEngine := VideoPlayback;
-
- if fShowVisualization then
- fCurrentVideoPlaybackEngine.play;
-
+ begin
+ fCurrentVideo := fVideoClip;
+ end;
Exit;
end;
Ord('P'):
@@ -216,7 +218,7 @@ begin
SDLK_TAB: // change visualization preset
begin
if fShowVisualization then
- fCurrentVideoPlaybackEngine.Position := now; // move to a random position
+ fCurrentVideo.Position := now; // move to a random position
end;
SDLK_RETURN:
@@ -254,7 +256,7 @@ begin
// pause video
VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
if (CurrentSong.Video.IsSet) and VideoFile.Exists then
- fCurrentVideoPlaybackEngine.Pause;
+ fCurrentVideo.Pause;
end
else // disable pause
@@ -267,7 +269,7 @@ begin
// video
VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
if (CurrentSong.Video.IsSet) and VideoFile.Exists then
- fCurrentVideoPlaybackEngine.Pause;
+ fCurrentVideo.Pause;
Paused := false;
end;
@@ -283,7 +285,7 @@ begin
fShowVisualization := false;
- fCurrentVideoPlaybackEngine := VideoPlayback;
+ fCurrentVideo := nil;
// create score class
Scores := TSingScores.Create;
@@ -358,8 +360,8 @@ begin
ClearSettings;
Party.CallBeforeSing;
- // reset video playback engine, to play Video Clip...
- fCurrentVideoPlaybackEngine := VideoPlayback;
+ // reset video playback engine
+ fCurrentVideo := nil;
// setup score manager
Scores.ClearPlayers; // clear old player values
@@ -480,10 +482,6 @@ begin
Exit;
end;
- // reset video playback engine, to play video clip ...
- fCurrentVideoPlaybackEngine.Close;
- fCurrentVideoPlaybackEngine := VideoPlayback;
-
{*
* == Background ==
* We have four types of backgrounds:
@@ -503,12 +501,13 @@ begin
VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
if (CurrentSong.Video.IsSet) and VideoFile.IsFile then
begin
- if (fCurrentVideoPlaybackEngine.Open(VideoFile)) then
+ fVideoClip := VideoPlayback.Open(VideoFile);
+ fCurrentVideo := fVideoClip;
+ if (fVideoClip <> nil) then
begin
fShowVisualization := false;
- fCurrentVideoPlaybackEngine := VideoPlayback;
- fCurrentVideoPlaybackEngine.Position := CurrentSong.VideoGAP + CurrentSong.Start;
- fCurrentVideoPlaybackEngine.Play;
+ fCurrentVideo.Position := CurrentSong.VideoGAP + CurrentSong.Start;
+ fCurrentVideo.Play;
VideoLoaded := true;
end;
end;
@@ -538,9 +537,9 @@ begin
if (TVisualizerOption(Ini.VisualizerOption) in [voOn]) then
begin
fShowVisualization := true;
- fCurrentVideoPlaybackEngine := Visualization;
- if (fCurrentVideoPlaybackEngine <> nil) then
- fCurrentVideoPlaybackEngine.Play;
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Play;
end;
{*
@@ -550,9 +549,9 @@ begin
(VideoLoaded = false)) then
begin
fShowVisualization := true;
- fCurrentVideoPlaybackEngine := Visualization;
- if (fCurrentVideoPlaybackEngine <> nil) then
- fCurrentVideoPlaybackEngine.Play;
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Play;
end;
// prepare lyrics timer
@@ -815,14 +814,14 @@ begin
// update and draw movie
if (ShowFinish and (VideoLoaded or fShowVisualization)) then
begin
- if assigned(fCurrentVideoPlaybackEngine) then
+ if assigned(fCurrentVideo) then
begin
// Just call this once
// when Screens = 2
if (ScreenAct = 1) then
- fCurrentVideoPlaybackEngine.GetFrame(CurrentSong.VideoGAP + LyricsState.GetCurrentTime());
+ fCurrentVideo.GetFrame(CurrentSong.VideoGAP + LyricsState.GetCurrentTime());
- fCurrentVideoPlaybackEngine.DrawGL(ScreenAct);
+ fCurrentVideo.DrawGL(ScreenAct);
end;
end;
@@ -902,15 +901,13 @@ begin
AudioPlayback.Stop;
AudioPlayback.SetSyncSource(nil);
- if (VideoPlayback <> nil) then
- VideoPlayback.Close;
-
- if (Visualization <> nil) then
- Visualization.Close;
-
// to prevent drawing closed video
VideoLoaded := false;
+ // close video files
+ fVideoClip := nil;
+ fCurrentVideo := nil;
+
// kill all stars and effects
GoldenRec.KillAll;