ResInsight/Fwk/VizFwk/LibRender/cvfShaderProgram.cpp
Roland Kaufmann 6d38344261 Don't validate shader programs on MacOS X
If the paint event is called before the view is visible, validation
of the shader program will cause an error on MacOS X 10.8 and forward,
stating that the operation was ignored.
2015-01-01 19:46:25 +01:00

883 lines
33 KiB
C++

//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 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 General Public License at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// 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.1 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 at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfShaderProgram.h"
#include "cvfOpenGL.h"
#include "cvfUniform.h"
#include "cvfUniformSet.h"
#include "cvfMatrixState.h"
#include "cvfTrace.h"
#include "cvfOpenGLResourceManager.h"
#include "cvfOglRc.h"
#include "cvfOpenGLCapabilities.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::ShaderProgram
/// \ingroup Render
///
/// Encapsulates a GLSL shader program.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ShaderProgram::ShaderProgram(const String& programName)
: m_programName(programName),
m_needsLinking(true)
{
}
//--------------------------------------------------------------------------------------------------
/// Get name of this shader program
///
/// If no name has been set, one will be constructed by concatenating the name of the attached shaders.
//--------------------------------------------------------------------------------------------------
String ShaderProgram::programName() const
{
if (m_programName.isEmpty())
{
String progName;
uint numShaders = shaderCount();
uint i;
for (i = 0; i < numShaders; i++)
{
const Shader* shader = m_shaders.at(i);
if (i > 0) progName += " # ";
progName += shader->shaderName();
}
return progName;
}
else
{
return m_programName;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::setProgramName(const String& programName)
{
m_programName = programName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ShaderProgram::~ShaderProgram()
{
// Just release our reference
CVF_ASSERT(OglRc::isSafeToRelease(m_oglRcProgram.p()));
m_oglRcProgram = NULL;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::addShader(Shader* shader)
{
CVF_ASSERT(shader);
m_shaders.push_back(shader);
m_linkedShaderVersionTicks.push_back(-1);
m_needsLinking = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint ShaderProgram::shaderCount() const
{
return static_cast<uint>(m_shaders.size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Shader* ShaderProgram::shader(uint index)
{
CVF_ASSERT(index < shaderCount());
return m_shaders.at(index);
}
//--------------------------------------------------------------------------------------------------
/// Links the program if needed
///
/// Will create the shader program if needed. Will compile the program's shaders if needed.
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::linkProgram(OpenGLContext* oglContext)
{
CVF_CALLSITE_OPENGL(oglContext);
CVF_ASSERT(ShaderProgram::supportedOpenGL(oglContext));
if (OglRc::safeOglId(m_oglRcProgram.p()) != 0)
{
if (!needsLinking())
{
return true;
}
}
// Do a delete/create cycle to avoid keeping tabs of which shaders
// that need to be detached. Assumption is that relinking happens seldom
deleteProgram(oglContext);
if (!createProgram(oglContext))
{
CVF_LOG_RENDER_ERROR(oglContext, String("Unable to create program '%1'").arg(programName()));
return false;
}
// For now, always call compile on all the shaders
// The compile should be a no-op if everything is in sync
uint numShaders = shaderCount();
CVF_ASSERT(numShaders == static_cast<uint>(m_linkedShaderVersionTicks.size()));
uint i;
for (i = 0; i < numShaders; i++)
{
Shader* shader = m_shaders.at(i);
if (!shader->compile(oglContext))
{
CVF_LOG_RENDER_ERROR(oglContext, String("Error compiling shader '%1' attached to program '%2'").arg(shader->shaderName()).arg(programName()));
return false;
}
CVF_ASSERT(shader->shaderOglId() != 0);
glAttachShader(m_oglRcProgram->oglId(), shader->shaderOglId());
CVF_CHECK_OGL(oglContext);
m_linkedShaderVersionTicks[i] = shader->compiledVersionTick();
}
bindFixedAttributes(oglContext);
glLinkProgram(m_oglRcProgram->oglId());
//Trace::show("%d", glGetAttribLocation(m_programObjID, "cvfa_vertex"));
//Trace::show("%d", glGetAttribLocation(m_programObjID, "cvfa_normal"));
//Trace::show("%d", glGetAttribLocation(m_programObjID, "cvfa_color"));
//Trace::show(programInfoLog().toAscii().ptr());
GLint iLinkStatus = 0;
glGetProgramiv(m_oglRcProgram->oglId(), GL_LINK_STATUS, &iLinkStatus);
if (iLinkStatus != GL_TRUE)
{
CVF_LOG_RENDER_ERROR(oglContext, String("Error linking shader program '%1', GLSL details:\n%2").arg(programName()).arg(programInfoLog(oglContext)));
return false;
}
m_needsLinking = false;
discoverActiveUniforms(oglContext);
return true;
}
//--------------------------------------------------------------------------------------------------
/// Creates the program. Does nothing shader program is already created
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::createProgram(OpenGLContext* oglContext)
{
CVF_ASSERT(ShaderProgram::supportedOpenGL(oglContext));
if (OglRc::safeOglId(m_oglRcProgram.p()) == 0)
{
OpenGLResourceManager* resourceManager = oglContext->resourceManager();
CVF_ASSERT(OglRc::isSafeToRelease(m_oglRcProgram.p()));
m_oglRcProgram = resourceManager->createOglRcProgram(oglContext);
if (m_oglRcProgram.isNull())
{
CVF_CHECK_OGL(oglContext);
return false;
}
m_needsLinking = true;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::needsLinking() const
{
if (m_needsLinking) return true;
uint numShaders = shaderCount();
CVF_ASSERT(numShaders == static_cast<uint>(m_linkedShaderVersionTicks.size()));
uint i;
for (i = 0; i < numShaders; i++)
{
const Shader* shader = m_shaders.at(i);
int compiledVersionTick = shader->compiledVersionTick();
if (compiledVersionTick != m_linkedShaderVersionTicks[i] || compiledVersionTick == -1)
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::useProgram(OpenGLContext* oglContext) const
{
CVF_CALLSITE_OPENGL(oglContext);
CVF_TIGHT_ASSERT(ShaderProgram::supportedOpenGL(oglContext));
if (m_needsLinking)
{
return false;
}
CVF_ASSERT(OglRc::safeOglId(m_oglRcProgram.p()) != 0);
#ifndef CVF_OSX
CVF_ASSERT(validateProgram(oglContext));
#endif
// Need this check to clear any "hanging" errors that is not produced by glUseProgram below, but still
// will make this method return false.
CVF_CLEAR_OGL_ERROR(oglContext);
glUseProgram(m_oglRcProgram->oglId());
// TODO
// Is there any lightweight way to check if the glUseCall was successful
if (CVF_TEST_AND_REPORT_OPENGL_ERROR(oglContext, "Use shader program"))
{
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::useNoProgram(OpenGLContext* oglContext)
{
CVF_CALLSITE_OPENGL(oglContext);
CVF_TIGHT_ASSERT(ShaderProgram::supportedOpenGL(oglContext));
glUseProgram(0);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::isProgramUsed(OpenGLContext* /*oglContext*/) const
{
GLint currentProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram); // Note: GL_CURRENT_PROGRAM is renamed to GL_ACTIVE_PROGRAM in 4.1
if (currentProgram != 0)
{
if (static_cast<OglId>(currentProgram) == OglRc::safeOglId(m_oglRcProgram.p()))
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
OglId ShaderProgram::programOglId() const
{
return OglRc::safeOglId(m_oglRcProgram.p());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::deleteProgram(OpenGLContext* oglContext)
{
CVF_ASSERT(oglContext);
if (m_oglRcProgram.notNull())
{
m_oglRcProgram->deleteResource(oglContext);
CVF_CHECK_OGL(oglContext);
CVF_ASSERT(OglRc::isSafeToRelease(m_oglRcProgram.p()));
m_oglRcProgram = NULL;
uint numShaders = static_cast<uint>(m_linkedShaderVersionTicks.size());
uint i;
for (i = 0; i < numShaders; i++)
{
m_linkedShaderVersionTicks[i] = -1;
}
m_needsLinking = true;
}
CVF_ASSERT(m_needsLinking);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::validateProgram(OpenGLContext* oglContext) const
{
CVF_CALLSITE_OPENGL(oglContext);
if (OglRc::safeOglId(m_oglRcProgram.p()) == 0)
{
return false;
}
glValidateProgram(m_oglRcProgram->oglId());
GLint validateStatus = GL_FALSE;
glGetProgramiv(m_oglRcProgram->oglId(), GL_VALIDATE_STATUS, &validateStatus);
if (validateStatus == GL_TRUE)
{
return true;
}
else
{
// Any textual result of the vaidation is presented in the log
CVF_LOG_RENDER_ERROR(oglContext, programInfoLog(oglContext));
return false;
}
}
//--------------------------------------------------------------------------------------------------
/// Returns the information log for this shader
///
/// See: http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramInfoLog.xml
//--------------------------------------------------------------------------------------------------
String ShaderProgram::programInfoLog(OpenGLContext* oglContext) const
{
CVF_CALLSITE_OPENGL(oglContext);
uint myOglId = OglRc::safeOglId(m_oglRcProgram.p());
if (myOglId == 0)
{
return "Program object not created.";
}
if (!glIsProgram(myOglId))
{
return "Program object identifier does not correspond to a shader program object.";
}
GLint reqBufferSize = 0;
glGetProgramiv(myOglId, GL_INFO_LOG_LENGTH, &reqBufferSize);
if (reqBufferSize > 0)
{
// TODO
// This is a good place for using CharArray
std::vector<GLchar> charBuffer;
charBuffer.resize(static_cast<size_t>(reqBufferSize + 1));
glGetProgramInfoLog(myOglId, reqBufferSize, NULL, &charBuffer[0]);
String logString(&charBuffer[0]);
return logString;
}
else
{
return "";
}
}
//--------------------------------------------------------------------------------------------------
/// Set a default uniform for this shader program
///
/// Default uniforms are stored with the shader program and may be used to bundle 'default' values
/// for some of the uniforms that the shader program exposes.and The default uniforms should be
/// applied using the applyDefaultUniforms() function.
//--------------------------------------------------------------------------------------------------
void ShaderProgram::setDefaultUniform(Uniform* uniform)
{
CVF_ASSERT(uniform);
if (m_defaultUniformSet.isNull())
{
m_defaultUniformSet = new UniformSet;
}
m_defaultUniformSet->setUniform(uniform);
}
//--------------------------------------------------------------------------------------------------
/// Apply the shader program's default uniforms
///
/// Will apply the shader program's default uniforms, if any. To get the intended behavior, the
/// default uniforms should typically be applied before applying any other uniforms. Otherwise, the
/// default values will overwrite any user specified uniforms.
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::applyDefaultUniforms(OpenGLContext* oglContext)
{
bool allUniformsSuccess = true;
if (m_defaultUniformSet.notNull())
{
size_t numUniforms = m_defaultUniformSet->count();
size_t i;
for (i = 0; i < numUniforms; i++)
{
const Uniform* uniform = m_defaultUniformSet->uniform(i);
allUniformsSuccess &= applyUniform(oglContext, *uniform);
}
}
return allUniformsSuccess;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::applyUniformAtLocation(OpenGLContext* oglContext, int location, const Uniform& uniform)
{
CVF_CALLSITE_OPENGL(oglContext);
CVF_TIGHT_ASSERT(location >= 0);
const int valCount = uniform.valueCount();
CVF_ASSERT_MSG(valCount > 0, "No data set for uniform");
switch (uniform.type())
{
case Uniform::INT: glUniform1iv(location, valCount, uniform.intPtr()); break;
case Uniform::FLOAT: glUniform1fv(location, valCount, uniform.floatPtr()); break;
case Uniform::FLOAT_VEC2: glUniform2fv(location, valCount, uniform.floatPtr()); break;
case Uniform::FLOAT_VEC3: glUniform3fv(location, valCount, uniform.floatPtr()); break;
case Uniform::FLOAT_VEC4: glUniform4fv(location, valCount, uniform.floatPtr()); break;
case Uniform::FLOAT_MAT4: glUniformMatrix4fv(location, valCount, GL_FALSE, uniform.floatPtr()); break;
case Uniform::UNDEFINED: CVF_FAIL_MSG("Unhandled type");
}
}
//--------------------------------------------------------------------------------------------------
/// Specify value of a uniform variable in this shader program
///
/// \return Returns false if the uniform doesn't exist in this shader program.
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::applyUniform(OpenGLContext* oglContext, const Uniform& uniform)
{
int location = uniformLocation(uniform.name());
if (location == -1)
{
// If you end up here one of the following might have happened
// - the shader program is not properly linked
// - the uniform name is wrong
// - the specified uniform name is declared but not actually used in the program
// It is actually necessary to make the texture have influence on the resulting color, not just touch
// the texture.
CVF_LOG_RENDER_ERROR(oglContext, String("In program '%1', error applying uniform: %2").arg(programName()).arg(uniform.name()));
return false;
}
applyUniformAtLocation(oglContext, location, uniform);
m_appliedUniformLocations.insert(location);
CVF_CHECK_OGL(oglContext);
return true;
}
//--------------------------------------------------------------------------------------------------
/// Specify values of uniform variables in this shader program
///
/// \return Returns true if all uniforms in the uniform set were applied successfully. Returns false
/// if any of the uniforms didn't exist in the shader program.
///
/// \sa applyUniform(), applyActiveUniformsOnly()
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::applyUniforms(OpenGLContext* oglContext, const UniformSet& uniformSet)
{
bool allUniformsSuccess = true;
size_t numUniforms = uniformSet.count();
size_t i;
for (i = 0; i < numUniforms; i++)
{
const Uniform* uniform = uniformSet.uniform(i);
allUniformsSuccess &= applyUniform(oglContext, *uniform);
}
return allUniformsSuccess;
}
//--------------------------------------------------------------------------------------------------
/// Apply only uniforms that are active in this shader program
///
/// As opposed to applyUniforms() this function will allow uniform sets consisting of uniforms that are
/// not active in the shader program.
//--------------------------------------------------------------------------------------------------
void ShaderProgram::applyActiveUniformsOnly(OpenGLContext* oglContext, const UniformSet& uniformSet)
{
size_t numUniforms = uniformSet.count();
size_t i;
for (i = 0; i < numUniforms; i++)
{
const Uniform* uniform = uniformSet.uniform(i);
int location = uniformLocation(uniform->name());
if (location != -1)
{
applyUniformAtLocation(oglContext, location, *uniform);
m_appliedUniformLocations.insert(location);
}
}
CVF_CHECK_OGL(oglContext);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::applyFixedUniforms(OpenGLContext* oglContext, const MatrixState& matrixState)
{
CVF_CALLSITE_OPENGL(oglContext);
std::map<FixedUniform, int>::const_iterator it;
for (it = m_fixedUniformsMap.begin(); it != m_fixedUniformsMap.end(); ++it)
{
int location = it->second;
CVF_ASSERT(location >= 0);
FixedUniform fixedUniform = it->first;
switch (fixedUniform)
{
case PROJECTION_MATRIX: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.projectionMatrix().ptr()); break;
case VIEW_MATRIX: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.viewMatrix().ptr()); break;
case VIEW_MATRIX_INVERSE: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.viewMatrixInverse().ptr()); break;
case MODEL_MATRIX: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelMatrix().ptr()); break;
case MODEL_MATRIX_INVERSE: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelMatrixInverse().ptr()); break;
case MODEL_MATRIX_INVERSE_TRANSPOSE: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelMatrixInverseTranspose().ptr()); break;
case MODEL_VIEW_MATRIX: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelViewMatrix().ptr()); break;
case MODEL_VIEW_MATRIX_INVERSE: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelViewMatrixInverse().ptr()); break;
case MODEL_VIEW_PROJECTION_MATRIX: glUniformMatrix4fv(location, 1, GL_FALSE, matrixState.modelViewProjectionMatrix().ptr()); break;
case NORMAL_MATRIX: glUniformMatrix3fv(location, 1, GL_FALSE, matrixState.normalMatrix().ptr()); break;
case VIEWPORT_WIDTH: glUniform1i(location, static_cast<GLint>(matrixState.viewportSize().x())); break;
case VIEWPORT_HEIGHT: glUniform1i(location, static_cast<GLint>(matrixState.viewportSize().y())); break;
case PIXEL_HEIGHT_AT_UNIT_DISTANCE: glUniform1f(location, matrixState.pixelHeightAtUnitDistance()); break;
default:
CVF_FAIL_MSG("Unhandled fixed uniform");
break;
}
// Assume that the uniform got set
// Hitting default clause implies programming error
m_appliedUniformLocations.insert(location);
CVF_CHECK_OGL(oglContext);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::clearUniformApplyTracking()
{
m_appliedUniformLocations.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::checkReportAllUniformsApplied(OpenGLContext* oglContext) const
{
const size_t numUniformsApplied = m_appliedUniformLocations.size();
const size_t numUniforms = m_fixedUniformsNameLocationMap.size() + m_uniformsNameLocationMap.size();
if (numUniforms != numUniformsApplied)
{
std::map<std::string, int>::const_iterator it;
for (it = m_uniformsNameLocationMap.begin(); it != m_uniformsNameLocationMap.end(); ++it)
{
int uniformLocation = it->second;
if (m_appliedUniformLocations.find(uniformLocation) == m_appliedUniformLocations.end())
{
std::string uniformName(it->first);
if (m_uniformsDisabledFromTracking.find(uniformName) == m_uniformsDisabledFromTracking.end())
{
CVF_LOG_RENDER_ERROR(oglContext, String("In program '%1', uniform not set: %2").arg(programName()).arg(uniformName));
}
}
}
for (it = m_fixedUniformsNameLocationMap.begin(); it != m_fixedUniformsNameLocationMap.end(); ++it)
{
int uniformLocation = it->second;
if (m_appliedUniformLocations.find(uniformLocation) == m_appliedUniformLocations.end())
{
CVF_LOG_RENDER_ERROR(oglContext, String("In program '%1', fixed uniform not set: %2").arg(programName()).arg(String(it->first)));
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::disableUniformTrackingForUniform(const char* name)
{
m_uniformsDisabledFromTracking.insert(name);
}
//--------------------------------------------------------------------------------------------------
/// Returns integer that represents the location of the specific uniform variable
///
/// This function returns -1 if the name does not correspond to an active uniform variable in
/// the program.
//--------------------------------------------------------------------------------------------------
int ShaderProgram::uniformLocation(const char* name) const
{
std::map<std::string, int>::const_iterator it = m_uniformsNameLocationMap.find(name);
if (it != m_uniformsNameLocationMap.end())
{
return it->second;
}
// Not found amongst general uniforms. Now try the fixed ones
it = m_fixedUniformsNameLocationMap.find(name);
if (it != m_fixedUniformsNameLocationMap.end())
{
return it->second;
}
return -1;
}
//--------------------------------------------------------------------------------------------------
/// Does discovery of active uniforms in this program.
///
/// Finds all active uniforms in the (linked) shader program and categorizes them as either fixed
/// or general uniforms. Stores the location for the uniforms for later usage.
//--------------------------------------------------------------------------------------------------
void ShaderProgram::discoverActiveUniforms(OpenGLContext* oglContext)
{
CVF_CALLSITE_OPENGL(oglContext);
m_fixedUniformsMap.clear();
m_fixedUniformsNameLocationMap.clear();
m_uniformsNameLocationMap.clear();
m_appliedUniformLocations.clear();
GLint numActiveUniforms = 0;
GLint maxUniformNameLength = 0;
glGetProgramiv(m_oglRcProgram->oglId(), GL_ACTIVE_UNIFORMS, &numActiveUniforms);
glGetProgramiv(m_oglRcProgram->oglId(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformNameLength);
if (numActiveUniforms <= 0 || maxUniformNameLength <= 0)
{
return;
}
CharArray uniformNameBuffer(static_cast<size_t>(maxUniformNameLength), 0);
const GLsizei bufferSize = static_cast<GLsizei>(uniformNameBuffer.size());
uint i;
for (i = 0; i < static_cast<uint>(numActiveUniforms); i++)
{
GLsizei numCharsInName = 0;
GLint uniformSize = 0;
GLenum uniformDataType = 0;
glGetActiveUniform(m_oglRcProgram->oglId(), i, bufferSize, &numCharsInName, &uniformSize, &uniformDataType, uniformNameBuffer.ptr());
CVF_CHECK_OGL(oglContext);
//Trace::show("%d: uniformSize=%d uniformDataType=%d uniformName=%s", i, uniformSize, uniformDataType, uniformNameBuffer.ptr());
if (numCharsInName > 0)
{
std::string uniformName = uniformNameBuffer.ptr();
// Added this code to fix a bug in the Nvidia drivers that reports arrays as xxx[0], like u_ecClipPlanes reported as u_ecClipPlanes[0]
size_t bracketPos = uniformName.find('[');
if (bracketPos != std::string::npos)
{
uniformName.resize(bracketPos);
}
int location = glGetUniformLocation(m_oglRcProgram->oglId(), uniformName.c_str());
CVF_CHECK_OGL(oglContext);
FixedUniform fixedUniform;
if (ShaderProgram::mapUniformNameToFixedUniformEnum(uniformName.c_str(), &fixedUniform))
{
m_fixedUniformsMap[fixedUniform] = location;
m_fixedUniformsNameLocationMap[uniformName] = location;
}
else
{
m_uniformsNameLocationMap[uniformName] = location;
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::mapUniformNameToFixedUniformEnum(const char* uniformName, FixedUniform* fixedUniform)
{
CVF_ASSERT(uniformName);
CVF_ASSERT(fixedUniform);
if (System::strcmp(uniformName, "cvfu_projectionMatrix") == 0) { *fixedUniform = PROJECTION_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_viewMatrix") == 0) { *fixedUniform = VIEW_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_viewMatrixInverse") == 0) { *fixedUniform = VIEW_MATRIX_INVERSE; return true; }
else if (System::strcmp(uniformName, "cvfu_modelMatrix") == 0) { *fixedUniform = MODEL_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_modelMatrixInverse") == 0) { *fixedUniform = MODEL_MATRIX_INVERSE; return true; }
else if (System::strcmp(uniformName, "cvfu_modelMatrixInverseTranspose") == 0) { *fixedUniform = MODEL_MATRIX_INVERSE_TRANSPOSE; return true; }
else if (System::strcmp(uniformName, "cvfu_modelViewMatrix") == 0) { *fixedUniform = MODEL_VIEW_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_modelViewMatrixInverse") == 0) { *fixedUniform = MODEL_VIEW_MATRIX_INVERSE; return true; }
else if (System::strcmp(uniformName, "cvfu_modelViewProjectionMatrix") == 0) { *fixedUniform = MODEL_VIEW_PROJECTION_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_normalMatrix") == 0) { *fixedUniform = NORMAL_MATRIX; return true; }
else if (System::strcmp(uniformName, "cvfu_viewportWidth") == 0) { *fixedUniform = VIEWPORT_WIDTH; return true; }
else if (System::strcmp(uniformName, "cvfu_viewportHeight") == 0) { *fixedUniform = VIEWPORT_HEIGHT; return true; }
else if (System::strcmp(uniformName, "cvfu_pixelHeightAtUnitDistance") == 0) { *fixedUniform = PIXEL_HEIGHT_AT_UNIT_DISTANCE; return true; }
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
/// Returns the index of the vertex attribute that is bound to attribute variable specified by name
///
/// Returns -1 if the name does not correspond to an active attribute or if name starts with the
/// reserved "gl_" prefix.
///
/// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glGetAttribLocation.xml
//--------------------------------------------------------------------------------------------------
int ShaderProgram::attributeLocation(OpenGLContext* oglContext, const char* name) const
{
CVF_CALLSITE_OPENGL(oglContext);
if (OglRc::safeOglId(m_oglRcProgram.p()) != 0)
{
GLint attribIndex = glGetAttribLocation(m_oglRcProgram->oglId(), name);
return attribIndex;
}
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ShaderProgram::bindFixedAttributes(OpenGLContext* oglContext)
{
CVF_CALLSITE_OPENGL(oglContext);
CVF_ASSERT(OglRc::safeOglId(m_oglRcProgram.p()) != 0);
glBindAttribLocation(m_oglRcProgram->oglId(), VERTEX, "cvfa_vertex");
glBindAttribLocation(m_oglRcProgram->oglId(), NORMAL, "cvfa_normal");
glBindAttribLocation(m_oglRcProgram->oglId(), COLOR, "cvfa_color");
glBindAttribLocation(m_oglRcProgram->oglId(), TEX_COORD_2F_0,"cvfa_texCoord");
CVF_CHECK_OGL(oglContext);
}
//--------------------------------------------------------------------------------------------------
/// Query if the current OpenGL context supports shaders
//--------------------------------------------------------------------------------------------------
bool ShaderProgram::supportedOpenGL(OpenGLContext* oglContext)
{
return oglContext->capabilities()->supportsOpenGL2();
}
} // namespace cvf