Skip to content

Commit

Permalink
Model Renderer|libgui: Don't try to bind uniforms that don't exist
Browse files Browse the repository at this point in the history
The variables defined in the render block, outside any passes, apply
to all passes. However, if a pass uses a different shader, it may not
have the same variables.
  • Loading branch information
skyjake committed Nov 3, 2015
1 parent 6547161 commit 61c595d
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 10 deletions.
18 changes: 18 additions & 0 deletions doomsday/apps/client/include/render/modelrenderer.h
Expand Up @@ -87,6 +87,24 @@ class ModelRenderer
*/
void render(vispsprite_t const &pspr);

/**
* Looks up the name of a shader based on a GLProgram instance.
*
* @param program Shader program. Must be a shader program
* created and owned by ModelRenderer.
* @return Name of the shader (in the shader bank).
*/
de::String shaderName(de::GLProgram const &program) const;

/**
* Looks up the definition of a shader based on a GLProgram instance.
*
* @param program Shader program. Must be a shader program
* created and owned by ModelRenderer.
* @return Shader definition record.
*/
de::Record const &shaderDefinition(de::GLProgram const &program) const;

public:
static void initBindings(de::Binder &binder, de::Record &module);

Expand Down
12 changes: 12 additions & 0 deletions doomsday/apps/client/src/render/modelrenderer.cpp
Expand Up @@ -70,6 +70,7 @@ DENG2_PIMPL(ModelRenderer)
struct Program : public GLProgram
{
String shaderName;
Record const *def = nullptr;
int useCount = 1; ///< Number of models using the program.
};

Expand Down Expand Up @@ -217,6 +218,7 @@ DENG2_PIMPL(ModelRenderer)

std::unique_ptr<Program> prog(new Program);
prog->shaderName = name;
prog->def = &ClientApp::shaders()[name].valueAsRecord(); // for lookups later

LOG_RES_VERBOSE("Loading model shader \"%s\"") << name;

Expand Down Expand Up @@ -722,6 +724,16 @@ void ModelRenderer::render(vispsprite_t const &pspr)
GLState::current().setCull(gl::Back).apply();
}

String ModelRenderer::shaderName(GLProgram const &program) const
{
return static_cast<Instance::Program const &>(program).shaderName;
}

Record const &ModelRenderer::shaderDefinition(GLProgram const &program) const
{
return *static_cast<Instance::Program const &>(program).def;
}

int ModelRenderer::identifierFromText(String const &text,
std::function<int (String const &)> resolver) // static
{
Expand Down
27 changes: 25 additions & 2 deletions doomsday/apps/client/src/render/stateanimator.cpp
Expand Up @@ -126,6 +126,8 @@ DENG2_PIMPL(StateAnimator)
Record names; ///< Local context for scripts, i.e., per-object model state.

ModelDrawable::Appearance appearance;

// Lookups used when drawing or updating state:
QHash<String, int> indexForPassName;
QHash<Variable *, int> passForMaterialVariable;

Expand Down Expand Up @@ -221,7 +223,7 @@ DENG2_PIMPL(StateAnimator)

initVariables();

// Set up the appearance.
// Set up the model drawing parameters.
if(!self.model().passes.isEmpty())
{
appearance.drawPasses = &self.model().passes;
Expand Down Expand Up @@ -258,7 +260,10 @@ DENG2_PIMPL(StateAnimator)
}
else
{
for(int i = 0; i < passCount; ++i) appearance.passMaterial << 0;
for(int i = 0; i < passCount; ++i)
{
appearance.passMaterial << 0;
}
}
appearance.passMask.resize(passCount);

Expand Down Expand Up @@ -499,6 +504,18 @@ DENG2_PIMPL(StateAnimator)
}
}

/**
* Checks if a shader definition has a declaration for a variable.
*
* @param program Shader definition.
* @param uniform Uniform.
* @return @c true, if a variable exists matching @a uniform.
*/
static bool hasDeclaredVariable(Record const &shaderDef, GLUniform const &uniform)
{
return shaderDef.hasMember(String::fromUtf8(uniform.name()));
}

/**
* Binds or unbinds uniforms that apply to all rendering passes.
*
Expand All @@ -522,11 +539,17 @@ DENG2_PIMPL(StateAnimator)
de::String const &passName,
BindOperation operation) const
{
auto const &modelRenderer = ClientApp::renderSystem().modelRenderer();

auto const vars = passVars.constFind(passName);
if(vars != passVars.constEnd())
{
for(auto i : vars.value())
{
if(!hasDeclaredVariable(modelRenderer.shaderDefinition(program),
*i->uniform))
continue;

if(operation == Bind)
{
i->updateUniform();
Expand Down
4 changes: 3 additions & 1 deletion doomsday/sdk/libgui/include/de/graphics/glprogram.h
Expand Up @@ -13,7 +13,7 @@
* 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 program; if not, see:
* http://www.gnu.org/licenses</small>
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBGUI_GLPROGRAM_H
Expand Down Expand Up @@ -106,6 +106,8 @@ class LIBGUI_PUBLIC GLProgram : public Asset

int glUniformLocation(char const *uniformName) const;

bool glHasUniform(char const *uniformName) const;

/**
* Determines which attribute location is used for a particular attribute semantic.
* These locations are available after the program has been successfully built
Expand Down
13 changes: 6 additions & 7 deletions doomsday/sdk/libgui/src/graphics/glprogram.cpp
Expand Up @@ -494,13 +494,12 @@ GLuint GLProgram::glName() const

int GLProgram::glUniformLocation(char const *uniformName) const
{
GLint loc = glGetUniformLocation(d->name, uniformName);
if(loc < 0)
{
LOG_AS("GLProgram");
LOGDEV_GL_WARNING("Could not find uniform '%s'") << uniformName;
}
return loc;
return glGetUniformLocation(d->name, uniformName);
}

bool GLProgram::glHasUniform(char const *uniformName) const
{
return glUniformLocation(uniformName) >= 0;
}

int GLProgram::attributeLocation(AttribSpec::Semantic semantic) const
Expand Down

0 comments on commit 61c595d

Please sign in to comment.