more sensible shader handling, incomplete but functional

add mixing modes
This commit is contained in:
Glenn Maynard
2007-02-19 23:40:19 +00:00
parent fd566a6355
commit ebf4bc5c0e
3 changed files with 128 additions and 127 deletions
+121 -126
View File
@@ -4,6 +4,7 @@
#include "RageDisplay_OGL_Helpers.h"
using namespace RageDisplay_OGL_Helpers;
#include "RageFile.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageUtil.h"
@@ -260,140 +261,124 @@ RString GetInfoLog( GLhandleARB h )
GLExt.glGetInfoLogARB( h, iLength, &iLength, pInfoLog );
RString sRet = pInfoLog;
delete [] pInfoLog;
TrimRight( sRet );
return sRet;
}
GLhandleARB CompileShader( GLenum ShaderType, RString sBuffer )
GLhandleARB CompileShader( GLenum ShaderType, RString sFile, vector<RString> asDefines )
{
GLhandleARB VertexShader = GLExt.glCreateShaderObjectARB( ShaderType );
const GLcharARB *pData = sBuffer.data();
int iLength = sBuffer.size();
GLExt.glShaderSourceARB( VertexShader, 1, &pData, (GLint*)&iLength );
RString sBuffer;
{
RageFile file;
if( !file.Open(sFile) )
{
LOG->Warn( "Error compiling shader %s: %s", sFile.c_str(), file.GetError().c_str() );
return 0;
}
if( file.Read(sBuffer, file.GetFileSize()) == -1 )
{
LOG->Warn( "Error compiling shader %s: %s", sFile.c_str(), file.GetError().c_str() );
return 0;
}
}
GLExt.glCompileShaderARB( VertexShader );
LOG->Trace( "Compiling shader %s", sFile.c_str() );
GLhandleARB hShader = GLExt.glCreateShaderObjectARB( ShaderType );
vector<const GLcharARB *> apData;
vector<GLint> aiLength;
FOREACH( RString, asDefines, s )
{
*s = ssprintf( "#define %s\n", s->c_str() );
apData.push_back( s->data() );
aiLength.push_back( s->size() );
}
apData.push_back( "#line 1\n" );
aiLength.push_back( 8 );
apData.push_back( sBuffer.data() );
aiLength.push_back( sBuffer.size() );
GLExt.glShaderSourceARB( hShader, apData.size(), &apData[0], &aiLength[0] );
GLExt.glCompileShaderARB( hShader );
RString sInfo = GetInfoLog( hShader );
GLint bCompileStatus = GL_FALSE;
GLExt.glGetObjectParameterivARB( VertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &bCompileStatus );
GLExt.glGetObjectParameterivARB( hShader, GL_OBJECT_COMPILE_STATUS_ARB, &bCompileStatus );
if( !bCompileStatus )
{
LOG->Trace( "Compile failure: %s", GetInfoLog( VertexShader ).c_str() );
LOG->Warn( "Error compiling shader %s:\n%s", sFile.c_str(), sInfo.c_str() );
GLExt.glDeleteObjectARB( hShader );
return 0;
}
return VertexShader;
if( !sInfo.empty() )
LOG->Trace( "Messages compiling shader %s:\n%s", sFile.c_str(), sInfo.c_str() );
return hShader;
}
int g_iAttribTextureMatrixScale;
/* XXX: How should we include these? Doing them like this is ugly. Linking them in
* from another file as a text symbol would be ideal, but that's completely different
* on each platform, so it'd be a maintenance nightmare. Reading them from a file would
* be annoying, too. */
const GLcharARB *g_TextureMatrixScaleShader =
" \
attribute vec4 TextureMatrixScale; \
void main( void ) \
{ \
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \
vec4 multiplied_tex_coord = gl_TextureMatrix[0] * gl_MultiTexCoord0; \
gl_TexCoord[0] = (multiplied_tex_coord * TextureMatrixScale) + \
(gl_MultiTexCoord0 * (vec4(1)-TextureMatrixScale)); \
gl_FrontColor = gl_Color; \
} \
";
void InitScalingScript()
GLhandleARB LoadShader( GLenum ShaderType, RString sFile, vector<RString> asDefines )
{
g_bTextureMatrixShader = 0;
if( !GLExt.m_bGL_ARB_fragment_shader && ShaderType == GL_FRAGMENT_SHADER_ARB )
return 0;
if( !GLExt.m_bGL_ARB_vertex_shader && ShaderType == GL_VERTEX_SHADER_ARB )
return 0;
if( !GLExt.m_bGL_ARB_shader_objects ||
!GLExt.m_bGL_ARB_vertex_shader ||
!GLExt.m_bGL_ARB_shading_language_100 )
return;
GLhandleARB hShader = CompileShader( ShaderType, sFile, asDefines );
if( hShader == 0 )
return 0;
GLhandleARB VertexShader = CompileShader( GL_VERTEX_SHADER_ARB, g_TextureMatrixScaleShader );
if( VertexShader == 0 )
return;
g_bTextureMatrixShader = GLExt.glCreateProgramObjectARB();
GLExt.glAttachObjectARB( g_bTextureMatrixShader, VertexShader );
GLExt.glDeleteObjectARB( VertexShader );
GLhandleARB hProgram = GLExt.glCreateProgramObjectARB();
GLExt.glAttachObjectARB( hProgram, hShader );
GLExt.glDeleteObjectARB( hShader );
// Link the program.
GLExt.glLinkProgramARB( g_bTextureMatrixShader );
GLExt.glLinkProgramARB( hProgram );
GLint bLinkStatus = false;
GLExt.glGetObjectParameterivARB( g_bTextureMatrixShader, GL_OBJECT_LINK_STATUS_ARB, &bLinkStatus );
GLExt.glGetObjectParameterivARB( hProgram, GL_OBJECT_LINK_STATUS_ARB, &bLinkStatus );
if( !bLinkStatus )
{
LOG->Trace( "Scaling shader link failed: %s", GetInfoLog(g_bTextureMatrixShader).c_str() );
GLExt.glDeleteObjectARB( g_bTextureMatrixShader );
return;
LOG->Warn( "Error linking shader %s: %s", sFile.c_str(), GetInfoLog(hProgram).c_str() );
GLExt.glDeleteObjectARB( hProgram );
return 0;
}
// Bind attributes.
g_iAttribTextureMatrixScale = GLExt.glGetAttribLocationARB( g_bTextureMatrixShader, "TextureMatrixScale" );
if( g_iAttribTextureMatrixScale == -1 )
{
LOG->Trace( "Scaling shader link failed: couldn't bind attribute \"TextureMatrixScale\"" );
GLExt.glDeleteObjectARB( g_bTextureMatrixShader );
g_bTextureMatrixShader = 0;
return;
}
GLExt.glVertexAttrib2fARB( g_iAttribTextureMatrixScale, 1, 1 );
return hProgram;
}
const GLcharARB *g_ColorBurnFragmentShader = " \
uniform sampler2D Texture1; \
uniform sampler2D Texture2; \
void main(void) \
{ \
vec4 color1 = texture2DProj( Texture1, gl_TexCoord[0] ); \
vec4 color2 = texture2DProj( Texture2, gl_TexCoord[0] ); \
\
/* Threshold to prevent division by zero: */ \
vec4 threshold = vec4(0.00001, 0.00001, 0.00001, 0.00001); \
vec4 color = 1-((1-color1) / max(color2, threshold)); \
color = (color * color1[3]) + (color2 * (1-color1[3]) ); \
color[3] = color2[3]; \
gl_FragColor = color; \
} \
";
static int g_iAttribTextureMatrixScale;
static GLhandleARB g_bColorBurnShader = 0;
void InitColorBurnScript()
static GLhandleARB g_bColorDodgeShader = 0;
static GLhandleARB g_bVividLightShader = 0;
static GLhandleARB g_hHardMixShader = 0;
void InitShaders()
{
g_bColorBurnShader = 0;
vector<RString> asDefines;
g_bTextureMatrixShader = LoadShader( GL_VERTEX_SHADER_ARB, "Data/Shaders/GLSL/Texture matrix scaling.vert", asDefines );
g_bColorBurnShader = LoadShader( GL_FRAGMENT_SHADER_ARB, "Data/Shaders/GLSL/Color burn.frag", asDefines );
g_bColorDodgeShader = LoadShader( GL_FRAGMENT_SHADER_ARB, "Data/Shaders/GLSL/Color dodge.frag", asDefines );
g_bVividLightShader = LoadShader( GL_FRAGMENT_SHADER_ARB, "Data/Shaders/GLSL/Vivid light.frag", asDefines );
g_hHardMixShader = LoadShader( GL_FRAGMENT_SHADER_ARB, "Data/Shaders/GLSL/Hard mix.frag", asDefines );
if( !GLExt.m_bGL_ARB_shader_objects ||
!GLExt.m_bGL_ARB_fragment_shader ||
!GLExt.m_bGL_ARB_shading_language_100 )
return;
GLhandleARB FragmentShader = CompileShader( GL_FRAGMENT_SHADER_ARB, g_ColorBurnFragmentShader );
if( FragmentShader == 0 )
// Bind attributes.
if( g_bTextureMatrixShader )
{
GLExt.glDeleteObjectARB( FragmentShader );
return;
}
AssertNoGLError();
g_bColorBurnShader = GLExt.glCreateProgramObjectARB();
GLExt.glAttachObjectARB( g_bColorBurnShader, FragmentShader );
GLExt.glDeleteObjectARB( FragmentShader );
// Link the program.
GLExt.glLinkProgramARB( g_bColorBurnShader );
GLint bLinkStatus = false;
GLExt.glGetObjectParameterivARB( g_bColorBurnShader, GL_OBJECT_LINK_STATUS_ARB, &bLinkStatus );
if( !bLinkStatus )
{
LOG->Trace( "Color burn shader link failed: %s", GetInfoLog(g_bColorBurnShader).c_str() );
GLExt.glDeleteObjectARB( g_bColorBurnShader );
return;
g_iAttribTextureMatrixScale = GLExt.glGetAttribLocationARB( g_bTextureMatrixShader, "TextureMatrixScale" );
if( g_iAttribTextureMatrixScale == -1 )
{
LOG->Trace( "Scaling shader link failed: couldn't bind attribute \"TextureMatrixScale\"" );
GLExt.glDeleteObjectARB( g_bTextureMatrixShader );
g_bTextureMatrixShader = 0;
}
else
{
GLExt.glVertexAttrib2fARB( g_iAttribTextureMatrixScale, 1, 1 );
AssertNoGLError();
}
}
}
@@ -422,7 +407,6 @@ RString RageDisplay_OGL::Init( const VideoModeParams &p, bool bAllowUnaccelerate
const char *szExtensionString = (const char *) glGetString(GL_EXTENSIONS);
vector<RString> asExtensions;
split( szExtensionString, " ", asExtensions );
sort( asExtensions.begin(), asExtensions.end() );
size_t iNextToPrint = 0;
while( iNextToPrint < asExtensions.size() )
{
@@ -707,8 +691,7 @@ RString RageDisplay_OGL::TryVideoMode( const VideoModeParams &p, bool &bNewDevic
/* Recreate all vertex buffers. */
InvalidateAllGeometry();
InitScalingScript();
InitColorBurnScript();
InitShaders();
}
/* Set vsync the Windows way, if we can. (What other extensions are there
@@ -827,6 +810,14 @@ static void SetupVertices( const RageSpriteVertex v[], int iNumVerts )
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 0, Texture );
if( GLExt.glClientActiveTextureARB != NULL )
{
GLExt.glClientActiveTextureARB( GL_TEXTURE1_ARB );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 0, Texture );
GLExt.glClientActiveTextureARB( GL_TEXTURE0_ARB );
}
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer( GL_FLOAT, 0, Normal );
}
@@ -1554,35 +1545,39 @@ void RageDisplay_OGL::SetTextureFiltering( TextureUnit tu, bool b )
void RageDisplay_OGL::SetEffectMode( EffectMode effect )
{
if( GLExt.glUseProgramObjectARB == NULL )
return;
GLhandleARB hShader = 0;
switch( effect )
{
case EffectMode_Normal:
if( GLExt.glUseProgramObjectARB != NULL )
GLExt.glUseProgramObjectARB( 0 );
break;
case EffectMode_ColorBurn:
if( !g_bColorBurnShader )
break; // unsupported
FlushGLErrors();
GLExt.glUseProgramObjectARB( g_bColorBurnShader );
GLint g_bColorBurnShaderTexture1 = GLExt.glGetUniformLocationARB( g_bColorBurnShader, "Texture1" );
GLint g_bColorBurnShaderTexture2 = GLExt.glGetUniformLocationARB( g_bColorBurnShader, "Texture2" );
GLExt.glUniform1iARB( g_bColorBurnShaderTexture1, 0 );
GLExt.glUniform1iARB( g_bColorBurnShaderTexture2, 1 );
AssertNoGLError();
break;
case EffectMode_Normal: hShader = 0; break;
case EffectMode_ColorBurn: hShader = g_bColorBurnShader; break;
case EffectMode_ColorDodge: hShader = g_bColorDodgeShader; break;
case EffectMode_VividLight: hShader = g_bVividLightShader; break;
case EffectMode_HardMix: hShader = g_hHardMixShader; break;
}
FlushGLErrors();
GLExt.glUseProgramObjectARB( hShader );
if( hShader == 0 )
return;
GLint iTexture1 = GLExt.glGetUniformLocationARB( hShader, "Texture1" );
GLint iTexture2 = GLExt.glGetUniformLocationARB( hShader, "Texture2" );
GLExt.glUniform1iARB( iTexture1, 0 );
GLExt.glUniform1iARB( iTexture2, 1 );
AssertNoGLError();
}
bool RageDisplay_OGL::IsEffectModeSupported( EffectMode effect )
{
switch( effect )
{
case EffectMode_Normal:
return true;
case EffectMode_ColorBurn:
return g_bColorBurnShader != 0;
case EffectMode_Normal: return true;
case EffectMode_ColorBurn: return g_bColorBurnShader != 0;
case EffectMode_ColorDodge: return g_bColorDodgeShader != 0;
case EffectMode_VividLight: return g_bVividLightShader != 0;
case EffectMode_HardMix: return g_hHardMixShader != 0;
}
return false;
+4 -1
View File
@@ -96,8 +96,11 @@ static const char *EffectModeNames[] =
/* Normal blending. All supported texture modes have their standard effects. */
"Normal",
/* Color burn blending. */
/* Layered blending. */
"ColorBurn",
"ColorDodge",
"VividLight",
"HardMix",
};
XToString( EffectMode );
LuaXType( EffectMode );
+3
View File
@@ -38,6 +38,9 @@ enum EffectMode
{
EffectMode_Normal,
EffectMode_ColorBurn,
EffectMode_ColorDodge,
EffectMode_VividLight,
EffectMode_HardMix,
NUM_EffectMode,
EffectMode_Invalid
};