From 588f2a31ffc6ae087cf08cd0c4a44fccb9767119 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Tue, 1 Feb 2005 03:04:32 +0000 Subject: [PATCH] implement TextureMatrixScale with a vertex shader --- stepmania/src/RageDisplay_OGL.cpp | 152 ++++++++++++++++++- stepmania/src/RageDisplay_OGL_Extensions.cpp | 64 ++++++++ stepmania/src/RageDisplay_OGL_Extensions.h | 25 +++ 3 files changed, 238 insertions(+), 3 deletions(-) diff --git a/stepmania/src/RageDisplay_OGL.cpp b/stepmania/src/RageDisplay_OGL.cpp index 219212dd42..98410ebd05 100644 --- a/stepmania/src/RageDisplay_OGL.cpp +++ b/stepmania/src/RageDisplay_OGL.cpp @@ -92,6 +92,8 @@ set g_glExts; * no GL_T2F_C4F_V3F. */ const GLenum RageSpriteVertexFormat = GL_T2F_C4F_N3F_V3F; +/* If we support texture matrix scaling, a handle to the vertex program: */ +static GLhandleARB g_bTextureMatrixShader = NULL; LowLevelWindow *wind; @@ -348,6 +350,98 @@ RageDisplay_OGL::RageDisplay_OGL() wind = NULL; } +CString GetInfoLog( GLhandleARB h ) +{ + GLint iLength; + GLExt.glGetObjectParameterivARB( h, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iLength ); + if( !iLength ) + return ""; + + GLcharARB *pInfoLog = new GLcharARB[iLength]; + GLExt.glGetInfoLogARB( h, iLength, &iLength, pInfoLog ); + CString sRet = pInfoLog; + delete [] pInfoLog; + return sRet; +} + +GLhandleARB CompileShader( GLenum ShaderType, CString sBuffer ) +{ + GLhandleARB VertexShader = GLExt.glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB ); + const GLcharARB *pData = sBuffer.data(); + int iLength = sBuffer.size(); + GLExt.glShaderSourceARB( VertexShader, 1, &pData, &iLength ); + + GLExt.glCompileShaderARB( VertexShader ); + + GLint bCompileStatus = GL_FALSE; + GLExt.glGetObjectParameterivARB( VertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &bCompileStatus ); + + if( !bCompileStatus ) + { + LOG->Trace( "Compile failure: %s", GetInfoLog( VertexShader ).c_str() ); + return NULL; + } + + return VertexShader; +} + +enum +{ + ATTRIB_TEXTURE_MATRIX_SCALE = 1 +}; + +/* 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 * (1-TextureMatrixScale)); \ + gl_FrontColor = gl_Color; \ +} \ +"; + +void InitScalingScript() +{ + g_bTextureMatrixShader = NULL; + + if( !GLExt.m_bGL_ARB_shader_objects || + !GLExt.m_bGL_ARB_vertex_shader || + !GLExt.m_bGL_ARB_shading_language_100 ) + return; + + GLhandleARB VertexShader = CompileShader( GL_VERTEX_SHADER_ARB, g_TextureMatrixScaleShader ); + if( VertexShader == NULL ) + return; + + g_bTextureMatrixShader = GLExt.glCreateProgramObjectARB(); + GLExt.glAttachObjectARB( g_bTextureMatrixShader, VertexShader ); + GLExt.glDeleteObjectARB( VertexShader ); + + // Bind attributes. + GLExt.glBindAttribLocationARB( g_bTextureMatrixShader, ATTRIB_TEXTURE_MATRIX_SCALE, "TextureMatrixScale" ); + + // Link the program. + GLExt.glLinkProgramARB( g_bTextureMatrixShader ); + GLint bLinkStatus = false; + GLExt.glGetObjectParameterivARB( g_bTextureMatrixShader, 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; + } + + GLExt.glVertexAttrib2fARB( ATTRIB_TEXTURE_MATRIX_SCALE, 1, 1 ); +} + CString RageDisplay_OGL::Init( VideoModeParams p, bool bAllowUnacceleratedRenderer ) { wind = MakeLowLevelWindow(); @@ -404,6 +498,8 @@ CString RageDisplay_OGL::Init( VideoModeParams p, bool bAllowUnacceleratedRender glGetFloatv(GL_POINT_SIZE_RANGE, g_point_range); glGetFloatv(GL_POINT_SIZE_GRANULARITY, &g_point_granularity); + InitScalingScript(); + return ""; } @@ -797,6 +893,7 @@ public: m_vPosition.resize( GetTotalVertices() ); m_vTexture.resize( GetTotalVertices() ); m_vNormal.resize( GetTotalVertices() ); + m_vTexMatrixScale.resize( GetTotalVertices() ); m_vTriangles.resize( GetTotalTriangles() ); } void Change( const vector &vMeshes ) @@ -813,6 +910,7 @@ public: m_vPosition[meshInfo.iVertexStart+j] = Vertices[j].p; m_vTexture[meshInfo.iVertexStart+j] = Vertices[j].t; m_vNormal[meshInfo.iVertexStart+j] = Vertices[j].n; + m_vTexMatrixScale[meshInfo.iVertexStart+j] = Vertices[j].TextureMatrixScale; } for( unsigned j=0; j m_vTexture; vector m_vNormal; vector m_vTriangles; + vector m_vTexMatrixScale; }; class RageCompiledGeometryHWOGL : public RageCompiledGeometrySWOGL @@ -862,6 +961,7 @@ protected: GLuint m_nTextureCoords; GLuint m_nNormals; GLuint m_nTriangles; + GLuint m_nTextureMatrixScale; void AllocateBuffers(); void UploadData(); @@ -889,7 +989,7 @@ static void InvalidateAllGeometry() RageCompiledGeometryHWOGL::RageCompiledGeometryHWOGL() { g_GeometryList.insert( this ); - m_nPositions = m_nTextureCoords = m_nNormals = m_nTriangles = 0; + m_nPositions = m_nTextureCoords = m_nNormals = m_nTriangles = m_nTextureMatrixScale = 0; AllocateBuffers(); } @@ -907,6 +1007,8 @@ RageCompiledGeometryHWOGL::~RageCompiledGeometryHWOGL() AssertNoGLError(); GLExt.glDeleteBuffersARB( 1, &m_nTriangles ); AssertNoGLError(); + GLExt.glDeleteBuffersARB( 1, &m_nTextureMatrixScale ); + AssertNoGLError(); } void RageCompiledGeometryHWOGL::AllocateBuffers() @@ -936,6 +1038,12 @@ void RageCompiledGeometryHWOGL::AllocateBuffers() GLExt.glGenBuffersARB( 1, &m_nTriangles ); AssertNoGLError(); } + + if( !m_nTextureMatrixScale ) + { + GLExt.glGenBuffersARB( 1, &m_nTextureMatrixScale ); + AssertNoGLError(); + } } void RageCompiledGeometryHWOGL::UploadData() @@ -971,12 +1079,23 @@ void RageCompiledGeometryHWOGL::UploadData() &m_vTriangles[0], GL_STATIC_DRAW_ARB ); // AssertNoGLError(); + + + if( m_bNeedsTextureMatrixScale ) + { + GLExt.glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureMatrixScale ); + GLExt.glBufferDataARB( + GL_ARRAY_BUFFER_ARB, + GetTotalVertices()*sizeof(RageVector2), + &m_vTexMatrixScale[0], + GL_STATIC_DRAW_ARB ); + } } void RageCompiledGeometryHWOGL::Invalidate() { /* Our vertex buffers no longer exist. Reallocate and reupload. */ - m_nPositions = m_nTextureCoords = m_nNormals = m_nTriangles = 0; + m_nPositions = m_nTextureCoords = m_nNormals = m_nTriangles = m_nTextureMatrixScale = 0; AllocateBuffers(); UploadData(); } @@ -984,7 +1103,6 @@ void RageCompiledGeometryHWOGL::Invalidate() void RageCompiledGeometryHWOGL::Allocate( const vector &vMeshes ) { RageCompiledGeometrySWOGL::Allocate( vMeshes ); - GLExt.glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nPositions ); GLExt.glBufferDataARB( GL_ARRAY_BUFFER_ARB, @@ -1016,6 +1134,13 @@ void RageCompiledGeometryHWOGL::Allocate( const vector &vMeshes ) NULL, GL_STATIC_DRAW_ARB ); AssertNoGLError(); + + GLExt.glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureMatrixScale ); + GLExt.glBufferDataARB( + GL_ARRAY_BUFFER_ARB, + GetTotalVertices()*sizeof(RageVector2), + NULL, + GL_STATIC_DRAW_ARB ); } void RageCompiledGeometryHWOGL::Change( const vector &vMeshes ) @@ -1068,6 +1193,21 @@ void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const glDisableClientState(GL_NORMAL_ARRAY); } + if( m_bNeedsTextureMatrixScale && g_bTextureMatrixShader != NULL ) + { + /* If we're using texture matrix scales, set up that buffer, too, and enable the + * vertex shader. This shader doesn't support all OpenGL state, so only enable it + * if we're using it. */ + GLExt.glEnableVertexAttribArrayARB( ATTRIB_TEXTURE_MATRIX_SCALE ); + AssertNoGLError(); + GLExt.glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nTextureMatrixScale ); + AssertNoGLError(); + GLExt.glVertexAttribPointerARB( ATTRIB_TEXTURE_MATRIX_SCALE, 2, GL_FLOAT, false, 0, NULL ); + AssertNoGLError(); + + GLExt.glUseProgramObjectARB( g_bTextureMatrixShader ); + } + GLExt.glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nTriangles ); AssertNoGLError(); @@ -1083,6 +1223,12 @@ void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const GL_UNSIGNED_SHORT, BUFFER_OFFSET(meshInfo.iTriangleStart*sizeof(msTriangle)) ); AssertNoGLError(); + + if( m_bNeedsTextureMatrixScale && g_bTextureMatrixShader != NULL ) + { + GLExt.glDisableVertexAttribArrayARB( ATTRIB_TEXTURE_MATRIX_SCALE ); + GLExt.glUseProgramObjectARB( NULL ); + } } RageCompiledGeometry* RageDisplay_OGL::CreateCompiledGeometry() diff --git a/stepmania/src/RageDisplay_OGL_Extensions.cpp b/stepmania/src/RageDisplay_OGL_Extensions.cpp index 7875b5cf32..ecdec9f199 100644 --- a/stepmania/src/RageDisplay_OGL_Extensions.cpp +++ b/stepmania/src/RageDisplay_OGL_Extensions.cpp @@ -16,6 +16,7 @@ #include "glext.h" #include "RageDisplay_OGL_Extensions.h" +#include "RageLog.h" #include "arch/LowLevelWindow/LowLevelWindow.h" GLExt_t GLExt; @@ -102,4 +103,67 @@ void GLExt_t::Load( LowLevelWindow *pWind ) if( HasExtension("GL_EXT_draw_range_elements") ) GLExt.glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) pWind->GetProcAddress("glDrawRangeElements"); + + m_bGL_ARB_shader_objects = HasExtension("GL_ARB_shader_objects"); + if( m_bGL_ARB_shader_objects ) + { + func_t funcs[] = { + F( glCreateShaderObjectARB ), + F( glCreateShaderObjectARB ), + F( glCreateProgramObjectARB ), + F( glShaderSourceARB ), + F( glCompileShaderARB ), + F( glGetObjectParameterfvARB ), + F( glGetObjectParameterivARB ), + F( glGetInfoLogARB ), + F( glAttachObjectARB ), + F( glDeleteObjectARB ), + F( glLinkProgramARB ), + F( glUseProgramObjectARB ), + F( glVertexAttrib2fARB ), + F( glVertexAttrib3fARB ), + F( glVertexAttrib4fARB ), + F( glEnableVertexAttribArrayARB ), + F( glDisableVertexAttribArrayARB ), + F( glVertexAttribPointerARB ), + NULL + }; + + if( !LoadAllOrNothing(funcs, pWind) ) + m_bGL_ARB_shader_objects = false; + } + + m_bGL_ARB_vertex_shader = m_bGL_ARB_shader_objects && HasExtension("GL_ARB_vertex_shader"); + if( m_bGL_ARB_vertex_shader ) + { + func_t funcs[] = + { + F( glBindAttribLocationARB ), + NULL + }; + if( !LoadAllOrNothing(funcs, pWind) ) + m_bGL_ARB_vertex_shader = false; + } + + m_bGL_ARB_shading_language_100 = HasExtension("GL_ARB_shading_language_100"); + if( m_bGL_ARB_shading_language_100 ) + { + while( glGetError() != GL_NO_ERROR ) + ; + const char *pzVersion = (const char *) glGetString( GL_SHADING_LANGUAGE_VERSION ); + + GLenum glError = glGetError(); + if( glError == GL_INVALID_ENUM ) + { + LOG->Info( "No GL_SHADING_LANGUAGE_VERSION; assuming 1.0" ); + m_iShadingLanguageVersion = 100; + } + else + { + const float fVersion = strtof( pzVersion, NULL ); + m_iShadingLanguageVersion = int(roundf(fVersion * 100)); + /* The version string may contain extra information beyond the version number. */ + LOG->Info( "OpenGL shading language: %s", pzVersion ); + } + } } diff --git a/stepmania/src/RageDisplay_OGL_Extensions.h b/stepmania/src/RageDisplay_OGL_Extensions.h index 720e7ef65e..474db4ff21 100644 --- a/stepmania/src/RageDisplay_OGL_Extensions.h +++ b/stepmania/src/RageDisplay_OGL_Extensions.h @@ -21,7 +21,32 @@ struct GLExt_t PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements; + // GL_ARB_shader_objects: + bool m_bGL_ARB_shader_objects; + PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; + PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; + PFNGLSHADERSOURCEARBPROC glShaderSourceARB; + PFNGLCOMPILESHADERARBPROC glCompileShaderARB; + PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; + PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; + PFNGLGETINFOLOGARBPROC glGetInfoLogARB; + PFNGLATTACHOBJECTARBPROC glAttachObjectARB; + PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; + PFNGLLINKPROGRAMARBPROC glLinkProgramARB; + PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; + PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; + PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; + PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; + PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; + PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; + PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; + + // GL_ARB_vertex_shader: + bool m_bGL_ARB_vertex_shader; + PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; + bool m_bGL_ARB_shading_language_100; + int m_iShadingLanguageVersion; /* * 100 */ void Load( LowLevelWindow *pWind ); };