diff --git a/guilib/GUIFontTTF.cpp b/guilib/GUIFontTTF.cpp index 1a911c6..d0a00c4 100644 --- a/guilib/GUIFontTTF.cpp +++ b/guilib/GUIFontTTF.cpp @@ -28,6 +28,7 @@ #include "MathUtils.h" #include "utils/log.h" #include "WindowingFactory.h" +#include "Shader.h" #include @@ -117,6 +118,119 @@ private: CFreeTypeLibrary g_freeTypeLibrary; // our freetype library +static void glGetViewportScale(GLfloat* Rx, GLfloat* Ry) +{ + GLfloat viewport[4]; + glGetFloatv(GL_VIEWPORT, viewport); + Rx[0] = 0.5f * (viewport[2] - viewport[0]); // X Scale + Rx[1] = 0.5f * (viewport[2] + viewport[0]); // X Offset + Rx[2] = - Rx[1]; // - X Offset + Rx[3] = 1.0f / Rx[0]; // 1.0 / X Scale + + Ry[0] = 0.5f * (viewport[3] - viewport[1]); // Y Scale + Ry[1] = 0.5f * (viewport[3] + viewport[1]); // Y Offset + Ry[2] = - Ry[1]; // - Y Offset + Ry[3] = 1.0f / Ry[0]; // 1.0 / Y Scale +} + +#ifdef HAS_SDL_OPENGL +class CTTFShaderGLSL + : public Shaders::CGLSLShaderProgram +{ +public: + CTTFShaderGLSL() + { + SetVertexShaderSource( + "uniform vec4 Rx;" + "uniform vec4 Ry;" + "float round(in float a)" + "{" + " return(sign(a)*floor(abs(a) + 0.5));" + "}" + "float correct(in float a, in vec4 R)" + "{" + " return ( round(a * R[0] + R[1]) + R[2]) * R[3];" + "}" + "void main()" + "{" + " gl_FrontColor = gl_Color;" + " gl_TexCoord[0] = gl_MultiTexCoord0;" + " gl_Position = ftransform();" + " gl_Position /= gl_Position.w;" + " gl_Position.x = correct(gl_Position.x, Rx);" + " gl_Position.y = correct(gl_Position.y, Ry);" + "}" + ); + } + void OnCompiledAndLinked() + { + m_HandleRx = glGetUniformLocation(ProgramHandle(), "Rx"); + m_HandleRy = glGetUniformLocation(ProgramHandle(), "Ry"); + } + + bool OnEnabled() + { + GLfloat Rx[4], Ry[4]; + glGetViewportScale(Rx, Ry); + glUniform4fv(m_HandleRx, 1, Rx); + glUniform4fv(m_HandleRy, 1, Ry); + return true; + } + GLint m_HandleRx; + GLint m_HandleRy; +}; + +class CTTFShaderARB + : public Shaders::CARBShaderProgram +{ +public: + CTTFShaderARB() + { + SetVertexShaderSource( + "!!ARBvp1.0\n" + "PARAM c[7] = { { 0.5 },\n" + " program.local[1..2],\n" + " state.matrix.mvp };\n" + "TEMP R0;\n" + "TEMP R1;\n" + "DP4 R0.x, vertex.position, c[6];\n" + "MOV R0.w, R0.x;\n" + "RCP R1.x, R0.x;\n" + "DP4 R0.z, vertex.position, c[5];\n" + "DP4 R0.y, vertex.position, c[4];\n" + "DP4 R0.x, vertex.position, c[3];\n" + "MUL R0, R0, R1.x;\n" + "MAD R0.y, R0, c[2].x, c[2];\n" + "MAD R0.x, R0, c[1], c[1].y;\n" + "ADD R0.y, R0, c[0].x;\n" + "ADD R0.x, R0, c[0];\n" + "FLR R0.y, R0;\n" + "FLR R0.x, R0;\n" + "ADD R0.y, R0, c[2].z;\n" + "ADD R0.x, R0, c[1].z;\n" + "MUL result.position.y, R0, c[2].w;\n" + "MUL result.position.x, R0, c[1].w;\n" + "MOV result.position.zw, R0;\n" + "MOV result.color, vertex.color;\n" + "MOV result.texcoord[0], vertex.texcoord[0];\n" + "END\n" + ); + } + + bool OnEnabled() + { + GLfloat Rx[4], Ry[4]; + glGetViewportScale(Rx, Ry); + glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, 1, Rx); + glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, 2, Ry); + VerifyGLState(); + return true; + } +}; + +static class Shaders::CShaderProgram* m_Shader = NULL; +#endif + CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) { m_texture = NULL; @@ -275,6 +399,21 @@ bool CGUIFontTTF::Load(const CStdString& strFilename, float height, float aspect Character *ellipse = GetCharacter(L'.'); if (ellipse) m_ellipsesWidth = ellipse->advance; +#ifdef HAS_SDL_OPENGL + if(m_Shader == NULL && (GLEW_ARB_shading_language_100 || GLEW_ARB_vertex_program)) + { + if(GLEW_ARB_shading_language_100) + m_Shader = new CTTFShaderGLSL(); + else if(GLEW_ARB_vertex_program) + m_Shader = new CTTFShaderARB(); + + if(m_Shader->CompileAndLink()) + CLog::Log(LOGERROR, "%s - compiled font rounding shader", __FUNCTION__); + else + CLog::Log(LOGERROR, "%s - failed to compile rounding shader", __FUNCTION__); + } +#endif + return true; } @@ -627,13 +756,35 @@ void CGUIFontTTF::RenderCharacter(float posX, float posY, const Character *ch, D g_graphicsContext.ClipRect(vertex, texture); // transform our positions - note, no scaling due to GUI calibration/resolution occurs - float x[4]; - + float x[4], y[4], z[4]; + if(m_hwtransform) + { + // if shader is okey, we use hardware transforms + x[0] = x[3] = vertex.x1; + x[1] = x[2] = vertex.x2; + y[0] = y[1] = vertex.y1; + y[2] = y[3] = vertex.y2; + z[0] = z[1] = z[2] = z[3] = 0.0; + } + else + { x[0] = g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y1); x[1] = g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y1); x[2] = g_graphicsContext.ScaleFinalXCoord(vertex.x2, vertex.y2); x[3] = g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y2); + y[0] = g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y1); + y[1] = g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y1); + y[2] = g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y2); + y[3] = g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y2); + +#ifndef HAS_SDL_2D + z[0] = g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y1); + z[1] = g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y1); + z[2] = g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y2); + z[3] = g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y2); +#endif + if (roundX) { // We only round the "left" side of the character, and then use the direction of rounding to @@ -655,15 +806,12 @@ void CGUIFontTTF::RenderCharacter(float posX, float posY, const Character *ch, D x[3] = rx3; } - float y1 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y1)); - float y2 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y1)); - float y3 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x2, vertex.y2)); - float y4 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y2)); - + for(int i=0; i<4; i++) + { + y[i] = ROUND_TO_PIXEL(y[i]); - float z1 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y1)); - float z2 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y1)); - float z3 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x2, vertex.y2)); - float z4 = (float)MathUtils::round_int(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y2)); + z[i] = ROUND_TO_PIXEL(z[i]); + } + } // tex coords converted to 0..1 range float tl = texture.x1 * m_textureScaleX; @@ -687,32 +835,24 @@ struct CUSTOMVERTEX { v[i].g = GET_G(color); v[i].b = GET_B(color); v[i].a = GET_A(color); + + v[i].x = x[i]; + v[i].y = y[i]; + v[i].z = z[i]; } #ifdef HAS_GL v[0].u = tl; v[0].v = tt; - v[0].x = x[0]; - v[0].y = y1; - v[0].z = z1; v[1].u = tr; v[1].v = tt; - v[1].x = x[1]; - v[1].y = y2; - v[1].z = z2; v[2].u = tr; v[2].v = tb; - v[2].x = x[2]; - v[2].y = y3; - v[2].z = z3; v[3].u = tl; v[3].v = tb; - v[3].x = x[3]; - v[3].y = y4; - v[3].z = z4; #else // GLES uses triangle strips, not quads, so have to rearrange the vertex order v[0].u = tl; diff --git a/guilib/GUIFontTTFGL.h b/guilib/GUIFontTTFGL.cpp index 0058fd7..2e9826e 100644 --- a/guilib/GUIFontTTFGL.cpp +++ b/guilib/GUIFontTTFGL.cpp @@ -59,6 +59,8 @@ void CGUIFontTTFGL::Begin() { if (m_nestedBeginCount == 0) { + m_hwtransform = g_graphicsContext.ApplyHardwareTransform(); + if (!m_bTextureLoaded) { // Have OpenGL generate a texture object handle for us @@ -98,6 +100,10 @@ void CGUIFontTTFGL::Begin() glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); VerifyGLState(); + + if(m_Shader && m_Shader->OK()) + m_Shader->Enable(); + #else g_Windowing.EnableGUIShader(SM_FONTS); #endif @@ -127,6 +133,9 @@ void CGUIFontTTF::End() glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawArrays(GL_QUADS, 0, m_vertex_count); glPopClientAttrib(); + + if(m_Shader && m_Shader->OK()) + m_Shader->Disable(); #else GLint posLoc = g_Windowing.GUIShaderGetPos(); GLint colLoc = g_Windowing.GUIShaderGetCol(); @@ -154,6 +163,12 @@ void CGUIFontTTFGL::End() g_Windowing.DisableGUIShader(); #endif + + if(m_hwtransform) + { + g_graphicsContext.RestoreHardwareTransform(); + m_hwtransform = false; + } } CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) diff --git a/guilib/GUIFontTTF.h b/guilib/GUIFontTTF.h index 0058fd7..2e9826e 100644 --- a/guilib/GUIFontTTF.h +++ b/guilib/GUIFontTTF.h @@ -157,6 +157,7 @@ protected: CStdString m_strFileName; private: + bool m_hwtransform; int m_referenceCount; }; diff --git a/guilib/GUITexture.cpp b/guilib/GUITexture.cpp index 50e5551..7786a69 100644 --- a/guilib/GUITexture.cpp +++ b/guilib/GUITexture.cpp @@ -82,6 +82,7 @@ CGUITextureBase::CGUITextureBase(float posX, float posY, float width, float heig m_allocateDynamically = false; m_isAllocated = NO; m_invalid = true; + m_hwtransform = false; } CGUITextureBase::CGUITextureBase(const CGUITextureBase &right) @@ -247,7 +248,24 @@ void CGUITextureBase::Render(float left, float top, float right, float bottom, f float x[4], y[4], z[4]; #define ROUND_TO_PIXEL(x) (float)(MathUtils::round_int(x)) + if(m_hwtransform) + { + x[0] = vertex.x1; + y[0] = vertex.y1; + + x[1] = vertex.x2; + y[1] = vertex.y1; + + x[2] = vertex.x2; + y[2] = vertex.y2; + + x[3] = vertex.x1; + y[3] = vertex.y2; + z[0] = z[1] = z[2] = z[3] = 0; + } + else + { x[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalXCoord(vertex.x1, vertex.y1)); y[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalYCoord(vertex.x1, vertex.y1)); z[0] = ROUND_TO_PIXEL(g_graphicsContext.ScaleFinalZCoord(vertex.x1, vertex.y1)); @@ -263,6 +281,7 @@ void CGUITextureBase::Render(float left, float top, float right, float bottom, f if (y[2] == y[0]) y[2] += 1.0f; if (x[2] == x[0]) x[2] += 1.0f; if (y[3] == y[1]) y[3] += 1.0f; if (x[3] == x[1]) x[3] += 1.0f; + } #define MIX_ALPHA(a,c) (((a * (c >> 24)) / 255) << 24) | (c & 0x00ffffff) diff --git a/guilib/GUITexture.h b/guilib/GUITexture.h index e979f4f..049517b 100644 --- a/guilib/GUITexture.h +++ b/guilib/GUITexture.h @@ -144,6 +144,7 @@ protected: CRect m_vertex; // vertex coords to render bool m_invalid; // if true, we need to recalculate + bool m_hwtransform; unsigned char m_alpha; diff --git a/guilib/GUITextureGL.cpp b/guilib/GUITextureGL.cpp index 074521f..4db8afb 100644 --- a/guilib/GUITextureGL.cpp +++ b/guilib/GUITextureGL.cpp @@ -68,24 +68,31 @@ void CGUITexture::Begin() glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); VerifyGLState(); } - //glDisable(GL_TEXTURE_2D); // uncomment these 2 lines to switch to wireframe rendering - //glBegin(GL_LINE_LOOP); - glBegin(GL_QUADS); + m_hwtransform = g_graphicsContext.ApplyHardwareTransform(); } void CGUITextureGL::End() { - glEnd(); if (m_diffuse.size()) { glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE0_ARB); } glDisable(GL_TEXTURE_2D); + + if(m_hwtransform) + { + g_graphicsContext.RestoreHardwareTransform(); + m_hwtransform = false; + } } void CGUITextureGL::Draw(float *x, float *y, float *z, const CRect &texture, const CRect &diffuse, color_t color, int orientation) { + //glDisable(GL_TEXTURE_2D); // uncomment these 2 lines to switch to wireframe rendering + //glBegin(GL_LINE_LOOP); + glBegin(GL_QUADS); + GLubyte a = (GLubyte)GET_A(color); GLubyte r = (GLubyte)GET_R(color); GLubyte g = (GLubyte)GET_G(color); @@ -134,6 +141,8 @@ void CGUITexture::Draw(float *x, float *y, float *z, const CRect &texture, const glMultiTexCoord2fARB(GL_TEXTURE1_ARB, diffuse.x1, diffuse.y2); } glVertex3f(x[3], y[3], z[3]); + + glEnd(); } void CGUITextureGL::DrawQuad(const CRect &rect, color_t color, CBaseTexture *texture, const CRect *texCoords) diff --git a/guilib/GraphicContext.cpp b/guilib/GraphicContext.cpp index 646a39e..e4d3d3f 100644 --- a/guilib/GraphicContext.cpp +++ b/guilib/GraphicContext.cpp @@ -749,9 +749,9 @@ void CGraphicContext::Flip() g_Windowing.PresentRender(); } -void CGraphicContext::ApplyHardwareTransform() +bool CGraphicContext::ApplyHardwareTransform() { - g_Windowing.ApplyHardwareTransform(m_finalTransform); + return g_Windowing.ApplyHardwareTransform(m_finalTransform); } void CGraphicContext::RestoreHardwareTransform() diff --git a/guilib/GraphicContext.h b/guilib/GraphicContext.h index 782d1a3..72ade75 100644 --- a/guilib/GraphicContext.h +++ b/guilib/GraphicContext.h @@ -128,7 +128,7 @@ public: void RestoreCameraPosition(); bool SetClipRegion(float x, float y, float w, float h); void RestoreClipRegion(); - void ApplyHardwareTransform(); + bool ApplyHardwareTransform(); void RestoreHardwareTransform(); void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL); void ClipToViewWindow();