/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "GLShader.h" #include "ServiceBroker.h" #include "rendering/MatrixGL.h" #include "rendering/RenderSystem.h" #include "utils/log.h" #include "windowing/GraphicContext.h" using namespace Shaders; CGLShader::CGLShader(const char* shader, const std::string& prefix) { m_proj = nullptr; m_model = nullptr; m_clipPossible = false; VertexShader()->LoadSource("gl_shader_vert.glsl"); PixelShader()->LoadSource(shader, prefix); } CGLShader::CGLShader(const char* vshader, const char* fshader, const std::string& prefix) { m_proj = nullptr; m_model = nullptr; m_clipPossible = false; VertexShader()->LoadSource(vshader, prefix); PixelShader()->LoadSource(fshader, prefix); } void CGLShader::OnCompiledAndLinked() { // This is called after CompileAndLink() // Variables passed directly to the Fragment shader m_hTex0 = glGetUniformLocation(ProgramHandle(), "m_samp0"); m_hTex1 = glGetUniformLocation(ProgramHandle(), "m_samp1"); m_hUniCol = glGetUniformLocation(ProgramHandle(), "m_unicol"); // Variables passed directly to the Vertex shader m_hProj = glGetUniformLocation(ProgramHandle(), "m_proj"); m_hModel = glGetUniformLocation(ProgramHandle(), "m_model"); // Vertex attributes m_hPos = glGetAttribLocation(ProgramHandle(), "m_attrpos"); m_hCol = glGetAttribLocation(ProgramHandle(), "m_attrcol"); m_hCord0 = glGetAttribLocation(ProgramHandle(), "m_attrcord0"); m_hCord1 = glGetAttribLocation(ProgramHandle(), "m_attrcord1"); // It's okay to do this only one time. Textures units never change. glUseProgram(ProgramHandle()); glUniform1i(m_hTex0, 0); glUniform1i(m_hTex1, 1); glUniform4f(m_hUniCol, 1.0, 1.0, 1.0, 1.0); glUseProgram(0); } bool CGLShader::OnEnabled() { // This is called after glUseProgram() const GLfloat *projMatrix = glMatrixProject.Get(); const GLfloat *modelMatrix = glMatrixModview.Get(); glUniformMatrix4fv(m_hProj, 1, GL_FALSE, projMatrix); glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix); const TransformMatrix &guiMatrix = CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIMatrix(); CRect viewPort; // absolute positions of corners CServiceBroker::GetRenderSystem()->GetViewPort(viewPort); /* glScissor operates in window coordinates. In order that we can use it to * perform clipping, we must ensure that there is an independent linear * transformation from the coordinate system used by CGraphicContext::ClipRect * to window coordinates, separately for X and Y (in other words, no * rotation or shear is introduced at any stage). To do, this, we need to * check that zeros are present in the following locations: * * GUI matrix: * / * 0 * * \ * | 0 * * * | * \ 0 0 * * / * ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with * input z = 0, so this column doesn't matter * Model-view matrix: * / * 0 0 * \ * | 0 * 0 * | * | 0 0 * * | * \ * * * * / <- eye w has no influence on window x/y (last column below * is either 0 or ignored) * Projection matrix: * / * 0 0 0 \ * | 0 * 0 0 | * | * * * * | <- normalised device coordinate z has no influence on window x/y * \ 0 0 * 0 / * * Some of these zeros are not strictly required to ensure this, but they tend * to be zeroed in the common case, so by checking for zeros here, we simplify * the calculation of the window x/y coordinates further down the line. * * (Minor detail: we don't quite deal in window coordinates as defined by * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all * that's needed to handle that is an effective negation at the stage where * Y is in normalised device coordinates.) */ m_clipPossible = guiMatrix.m[0][1] == 0 && guiMatrix.m[1][0] == 0 && guiMatrix.m[2][0] == 0 && guiMatrix.m[2][1] == 0 && modelMatrix[0+1*4] == 0 && modelMatrix[0+2*4] == 0 && modelMatrix[1+0*4] == 0 && modelMatrix[1+2*4] == 0 && modelMatrix[2+0*4] == 0 && modelMatrix[2+1*4] == 0 && projMatrix[0+1*4] == 0 && projMatrix[0+2*4] == 0 && projMatrix[0+3*4] == 0 && projMatrix[1+0*4] == 0 && projMatrix[1+2*4] == 0 && projMatrix[1+3*4] == 0 && projMatrix[3+0*4] == 0 && projMatrix[3+1*4] == 0 && projMatrix[3+3*4] == 0; m_clipXFactor = 0.0; m_clipXOffset = 0.0; m_clipYFactor = 0.0; m_clipYOffset = 0.0; if (m_clipPossible) { m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4]; m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4]; m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4]; m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4]; float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4]; float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW); float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme m_clipXFactor = m_clipXFactor * xMult; m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2; m_clipYFactor = m_clipYFactor * yMult; m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2; } return true; } void CGLShader::Free() { // Do Cleanup here CGLSLShaderProgram::Free(); }