{############################################################################
# Visualizer support for UltraStar deluxe #
# #
# Created by hennymcc #
# Slight modifications by Jay Binks #
# based on UVideo.pas #
#############################################################################}
unit UVisualizer;
interface
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
uses SDL,
UGraphicClasses,
textgl,
math,
OpenGL12,
SysUtils,
UIni,
{$ifdef DebugDisplay}
dialogs,
{$ENDIF}
projectM,
UMusic,
windows;
implementation
uses
UGraphic;
var
singleton_VideoProjectM : IVideoPlayback;
const
gx = 32;
gy = 24;
fps = 30;
texsize = 512;
visuals_Dir = 'Visuals'; // TODO: move this to a place common for all visualizers
projectM_Dir = visuals_Dir+'/projectM';
type
TVideoPlayback_ProjectM = class( TInterfacedObject, IVideoPlayback, IVideoVisualization )
pm : PProjectM;
VisualizerStarted ,
VisualizerPaused : Boolean;
VisualTex : glUint;
PCMData : TPCMData;
hRC : Integer;
hDC : Integer;
procedure VisualizerStart;
procedure VisualizerStop;
procedure VisualizerTogglePause;
public
constructor create();
procedure init();
function GetName: String;
function Open( aFileName : string): boolean; // true if succeed
procedure Close;
procedure Play;
procedure Pause;
procedure Stop;
procedure MoveTo(Time: real);
function getPosition: real;
procedure GetFrame(Time: Extended);
procedure DrawGL(Screen: integer);
end;
constructor TVideoPlayback_ProjectM.create();
begin
end;
procedure TVideoPlayback_ProjectM.init();
begin
writeln( 'TVideoPlayback_ProjectM - INITIALIZE !!!!!!!!' );
VisualizerStarted := False;
VisualizerPaused := False;
glGenTextures(1, PglUint(@VisualTex));
glBindTexture(GL_TEXTURE_2D, VisualTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
end;
function TVideoPlayback_ProjectM.GetName: String;
begin
result := 'ProjectM';
end;
function TVideoPlayback_ProjectM.Open( aFileName : string): boolean; // true if succeed
begin
VisualizerStart();
result := true;
end;
procedure TVideoPlayback_ProjectM.Close;
begin
end;
procedure TVideoPlayback_ProjectM.Play;
begin
VisualizerStart();
end;
procedure TVideoPlayback_ProjectM.Pause;
begin
VisualizerTogglePause();
end;
procedure TVideoPlayback_ProjectM.Stop;
begin
VisualizerStop();
end;
procedure TVideoPlayback_ProjectM.MoveTo(Time: real);
begin
// this code MAY be able to be cut down... but Im not 100% sure..
// in here, we cant realy move to a specific time, since its all random generated
// but a call to this function will change the preset, which changes the pattern
projectM_reset(pm);
pm^.fullscreen := 0;
pm^.renderTarget^.texsize := texsize;
pm^.gx := gx;
pm^.gy := gy;
pm^.fps := fps;
pm^.renderTarget^.usePbuffers := 0;
pm^.fontURL := PChar(projectM_Dir+'/fonts');
pm^.presetURL := PChar(projectM_Dir+'/presets');
glPushAttrib(GL_ALL_ATTRIB_BITS);
projectM_init(pm);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
projectM_resetGL(pm, ScreenW, ScreenH);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glPopAttrib();
end;
function TVideoPlayback_ProjectM.getPosition: real;
begin
result := 0;
end;
procedure TVideoPlayback_ProjectM.VisualizerStart;
begin
VisualizerStarted := True;
New(pm);
projectM_reset(pm);
pm^.fullscreen := 0;
pm^.renderTarget^.texsize := texsize;
pm^.gx := gx;
pm^.gy := gy;
pm^.fps := fps;
pm^.renderTarget^.usePbuffers := 0;
pm^.fontURL := PChar(projectM_Dir+'/fonts');
pm^.presetURL := PChar(projectM_Dir+'/presets');
glPushAttrib(GL_ALL_ATTRIB_BITS);
projectM_init(pm);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
projectM_resetGL(pm, ScreenW, ScreenH);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glPopAttrib();
end;
procedure TVideoPlayback_ProjectM.VisualizerStop;
begin
if VisualizerStarted then begin
VisualizerStarted := False;
Dispose(pm);
end;
end;
procedure TVideoPlayback_ProjectM.VisualizerTogglePause;
begin
VisualizerPaused := not VisualizerPaused;
end;
procedure TVideoPlayback_ProjectM.GetFrame(Time: Extended);
var
i: integer;
nSamples: cardinal;
begin
if not VisualizerStarted then Exit;
if VisualizerPaused then Exit;
// get audio data
nSamples := AudioPlayback.GetPCMData(PcmData);
addPCM16Data(PSmallInt(@PcmData), nSamples);
// store OpenGL state (might be messed up otherwise)
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(GL_TEXTURE);
glPushMatrix();
// let projectM render a frame
renderFrame(pm);
glFlush();
{$IFDEF UseTexture}
glBindTexture(GL_TEXTURE_2D, VisualTex);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, VisualWidth, VisualHeight, 0);
{$ENDIF}
// restore USDX OpenGL state
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glPopAttrib();
// discard projectM's depth buffer information (avoid overlay)
glClear(GL_DEPTH_BUFFER_BIT);
end;
procedure TVideoPlayback_ProjectM.DrawGL(Screen: integer);
begin
{$IFDEF UseTexture}
// have a nice black background to draw on (even if there were errors opening the vid)
if Screen=1 then begin
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;
// exit if there's nothing to draw
if not VisualizerStarted then Exit;
// setup display
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 1, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, VisualTex);
glColor4f(1, 1, 1, 1);
// draw projectM frame
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(1, 0);
glTexCoord2f(1, 1); glVertex2f(1, 1);
glTexCoord2f(0, 1); glVertex2f(0, 1);
glEnd();
{
glbegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(400-VisualWidth/2, 300-VisualHeight/2);
glTexCoord2f(0, 1);
glVertex2f(400-VisualWidth/2, 300+VisualHeight/2);
glTexCoord2f(1, 1);
glVertex2f(400+VisualWidth/2, 300+VisualHeight/2);
glTexCoord2f(1, 0);
glVertex2f(400+VisualWidth/2, 300-VisualHeight/2);
glEnd;
}
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
// restore state
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
{$ENDIF}
end;
initialization
singleton_VideoProjectM := TVideoPlayback_ProjectM.create();
writeln( 'UVideoProjectM - Register Playback' );
AudioManager.add( singleton_VideoProjectM );
finalization
AudioManager.Remove( singleton_VideoProjectM );
end.