SparrowRenderer/src/forwardmodule.cpp
2016-04-21 17:14:22 +02:00

207 lines
6.9 KiB
C++

#include "forwardmodule.h"
#include "scene.h"
#include "mesh.h"
#include "shader.h"
#include "light.h"
#include "texture.h"
#include <glm/ext.hpp>
void ForwardModule::renderGL(Camera* myCamera, Scene* scene)
{
// bind target
renderTarget->bindFBO();
if(clearBeforeDrawing)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width, height);
// render ambient lighting
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
lightPass(myCamera, scene, NULL);
// render directionnal lighting and point lighting
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE);
for(SceneIterator<Light*>* lightIt = scene->getLights(); lightIt->isValid(); lightIt->next())
lightPass(myCamera, scene, lightIt->getItem());
glDisable(GL_BLEND);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
}
void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light)
{
if(isWireframe){
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}else{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
// loop over all types of geometry
for(std::size_t i=0; i<geometryFlagList.size(); ++i)
{
std::size_t j;
for(j=0; j<lightFlagList.size(); ++j)
if(lightFlagList[j] == light->getFlags())
break;
if(j == lightFlagList.size())
{
fprintf(stderr, "WARNING : missing shader for the light");
continue;
}
Shader* shader = shaders[i*lightFlagList.size() + j];
shader->bind();
// bind light attributes
switch(light->getType())
{
case Light::AMBIENT:
shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); // add attribute, and setter for ambient lighting
break;
case Light::DIRECTIONNAL:
shader->bindVec3(shader->getLocation("dirLight"), -light->getDir());
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
if(light->isShadowCaster())
{
light->getShadowMap()->bind(PhongMaterial::NB_PHONG_SLOTS); // NB_PHONG_SLOTS has the value of the first available slot after the phong material texture slots
shader->bindInteger(shader->getLocation("shadowMap"), PhongMaterial::NB_PHONG_SLOTS);
}
break;
case Light::POINT:
shader->bindVec3(shader->getLocation("pointLight"), light->getPos());
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
shader->bindFloat(shader->getLocation("attenuation"), light->getAttenuation());
break;
case Light::SPOT:
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
// TODO add cutoff and attenuation
break;
}
unsigned int id = 2;
for(SceneIterator<GeometryNode*>* geometryIt = scene->getGeometry();
geometryIt->isValid(); geometryIt->next())
{
GeometryNode* node = geometryIt->getItem();
shader->bindUnsignedInteger(shader->getLocation("object_identifier"), id);
if(node->mesh->hasInstances())
id += node->mesh->instances_offsets.size();
else
++id;
Material* mat = node->mesh->material;
unsigned int flags = mat->getFlags();
if(node->mesh->hasInstances())
flags |= INSTANCING_FLAG;
if(flags == geometryFlagList[i]) // if flag matches material
{
// compute matrix attributes
glm::mat4 modelViewMatrix = myCamera->getViewMatrix() * node->modelMatrix;
glm::mat4 mvp = myCamera->getProjectionMatrix() * modelViewMatrix;
glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix));
if(light != NULL && light->isShadowCaster())
{
glm::mat4 lightMVP = Light::biasMatrix * light->getProjectionMatrix() * light->getViewMatrix() * node->modelMatrix;
shader->bindMat4(shader->getLocation("lightMVP"), lightMVP);
}
shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix());
shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix);
shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix));
shader->bindMat4(shader->getLocation("MVP"), mvp);
node->mesh->draw(shader);
}
}
}
}
// modern opengl methods
void ForwardModule::setShaderSource(ShaderSource* source)
{
if(shaderSources != NULL)
delete(shaderSources);
shaderSources = source;
}
void ForwardModule::compileShaders(Scene* scene)
{
geometryFlagList.clear();
lightFlagList.clear();
for(Shader* s : shaders)
delete(s);
shaders.clear();
// get material flags
const int nb_geometry_flags = 1 << NB_FLAGS;
bool geometryFlags[nb_geometry_flags];
for(int i=0; i<nb_geometry_flags; ++i)
geometryFlags[i] = false;
for(SceneIterator<GeometryNode*>* geometryIt = scene->getGeometry();
geometryIt->isValid(); geometryIt->next())
{
Mesh* m = geometryIt->getItem()->mesh;
unsigned int flags = m->material->getFlags();
if(m->hasInstances())
flags |= INSTANCING_FLAG;
geometryFlags[flags] = true;
}
for(int i=0; i<nb_geometry_flags; ++i)
{
if(geometryFlags[i])
geometryFlagList.push_back(i);
}
// get light flags
const int nb_light_flags = 1 << Light::NB_LIGHT_FLAGS;
bool lightFlags[nb_light_flags];
for(int i=0; i<nb_light_flags; ++i)
lightFlags[i] = false;
// ambient light
lightFlags[Light::getFlags(NULL)] = true;
// scene lights
for(SceneIterator<Light*>* lightIt = scene->getLights();
lightIt->isValid(); lightIt->next())
{
Light* l = lightIt->getItem();
lightFlags[Light::getFlags(l)] = true;
}
for(int i=0; i<nb_light_flags; ++i)
{
if(lightFlags[i])
lightFlagList.push_back(i);
}
// shader compilation
for(int i : geometryFlagList)
{
std::vector<const char*> defines;
std::size_t boundary = defines.size();
for(int j : lightFlagList)
{
while(defines.size() > boundary)
defines.pop_back();
// set light defines
for(int k=0; k<Light::NB_LIGHT_FLAGS; ++k)
{
if(j & (1 << k))
defines.push_back(Light::flagStr[k]);
}
// compilation
shaders.push_back(shaderSources->compile(defines.size(), defines.data()));
}
}
}
void ForwardModule::setRenderTarget(const FrameBuffer* target)
{
if(target != NULL)
renderTarget = target;
}