1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
/*
* 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();
}
|