diff options
Diffstat (limited to 'src/graphics/ShaderRegistry.cpp')
-rw-r--r-- | src/graphics/ShaderRegistry.cpp | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/graphics/ShaderRegistry.cpp b/src/graphics/ShaderRegistry.cpp new file mode 100644 index 0000000..529482f --- /dev/null +++ b/src/graphics/ShaderRegistry.cpp @@ -0,0 +1,193 @@ +// +// 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 "ShaderRegistry.h" + +#include "GLContext.h" +#include "OGLShader.h" + +#include "../base/Logger.h" +#include "../base/Exception.h" +#include "../base/OSHelper.h" +#include "../base/FileHelper.h" +#include "../base/StringHelper.h" + +#include <iostream> + +using namespace std; +using namespace boost; + +namespace avg { + +std::string ShaderRegistry::s_sLibPath; + +ShaderRegistryPtr ShaderRegistry::get() +{ + return GLContext::getCurrent()->getShaderRegistry(); +} + +ShaderRegistry::ShaderRegistry() +{ + if (s_sLibPath == "") { + setShaderPath(getPath(getAvgLibPath())+"shaders"); + } +} + +ShaderRegistry::~ShaderRegistry() +{ +} + +void ShaderRegistry::setShaderPath(const string& sLibPath) +{ + s_sLibPath = sLibPath; +#ifdef __linux + // XXX: If we're running make distcheck, the shaders are in a different place than + // usual. Grrr. + char * pszSrcDir = getenv("srcdir"); + if (pszSrcDir && string(pszSrcDir) != ".") { + s_sLibPath = string(pszSrcDir) + "/../graphics/shaders"; + } +#endif + AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO, + "Loading shaders from "+s_sLibPath); +} + +void ShaderRegistry::setPreprocessorDefine(const string& sName, const string& sValue) +{ + m_PreprocessorDefinesMap[sName] = sValue; +} + +void ShaderRegistry::createShader(const std::string& sID) +{ + OGLShaderPtr pShader = getShader(sID); + if (!pShader) { + string sShaderCode; + string sVertPreprocessed; + loadShaderString(s_sLibPath+"/standard.vert", sVertPreprocessed); + string sFilename = s_sLibPath+"/"+sID+".frag"; + string sFragPreprocessed; + loadShaderString(sFilename, sFragPreprocessed); + string sVertPrefix = createPrefixString(false); + string sFragPrefix = createPrefixString(true); + m_ShaderMap[sID] = OGLShaderPtr( + new OGLShader(sID, sVertPreprocessed, sFragPreprocessed, sVertPrefix, + sFragPrefix)); + } +} + +OGLShaderPtr ShaderRegistry::getShader(const std::string& sID) const +{ + ShaderMap::const_iterator it = m_ShaderMap.find(sID); + if (it == m_ShaderMap.end()) { + return OGLShaderPtr(); + } else { + return it->second; + } +} + +OGLShaderPtr ShaderRegistry::getCurShader() const +{ + return m_pCurShader; +} + +void ShaderRegistry::setCurShader(const std::string& sID) +{ + if (sID == "") { + m_pCurShader = OGLShaderPtr(); + } else { + m_pCurShader = getShader(sID); + } +} + +void ShaderRegistry::loadShaderString(const string& sFilename, string& sPreprocessed) +{ + string sShaderCode; + readWholeFile(sFilename, sShaderCode); + preprocess(sShaderCode, sFilename, sPreprocessed); +} + +void ShaderRegistry::preprocess(const string& sShaderCode, const string& sFileName, + string& sProcessed) +{ + sProcessed.append("#line 0\n"); + istringstream stream(sShaderCode); + string sCurLine; + int curLine = 0; + while(getline(stream, sCurLine)) { + curLine++; + string sStripped = removeStartEndSpaces(sCurLine); + if (sStripped.substr(0, 8) == "#include") { + size_t startPos = sStripped.find('"'); + size_t endPos = sStripped.find('"', startPos+1); + if (startPos == string::npos || endPos == string::npos) { + throwParseError(sFileName, curLine); + } + string sIncFileName = sStripped.substr(startPos+1, endPos-startPos-1); + sIncFileName = s_sLibPath+"/"+sIncFileName; + string sIncludedFile; + readWholeFile(sIncFileName, sIncludedFile); + string sProcessedIncludedFile; + preprocess(sIncludedFile, sIncFileName, sProcessedIncludedFile); + sProcessed.append(sProcessedIncludedFile); + sProcessed.append("#line "+toString(curLine)+"\n"); + } else { + sProcessed.append(sCurLine+"\n"); + } + } +} + +string ShaderRegistry::createPrefixString(bool bFragment) +{ + stringstream ss; + std::map<std::string, std::string>::iterator it; + for (it = m_PreprocessorDefinesMap.begin(); it != m_PreprocessorDefinesMap.end(); + ++it) + { + ss << "#define " << it->first << " " << it->second << endl; + } + if (GLContext::getCurrent()->isGLES()) { + ss << endl; + if (bFragment) { + ss << "#extension GL_OES_standard_derivatives : enable" << endl; + } + ss << "precision mediump float;" << endl; + } + return ss.str(); +} + +void ShaderRegistry::throwParseError(const string& sFileName, int curLine) +{ + throw Exception(AVG_ERR_VIDEO_GENERAL, "File '"+sFileName+"', Line "+ + toString(curLine)+": Syntax error."); +} + +void createShader(const std::string& sID) +{ + return ShaderRegistry::get()->createShader(sID); +} + +OGLShaderPtr getShader(const std::string& sID) +{ + return ShaderRegistry::get()->getShader(sID); +} + +} + |