#include "LightNode.hpp"
#include "Camera.hpp"
#include "ColorUtils.hpp"
#include "Config.hpp"
#include "Debug.hpp"
#include "DirectionalLight.hpp"
#include "FrameBuffer.hpp"
#include "GlState.hpp"
#include "PointLight.hpp"
#include "Scene.hpp"
#include "ShadowVolumeCaster.hpp"
#include "SpotLight.hpp"
#include "TextureRtt.hpp"
#include "Transform.hpp"
#include "UniformBuffer.hpp"
#include "Viewport.hpp"
namespace wren {
glm::vec3 LightNode::cGlobalAmbientIntensity;
GlslLayout::Lights LightNode::cActiveLights;
std::vector<int> LightNode::cActiveLightsCastingShadows(LightNode::TYPE_COUNT, 0);
void LightNode::updateUniforms() {
const std::vector<DirectionalLight *> &directionalLights = Scene::instance()->directionalLights();
const std::vector<PointLight *> &pointLights = Scene::instance()->pointLights();
const std::vector<SpotLight *> &spotLights = Scene::instance()->spotLights();
const Camera *camera = Scene::instance()->currentViewport()->camera();
LightNode::cActiveLights.mAmbientLight = glm::vec4(LightNode::ambientLight(), 1.0f);
glm::int32 lightCount = 0;
for (DirectionalLight *l : directionalLights) {
if (!l->parent() || l->parent()->isVisible()) {
LightNode::cActiveLights.mDirectionalLights[lightCount].mColorAndIntensity = glm::vec4(l->color(), l->intensity()),
LightNode::cActiveLights.mDirectionalLights[lightCount].mDirection =
glm::normalize(camera->view() * glm::vec4(l->direction(), 0.0f));
++lightCount;
}
if (lightCount >= gMaxActiveDirectionalLights)
break;
}
LightNode::cActiveLights.mLightCount[0] = lightCount;
lightCount = 0;
for (PointLight *l : pointLights) {
if (!l->parent() || l->parent()->isVisible()) {
LightNode::cActiveLights.mPointLights[lightCount].mColorAndIntensity = glm::vec4(l->color(), l->intensity()),
LightNode::cActiveLights.mPointLights[lightCount].mPosition = camera->view() * glm::vec4(l->position(), 1.0);
LightNode::cActiveLights.mPointLights[lightCount].mAttenuationAndRadius =
glm::vec4(l->attenuationConstant(), l->attenuationLinear(), l->attenuationQuadratic(), l->radius());
++lightCount;
}
if (lightCount >= gMaxActivePointLights)
break;
}
LightNode::cActiveLights.mLightCount[1] = lightCount;
lightCount = 0;
for (SpotLight *l : spotLights) {
if (!l->parent() || l->parent()->isVisible()) {
LightNode::cActiveLights.mSpotLights[lightCount].mColorAndIntensity = glm::vec4(l->color(), l->intensity()),
LightNode::cActiveLights.mSpotLights[lightCount].mPosition = camera->view() * glm::vec4(l->position(), 1.0f);
LightNode::cActiveLights.mSpotLights[lightCount].mDirection =
glm::normalize(camera->view() * glm::vec4(l->direction(), 0.0f));
LightNode::cActiveLights.mSpotLights[lightCount].mAttenuationAndRadius =
glm::vec4(l->attenuationConstant(), l->attenuationLinear(), l->attenuationQuadratic(), l->radius());
LightNode::cActiveLights.mSpotLights[lightCount].mSpotParams =
glm::vec4(l->beamWidth(), l->cutOffAngle(), 1.0f / (l->cutOffAngle() - l->beamWidth()), 0.0f);
++lightCount;
}
if (lightCount >= gMaxActiveSpotLights)
break;
}
LightNode::cActiveLights.mLightCount[2] = lightCount;
glstate::uniformBuffer(WR_GLSL_LAYOUT_UNIFORM_BUFFER_LIGHTS)->writeValue(&LightNode::cActiveLights);
}
void LightNode::setOn(bool on) {
if (on == mOn)
return;
Scene::instance()->removeLight(this);
mOn = on;
Scene::instance()->addLight(this);
if (mCastShadows) {
if (on)
enableShadowCasting();
else
disableShadowCasting();
}
}
void LightNode::setColor(const glm::vec3 &color) {
mColor = colorutils::srgbToLinear(glm::vec4(color, 1.0));
}
void LightNode::setCastShadows(bool castShadows) {
if (mCastShadows == castShadows)
return;
mCastShadows = castShadows;
if (mOn) {
if (castShadows)
enableShadowCasting();
else
disableShadowCasting();
}
}
LightNode::LightNode() : mOn(true), mCastShadows(false), mIntensity(1.0f), mAmbientIntensity(0.0f), mColor(gVec3Ones) {
}
LightNode::~LightNode() {
if (mOn && mCastShadows) {
for (auto entry : mShadowListeners)
entry.second->notifyLightRemoved(this);
}
}
void LightNode::enableShadowCasting() {
++LightNode::cActiveLightsCastingShadows[this->type()];
}
void LightNode::disableShadowCasting() {
--LightNode::cActiveLightsCastingShadows[this->type()];
for (auto entry : mShadowListeners)
entry.second->notifyLightRemoved(this);
mShadowListeners.clear();
}
}