diff options
Diffstat (limited to 'src/player/OGLSurface.cpp')
-rw-r--r-- | src/player/OGLSurface.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/player/OGLSurface.cpp b/src/player/OGLSurface.cpp new file mode 100644 index 0000000..b0aa58e --- /dev/null +++ b/src/player/OGLSurface.cpp @@ -0,0 +1,262 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "OGLSurface.h" + +#include "../base/MathHelper.h" +#include "../base/Logger.h" +#include "../base/Exception.h" +#include "../base/ScopeTimer.h" +#include "../base/ObjectCounter.h" + +#include "../graphics/GLContext.h" +#include "../graphics/GLTexture.h" + +#include <iostream> +#include <sstream> + +#include "../glm/gtc/matrix_transform.hpp" + +using namespace std; + +static glm::mat4 yuvCoeff( + 1.0f, 1.0f, 1.0f, 0.0f, + 0.0f, -0.34f, 1.77f, 0.0f, + 1.40f, -0.71f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + +namespace avg { + +OGLSurface::OGLSurface() + : m_Size(-1,-1), + m_Gamma(1,1,1), + m_Brightness(1,1,1), + m_Contrast(1,1,1), + m_AlphaGamma(1), + m_bIsDirty(true) +{ + ObjectCounter::get()->incRef(&typeid(*this)); +} + +OGLSurface::~OGLSurface() +{ + ObjectCounter::get()->decRef(&typeid(*this)); +} + +void OGLSurface::create(PixelFormat pf, GLTexturePtr pTex0, GLTexturePtr pTex1, + GLTexturePtr pTex2, GLTexturePtr pTex3) +{ + m_pf = pf; + m_Size = pTex0->getSize(); + m_pTextures[0] = pTex0; + m_pTextures[1] = pTex1; + m_pTextures[2] = pTex2; + m_pTextures[3] = pTex3; + m_bIsDirty = true; + + // Make sure pixel format and number of textures line up. + if (pixelFormatIsPlanar(pf)) { + AVG_ASSERT(m_pTextures[2]); + if (pixelFormatHasAlpha(m_pf)) { + AVG_ASSERT(m_pTextures[3]); + } else { + AVG_ASSERT(!m_pTextures[3]); + } + } else { + AVG_ASSERT(!m_pTextures[1]); + } +} + +void OGLSurface::setMask(GLTexturePtr pTex) +{ + m_pMaskTexture = pTex; + m_bIsDirty = true; +} + +void OGLSurface::destroy() +{ + m_pTextures[0] = GLTexturePtr(); + m_pTextures[1] = GLTexturePtr(); + m_pTextures[2] = GLTexturePtr(); + m_pTextures[3] = GLTexturePtr(); +} + +void OGLSurface::activate(const IntPoint& logicalSize, bool bPremultipliedAlpha) const +{ + StandardShaderPtr pShader = StandardShader::get(); + + GLContext::checkError("OGLSurface::activate()"); + switch (m_pf) { + case YCbCr420p: + case YCbCrJ420p: + pShader->setColorModel(1); + break; + case YCbCrA420p: + pShader->setColorModel(3); + break; + case A8: + pShader->setColorModel(2); + break; + default: + pShader->setColorModel(0); + } + + m_pTextures[0]->activate(GL_TEXTURE0); + + if (pixelFormatIsPlanar(m_pf)) { + m_pTextures[1]->activate(GL_TEXTURE1); + m_pTextures[2]->activate(GL_TEXTURE2); + if (m_pf == YCbCrA420p) { + m_pTextures[3]->activate(GL_TEXTURE3); + } + } + if (pixelFormatIsPlanar(m_pf) || colorIsModified()) { + glm::mat4 mat = calcColorspaceMatrix(); + pShader->setColorspaceMatrix(mat); + } else { + pShader->disableColorspaceMatrix(); + } + pShader->setGamma(glm::vec4(1/m_Gamma.x, 1/m_Gamma.y, 1/m_Gamma.z, + 1./m_AlphaGamma)); + + pShader->setPremultipliedAlpha(bPremultipliedAlpha); + if (m_pMaskTexture) { + m_pMaskTexture->activate(GL_TEXTURE4); + // Special case for pot textures: + // The tex coords in the vertex array are scaled to fit the image texture. We + // need to undo this and fit to the mask texture. In the npot case, everything + // evaluates to (1,1); + glm::vec2 texSize = glm::vec2(m_pTextures[0]->getGLSize()); + glm::vec2 imgSize = glm::vec2(m_pTextures[0]->getSize()); + glm::vec2 maskTexSize = glm::vec2(m_pMaskTexture->getGLSize()); + glm::vec2 maskImgSize = glm::vec2(m_pMaskTexture->getSize()); + glm::vec2 maskScale = glm::vec2(maskTexSize.x/maskImgSize.x, + maskTexSize.y/maskImgSize.y); + glm::vec2 imgScale = glm::vec2(texSize.x/imgSize.x, texSize.y/imgSize.y); + glm::vec2 maskPos = m_MaskPos/maskScale; + // Special case for words nodes. + if (logicalSize != IntPoint(0,0)) { + maskScale *= glm::vec2((float)logicalSize.x/m_Size.x, + (float)logicalSize.y/m_Size.y); + } + pShader->setMask(true, maskPos, m_MaskSize*maskScale/imgScale); + } else { + pShader->setMask(false); + } + pShader->activate(); + GLContext::checkError("OGLSurface::activate"); +} + +GLTexturePtr OGLSurface::getTex(int i) const +{ + return m_pTextures[i]; +} + +void OGLSurface::setMaskCoords(glm::vec2 maskPos, glm::vec2 maskSize) +{ + m_MaskPos = maskPos; + m_MaskSize = maskSize; + m_bIsDirty = true; +} + +PixelFormat OGLSurface::getPixelFormat() +{ + return m_pf; +} + +IntPoint OGLSurface::getSize() +{ + return m_Size; +} + +IntPoint OGLSurface::getTextureSize() +{ + return m_pTextures[0]->getGLSize(); +} + +bool OGLSurface::isCreated() const +{ + return m_pTextures[0]; +} + +void OGLSurface::setColorParams(const glm::vec3& gamma, const glm::vec3& brightness, + const glm::vec3& contrast) +{ + m_Gamma = gamma; + m_Brightness = brightness; + m_Contrast = contrast; + m_bIsDirty = true; +} + +void OGLSurface::setAlphaGamma(float gamma) +{ + m_AlphaGamma = gamma; + m_bIsDirty = true; +} + +bool OGLSurface::isDirty() const +{ + bool bIsDirty = m_bIsDirty; + for (unsigned i=0; i<getNumPixelFormatPlanes(m_pf); ++i) { + if (m_pTextures[i]->isDirty()) { + bIsDirty = true; + } + } + return bIsDirty; +} + +void OGLSurface::resetDirty() +{ + m_bIsDirty = false; + for (unsigned i=0; i<getNumPixelFormatPlanes(m_pf); ++i) { + m_pTextures[i]->resetDirty(); + } +} + +glm::mat4 OGLSurface::calcColorspaceMatrix() const +{ + glm::mat4 mat; + if (colorIsModified()) { + mat = glm::scale(mat, m_Brightness); + glm::vec3 contrast = glm::vec3(0.5f, 0.5f, 0.5f) - m_Contrast/2.f; + mat = glm::translate(mat, contrast); + mat = glm::scale(mat, m_Contrast); + } + if (m_pf == YCbCr420p || m_pf == YCbCrJ420p || m_pf == YCbCrA420p) { + mat *= yuvCoeff; + mat = glm::translate(mat, glm::vec3(0.0, -0.5, -0.5)); + if (m_pf == YCbCr420p || m_pf == YCbCrA420p) { + mat = glm::scale(mat, + glm::vec3(255.0f/(235-16), 255.0f/(235-16), 255.0f/(235-16))); + mat = glm::translate(mat, glm::vec3(-16.0f/255, -16.0f/255, -16.0f/255)); + } + } + return mat; +} + +bool OGLSurface::colorIsModified() const +{ + return (fabs(m_Brightness.x-1.0) > 0.00001 || fabs(m_Brightness.y-1.0) > 0.00001 || + fabs(m_Brightness.z-1.0) > 0.00001 || fabs(m_Contrast.x-1.0) > 0.00001 || + fabs(m_Contrast.y-1.0) > 0.00001 || fabs(m_Contrast.z-1.0) > 0.00001); +} + +} |