From 65cd744909a51e2c9adcfbd3bbbeee096b35b111 Mon Sep 17 00:00:00 2001 From: tobigun Date: Mon, 17 Dec 2007 16:40:13 +0000 Subject: - faster preset switching - added projectM 1.0 support git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@715 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UVisualizer.pas | 761 +++++++++++++++++++------------------- 1 file changed, 378 insertions(+), 383 deletions(-) diff --git a/Game/Code/Classes/UVisualizer.pas b/Game/Code/Classes/UVisualizer.pas index 6548e2b7..5fc4bb82 100644 --- a/Game/Code/Classes/UVisualizer.pas +++ b/Game/Code/Classes/UVisualizer.pas @@ -1,383 +1,378 @@ -{############################################################################ -# 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; - -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; - - RndPCMcount : integer; - - procedure VisualizerStart; - procedure VisualizerStop; - - procedure VisualizerTogglePause; - - function GetRandomPCMData(var data: TPCMData): Cardinal; - 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 - RndPCMcount := 0; -end; - - -procedure TVideoPlayback_ProjectM.init(); -begin - 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); - - if nSamples = 0 then - nSamples := GetRandomPCMData(PcmData); - - addPCM16Data(PPCM16Data(@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 - try - renderFrame(pm); - except - // This happens with some presets... ( and only some times also .. moreso on linux ) - // if we have an "Invalid Floating Point Error" while rendering a frame... then change preset. - MoveTo( now ); - - // hmm have to be careful, that we dont get to many here... coz it could keep failing.. and trying again. - end; - 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; - -function TVideoPlayback_ProjectM.GetRandomPCMData(var data: TPCMData): Cardinal; -var - i: integer; -begin - // Produce some fake PCM data - if ( RndPCMcount mod 500 = 0 ) then - begin - for i := 0 to 511 do begin - data[0][i] := 0; - data[1][i] := 0; - end; - end - else begin - for i := 0 to 511 do begin - if ( i mod 2 = 0 ) then begin - data[0][i] := floor(Random * power(2.,14)); - data[1][i] := floor(Random * power(2.,14)); - end - else begin; - data[0][i] := floor(Random * power(2.,14)); - data[1][i] := floor(Random * power(2.,14)); - end; - if ( i mod 2 = 1 ) then begin - data[0][i] := -data[0][i]; - data[1][i] := -data[1][i]; - end; - end; - end; - Inc( RndPCMcount ); - result := 512; -end; - - -initialization - singleton_VideoProjectM := TVideoPlayback_ProjectM.create(); - AudioManager.add( singleton_VideoProjectM ); - -finalization - AudioManager.Remove( singleton_VideoProjectM ); - - - -end. +{############################################################################ +# 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} + +{$I switches.inc} + +uses + SDL, + UGraphicClasses, + textgl, + math, + OpenGL12, + SysUtils, + UIni, + {$ifdef DebugDisplay} + {$ifdef win32} + dialogs, + {$endif} + {$endif} + projectM, + UMusic; + +implementation + +uses + UGraphic, + ULog; + +var + singleton_VideoProjectM : IVideoPlayback; + +const + gx = 32; + gy = 24; + fps = 30; + texsize = 512; + visualsDir = 'Visuals'; // TODO: move this to a place common for all visualizers + projectMDir = visualsDir+'/projectM'; + presetsDir = projectMDir+'/presets'; + fontsDir = projectMDir+'/fonts'; + +type + TVideoPlayback_ProjectM = class( TInterfacedObject, IVideoPlayback, IVideoVisualization ) + private + pm : TProjectM; + + VisualizerStarted , + VisualizerPaused : Boolean; + + VisualTex : glUint; + PCMData : TPCMData; + hRC : Integer; + hDC : Integer; + + RndPCMcount : integer; + + projMatrix: array[0..3, 0..3] of GLdouble; + texMatrix: array[0..3, 0..3] of GLdouble; + + procedure VisualizerStart; + procedure VisualizerStop; + + procedure VisualizerTogglePause; + + function GetRandomPCMData(var data: TPCMData): Cardinal; + + procedure SaveOpenGLState(); + procedure RestoreOpenGLState(); + + 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 + RndPCMcount := 0; +end; + + +procedure TVideoPlayback_ProjectM.init(); +begin + VisualizerStarted := False; + VisualizerPaused := False; + + {$IFDEF UseTexture} + 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); + {$ENDIF} +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 + pm.RandomPreset(); +end; + +function TVideoPlayback_ProjectM.getPosition: real; +begin + result := 0; +end; + +procedure TVideoPlayback_ProjectM.SaveOpenGLState(); +begin + // save all OpenGL state-machine attributes + glPushAttrib(GL_ALL_ATTRIB_BITS); + + // save projection-matrix + glMatrixMode(GL_PROJECTION); + // - WARNING: projection-matrix stack-depth is only 2! + // -> overflow might occur if glPopMatrix() is used for this matrix + // -> use glGet() instead of glPushMatrix() + glPushMatrix(); + //glGetDoublev(GL_PROJECTION_MATRIX, @projMatrix); + + // save texture-matrix + glMatrixMode(GL_TEXTURE); + // - WARNING: texture-matrix stack-depth is only 2! + // -> overflow might occur if glPopMatrix() is used for this matrix + // -> use glGet() instead of glPushMatrix() if problems appear + glPushMatrix(); + //glGetDoublev(GL_TEXTURE_MATRIX, @texMatrix); + + // save modelview-matrix + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +end; + +procedure TVideoPlayback_ProjectM.RestoreOpenGLState(); +begin + // restore projection-matrix + glMatrixMode(GL_PROJECTION); + // - WARNING: projection-matrix stack-depth is only 2! + // -> overflow _occurs_ if glPopMatrix() is used for this matrix + // -> use glLoadMatrix() instead of glPopMatrix() + glPopMatrix(); + //glLoadMatrixd(@projMatrix); + + // restore texture-matrix + // -> overflow might occur if glPopMatrix() is used for this matrix + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + //glLoadMatrixd(@texMatrix); + + // restore modelview-matrix + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + // restore all OpenGL state-machine attributes + glPopAttrib(); +end; + +procedure TVideoPlayback_ProjectM.VisualizerStart; +var + initResult: Cardinal; +begin + VisualizerStarted := True; + + pm := TProjectM.Create(gx, gy, fps, texsize, ScreenW, ScreenH, + presetsDir, fontsDir); + //initResult := projectM_initRenderToTexture(pm); + + SaveOpenGLState(); + pm.ResetGL(ScreenW, ScreenH); + RestoreOpenGLState(); +end; + +procedure TVideoPlayback_ProjectM.VisualizerStop; +begin + if VisualizerStarted then begin + VisualizerStarted := False; + pm.Free(); + end; +end; + +procedure TVideoPlayback_ProjectM.VisualizerTogglePause; +begin + VisualizerPaused := not VisualizerPaused; +end; + +procedure TVideoPlayback_ProjectM.GetFrame(Time: Extended); +var + i: integer; + nSamples: cardinal; + stackDepth: Integer; +begin + if not VisualizerStarted then Exit; + if VisualizerPaused then Exit; + + // get audio data + nSamples := AudioPlayback.GetPCMData(PcmData); + + if nSamples = 0 then + nSamples := GetRandomPCMData(PcmData); + + pm.AddPCM16Data(PSmallint(@PcmData), nSamples); + + // store OpenGL state (might be messed up otherwise) + SaveOpenGLState(); + pm.ResetGL(ScreenW, ScreenH); + + //glGetIntegerv(GL_PROJECTION_STACK_DEPTH, @stackDepth); + //writeln('StackDepth0: ' + inttostr(stackDepth)); + + // let projectM render a frame + try + pm.RenderFrame(); + except + // this may happen with some presets ( on linux ) if there is a div by zero + // in projectM's getBeatVals() function (file: beat_detect.cc) + Log.LogStatus('Div by zero!', 'Visualizer'); + MoveTo( now ); + end; + + //glGetIntegerv(GL_PROJECTION_STACK_DEPTH, @stackDepth); + //writeln('StackDepth1: ' + inttostr(stackDepth)); + + {$IFDEF UseTexture} + glBindTexture(GL_TEXTURE_2D, VisualTex); + glFlush(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, VisualWidth, VisualHeight, 0); + {$ENDIF} + + // restore USDX OpenGL state + RestoreOpenGLState(); + + // 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(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + // restore state + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + {$ENDIF} +end; + +function TVideoPlayback_ProjectM.GetRandomPCMData(var data: TPCMData): Cardinal; +var + i: integer; +begin + // Produce some fake PCM data + if ( RndPCMcount mod 500 = 0 ) then + begin + for i := 0 to 511 do begin + data[0][i] := 0; + data[1][i] := 0; + end; + end + else begin + for i := 0 to 511 do begin + if ( i mod 2 = 0 ) then begin + data[0][i] := floor(Random * power(2.,14)); + data[1][i] := floor(Random * power(2.,14)); + end + else begin; + data[0][i] := floor(Random * power(2.,14)); + data[1][i] := floor(Random * power(2.,14)); + end; + if ( i mod 2 = 1 ) then begin + data[0][i] := -data[0][i]; + data[1][i] := -data[1][i]; + end; + end; + end; + Inc( RndPCMcount ); + result := 512; +end; + + +initialization + singleton_VideoProjectM := TVideoPlayback_ProjectM.create(); + AudioManager.add( singleton_VideoProjectM ); + +finalization + AudioManager.Remove( singleton_VideoProjectM ); + + + +end. -- cgit v1.2.3