aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code
diff options
context:
space:
mode:
Diffstat (limited to 'Game/Code')
-rw-r--r--Game/Code/Classes/UGraphic.pas1
-rw-r--r--Game/Code/Classes/UVisualizer.pas156
2 files changed, 110 insertions, 47 deletions
diff --git a/Game/Code/Classes/UGraphic.pas b/Game/Code/Classes/UGraphic.pas
index fdc7fca0..2432503c 100644
--- a/Game/Code/Classes/UGraphic.pas
+++ b/Game/Code/Classes/UGraphic.pas
@@ -413,6 +413,7 @@ begin
// Other extensions e.g. OpenGL 1.3-2.0 or Framebuffer-Object might be loaded here
// ...
+ //Load_GL_EXT_framebuffer_object();
end;
procedure Initialize3D (Title: string);
diff --git a/Game/Code/Classes/UVisualizer.pas b/Game/Code/Classes/UVisualizer.pas
index 6864b6b9..e2125201 100644
--- a/Game/Code/Classes/UVisualizer.pas
+++ b/Game/Code/Classes/UVisualizer.pas
@@ -10,6 +10,23 @@ unit UVisualizer;
* - write a plugin for projectM in C/C++ (so we need no wrapper anymore)
*)
+{* Note:
+ * It would be easier to create a seperate Render-Context (RC) for projectM
+ * and switch to it when necessary. This can be achieved by pbuffers
+ * (slow and platform specific) or the OpenGL FramebufferObject (FBO) extension
+ * (fast and plattform-independent but not supported by older graphic-cards/drivers).
+ *
+ * See http://oss.sgi.com/projects/ogl-sample/registry/EXT/framebuffer_object.txt
+ *
+ * To support as many cards as possible we will stick to the current dirty
+ * solution for now even if it is a pain to save/restore projectM's state due
+ * to bugs etc.
+ *
+ * This also restricts us to projectM. As other plug-ins might have different
+ * needs and bugs concerning the OpenGL state, USDX's state would probably be
+ * corrupted after the plug-in finshed drawing.
+ *}
+
interface
{$IFDEF FPC}
@@ -38,6 +55,8 @@ uses
ULog;
{$IF PROJECTM_VERSION < 1000000} // < 1.0
+// Initialization data used on projectM 0.9x creation.
+// Since projectM 1.0 this data is passed via the config-file.
const
meshX = 32;
meshY = 24;
@@ -95,7 +114,7 @@ type
function TVideoPlayback_ProjectM.GetName: String;
begin
- result := 'ProjectM';
+ Result := 'ProjectM';
end;
function TVideoPlayback_ProjectM.Init(): boolean;
@@ -133,7 +152,7 @@ end;
function TVideoPlayback_ProjectM.Open(const aFileName : string): boolean; // true if succeed
begin
- result := false;
+ Result := false;
end;
procedure TVideoPlayback_ProjectM.Close;
@@ -159,14 +178,25 @@ end;
procedure TVideoPlayback_ProjectM.SetPosition(Time: real);
begin
if assigned(pm) then
- pm.NextPreset();
+ pm.RandomPreset();
end;
function TVideoPlayback_ProjectM.GetPosition: real;
begin
- result := 0;
+ Result := 0;
end;
+{**
+ * Saves the current OpenGL state.
+ * This is necessary to prevent projectM from corrupting USDX's current
+ * OpenGL state.
+ *
+ * The following steps are performed:
+ * - All attributes are pushed to the attribute-stack
+ * - Projection-/Texture-matrices are saved
+ * - Modelview-matrix is pushed to the Modelview-stack
+ * - the OpenGL error-state (glGetError) is cleared
+ *}
procedure TVideoPlayback_ProjectM.SaveOpenGLState();
begin
// save all OpenGL state-machine attributes
@@ -177,12 +207,12 @@ begin
// already uses 2 stack-entries so overflows might be possible on older hardware.
// In contrast to this the GL_MODELVIEW stack-size is at least 32, so we can
// use glPushMatrix() for this stack.
-
+
// save projection-matrix
glMatrixMode(GL_PROJECTION);
glGetDoublev(GL_PROJECTION_MATRIX, @projMatrix);
- {$IF (PROJECTM_VERSION >= 1000000) and (PROJECTM_VERSION < 1010000)} // [1.0..1.1)
- // bugfix (1.0 and 1.01): projection-matrix is popped without being pushed first
+ {$IF PROJECTM_VERSION = 1000000} // 1.0, 1.01
+ // bugfix: projection-matrix is popped without being pushed first
glPushMatrix();
{$IFEND}
@@ -193,14 +223,24 @@ begin
// save modelview-matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- {$IF (PROJECTM_VERSION >= 1000000) and (PROJECTM_VERSION < 1010000)} // [1.0..1.1)
- // bugfix (1.0 and 1.01): modelview-matrix is popped without being pushed first
+ {$IF PROJECTM_VERSION = 1000000} // 1.0, 1.01
+ // bugfix: modelview-matrix is popped without being pushed first
glPushMatrix();
{$IFEND}
+
+ // reset OpenGL error-state
+ glGetError();
end;
+{**
+ * Restores the OpenGL state saved by SaveOpenGLState()
+ * and resets the error-state.
+ *}
procedure TVideoPlayback_ProjectM.RestoreOpenGLState();
begin
+ // reset OpenGL error-state
+ glGetError();
+
// restore projection-matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixd(@projMatrix);
@@ -218,36 +258,45 @@ begin
end;
procedure TVideoPlayback_ProjectM.VisualizerStart;
-var
- initResult: Cardinal;
begin
if VisualizerStarted then
Exit;
+ // the OpenGL state must be saved before
+ SaveOpenGLState();
try
- {$IF PROJECTM_VERSION >= 1000000} // >= 1.0
- pm := TProjectM.Create(ProjectMPath + 'config.inp');
- {$ELSE}
- pm := TProjectM.Create(
- meshX, meshY, fps, textureSize, ScreenW, ScreenH,
- ProjectMPath + 'presets', ProjectMPath + 'fonts');
- {$IFEND}
- except on E: Exception do
- begin
- // Create() might fail if the config-file is not found
- Log.LogError('TProjectM.Create: ' + E.Message, 'TVideoPlayback_ProjectM.VisualizerStart');
- Exit;
- end;
- end;
- VisualizerStarted := True;
+ try
+ {$IF PROJECTM_VERSION >= 1000000} // >= 1.0
+ pm := TProjectM.Create(ProjectMPath + 'config.inp');
+ {$ELSE}
+ pm := TProjectM.Create(
+ meshX, meshY, fps, textureSize, ScreenW, ScreenH,
+ ProjectMPath + 'presets', ProjectMPath + 'fonts');
+ {$IFEND}
+ except on E: Exception do
+ begin
+ // Create() might fail if the config-file is not found
+ Log.LogError('TProjectM.Create: ' + E.Message, 'TVideoPlayback_ProjectM.VisualizerStart');
+ Exit;
+ end;
+ end;
- // skip projectM preset
- pm.RandomPreset();
- // initialize OpenGL
- SaveOpenGLState();
- pm.ResetGL(ScreenW, ScreenH);
- RestoreOpenGLState();
+ // initialize OpenGL
+ pm.ResetGL(ScreenW, ScreenH);
+ // skip projectM default-preset
+ pm.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();
+
+ VisualizerStarted := True;
+ finally
+ RestoreOpenGLState();
+ end;
end;
procedure TVideoPlayback_ProjectM.VisualizerStop;
@@ -278,32 +327,41 @@ begin
// get audio data
nSamples := AudioPlayback.GetPCMData(PcmData);
+ // generate some data if non is available
if (nSamples = 0) then
nSamples := GetRandomPCMData(PcmData);
+ // send audio-data to projectM
if (nSamples > 0) then
pm.AddPCM16Data(PSmallInt(@PcmData), nSamples);
// store OpenGL state (might be messed up otherwise)
SaveOpenGLState();
- pm.ResetGL(ScreenW, ScreenH);
-
- // let projectM render a frame
- pm.RenderFrame();
-
- {$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();
+ try
+ // setup projectM's OpenGL state
+ pm.ResetGL(ScreenW, ScreenH);
+
+ // let projectM render a frame
+ pm.RenderFrame();
+
+ {$IFDEF UseTexture}
+ glBindTexture(GL_TEXTURE_2D, VisualTex);
+ glFlush();
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, VisualWidth, VisualHeight, 0);
+ {$ENDIF}
+ finally
+ // restore USDX OpenGL state
+ RestoreOpenGLState();
+ end;
// discard projectM's depth buffer information (avoid overlay)
glClear(GL_DEPTH_BUFFER_BIT);
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);
begin
{$IFDEF UseTexture}
@@ -313,7 +371,7 @@ 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;
@@ -352,6 +410,10 @@ begin
{$ENDIF}
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;
var
i: integer;
@@ -370,7 +432,7 @@ begin
end;
end;
Inc(RndPCMcount);
- result := 512;
+ Result := 512;
end;