diff --git a/src/render/software/AtmosphereModelBruneton.cpp b/src/render/software/AtmosphereModelBruneton.cpp index d8efadc..77118b1 100644 --- a/src/render/software/AtmosphereModelBruneton.cpp +++ b/src/render/software/AtmosphereModelBruneton.cpp @@ -15,6 +15,7 @@ #include "Scenery.h" #include "AtmosphereDefinition.h" #include "AtmosphereRenderer.h" +#include "AtmosphereResult.h" #include "SoftwareRenderer.h" #include "WaterRenderer.h" #include "LightComponent.h" @@ -1153,6 +1154,10 @@ AtmosphereModelBruneton::AtmosphereModelBruneton(SoftwareRenderer *parent): { } +AtmosphereModelBruneton::~AtmosphereModelBruneton() +{ +} + AtmosphereResult AtmosphereModelBruneton::getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base) { Vector3 x = {0.0, Rg + eye.y * WORLD_SCALING, 0.0}; @@ -1215,12 +1220,12 @@ AtmosphereResult AtmosphereModelBruneton::applyAerialPerspective(Vector3 locatio return result; } -void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vector3 &, int) +bool AtmosphereModelBruneton::getLightsAt(std::vector &result, const Vector3 &location) const { LightComponent sun, irradiance; double muS; - double altitude = status->getLocation().y * WORLD_SCALING; + double altitude = location.y * WORLD_SCALING; double r0 = Rg + WORKAROUND_OFFSET + altitude; Vector3 up = {0.0, 1.0, 0.0}; @@ -1241,14 +1246,16 @@ void AtmosphereModelBruneton::fillLightingStatus(LightStatus *status, const Vect sun.reflection = ISun; sun.altered = 1; - status->pushComponent(sun); + result.push_back(sun); irradiance.color = _irradiance(_irradianceTexture, r0, muS); irradiance.direction = VECTOR_DOWN; irradiance.reflection = 0.0; irradiance.altered = 0; - status->pushComponent(irradiance); + result.push_back(irradiance); + + return true; } Texture2D *AtmosphereModelBruneton::getTextureTransmittance() const diff --git a/src/render/software/AtmosphereModelBruneton.h b/src/render/software/AtmosphereModelBruneton.h index 7d0aa8b..d826172 100644 --- a/src/render/software/AtmosphereModelBruneton.h +++ b/src/render/software/AtmosphereModelBruneton.h @@ -3,19 +3,20 @@ #include "software_global.h" -#include "AtmosphereResult.h" +#include "LightSource.h" namespace paysages { namespace software { -class SOFTWARESHARED_EXPORT AtmosphereModelBruneton +class SOFTWARESHARED_EXPORT AtmosphereModelBruneton: public LightSource { public: AtmosphereModelBruneton(SoftwareRenderer *parent); + virtual ~AtmosphereModelBruneton(); AtmosphereResult getSkyColor(Vector3 eye, const Vector3 &direction, const Vector3 &sun_position, const Color &base); AtmosphereResult applyAerialPerspective(Vector3 location, const Color &base); - void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque); + virtual bool getLightsAt(std::vector &result, const Vector3 &location) const override; /* Functions to get access to internal textures (for opengl shaders) */ Texture2D* getTextureTransmittance() const; diff --git a/src/render/software/AtmosphereRenderer.cpp b/src/render/software/AtmosphereRenderer.cpp index 5be7ba1..15218b8 100644 --- a/src/render/software/AtmosphereRenderer.cpp +++ b/src/render/software/AtmosphereRenderer.cpp @@ -80,15 +80,6 @@ static inline void _applyWeatherEffects(AtmosphereDefinition* definition, Atmosp BaseAtmosphereRenderer::BaseAtmosphereRenderer(SoftwareRenderer* renderer): parent(renderer) { - -} - -void BaseAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3, int) -{ - for (LightComponent light:lights) - { - status->pushComponent(light); - } } AtmosphereResult BaseAtmosphereRenderer::applyAerialPerspective(Vector3, Color base) @@ -109,50 +100,14 @@ AtmosphereResult BaseAtmosphereRenderer::getSkyColor(Vector3) Vector3 BaseAtmosphereRenderer::getSunDirection(bool cache) const { - if (cache and lights.size() > 0) - { - return lights[0].direction.scale(-1.0); - } - else - { - AtmosphereDefinition* atmosphere = getDefinition(); - double sun_angle = (atmosphere->propDayTime()->getValue() + 0.75) * M_PI * 2.0; - return Vector3(cos(sun_angle), sin(sun_angle), 0.0); - } + AtmosphereDefinition* atmosphere = getDefinition(); + double sun_angle = (atmosphere->propDayTime()->getValue() + 0.75) * M_PI * 2.0; + return Vector3(cos(sun_angle), sin(sun_angle), 0.0); } -void BaseAtmosphereRenderer::setBasicLights() +bool BaseAtmosphereRenderer::getLightsAt(std::vector &, const Vector3 &) const { - LightComponent light; - - lights.clear(); - - light.color.r = 0.6; - light.color.g = 0.6; - light.color.b = 0.6; - light.direction.x = -1.0; - light.direction.y = -0.5; - light.direction.z = 1.0; - light.direction = light.direction.normalize(); - light.altered = 1; - light.reflection = 0.0; - lights.push_back(light); - - light.color.r = 0.2; - light.color.g = 0.2; - light.color.b = 0.2; - light.direction.x = 1.0; - light.direction.y = -0.5; - light.direction.z = -1.0; - light.direction = light.direction.normalize(); - light.altered = 0; - light.reflection = 0.0; - lights.push_back(light); -} - -void BaseAtmosphereRenderer::setStaticLights(const std::vector &lights) -{ - this->lights = lights; + return false; } AtmosphereDefinition* BaseAtmosphereRenderer::getDefinition() const @@ -171,12 +126,6 @@ SoftwareBrunetonAtmosphereRenderer::~SoftwareBrunetonAtmosphereRenderer() delete model; } -void SoftwareBrunetonAtmosphereRenderer::getLightingStatus(LightStatus* status, Vector3 normal, int opaque) -{ - model->fillLightingStatus(status, normal, opaque); - parent->getNightSky()->fillLightingStatus(status, normal, opaque); -} - AtmosphereResult SoftwareBrunetonAtmosphereRenderer::applyAerialPerspective(Vector3 location, Color base) { AtmosphereDefinition* definition = getDefinition(); @@ -258,3 +207,11 @@ AtmosphereResult SoftwareBrunetonAtmosphereRenderer::getSkyColor(Vector3 directi return result; } + +bool SoftwareBrunetonAtmosphereRenderer::getLightsAt(std::vector &result, const Vector3 &location) const +{ + bool changed = false; + changed |= model->getLightsAt(result, location); + changed |= parent->getNightSky()->getLightsAt(result, location); + return changed; +} diff --git a/src/render/software/AtmosphereRenderer.h b/src/render/software/AtmosphereRenderer.h index 48969e0..7f22aec 100644 --- a/src/render/software/AtmosphereRenderer.h +++ b/src/render/software/AtmosphereRenderer.h @@ -3,30 +3,26 @@ #include "software_global.h" -#include "Color.h" -#include "LightComponent.h" +#include "LightSource.h" namespace paysages { namespace software { -class BaseAtmosphereRenderer +class BaseAtmosphereRenderer: public LightSource { public: BaseAtmosphereRenderer(SoftwareRenderer* parent); virtual ~BaseAtmosphereRenderer() {} - virtual void getLightingStatus(LightStatus* status, Vector3 normal, int opaque); virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base); virtual AtmosphereResult getSkyColor(Vector3 direction); virtual Vector3 getSunDirection(bool cache=true) const; - void setBasicLights(); - void setStaticLights(const std::vector &lights); + virtual bool getLightsAt(std::vector &result, const Vector3 &location) const override; protected: virtual AtmosphereDefinition* getDefinition() const; SoftwareRenderer* parent; - std::vector lights; }; class SoftwareBrunetonAtmosphereRenderer: public BaseAtmosphereRenderer @@ -35,10 +31,11 @@ public: SoftwareBrunetonAtmosphereRenderer(SoftwareRenderer* parent); virtual ~SoftwareBrunetonAtmosphereRenderer(); - virtual void getLightingStatus(LightStatus* status, Vector3 normal, int opaque) override; virtual AtmosphereResult applyAerialPerspective(Vector3 location, Color base) override; virtual AtmosphereResult getSkyColor(Vector3 direction) override; + virtual bool getLightsAt(std::vector &result, const Vector3 &location) const override; + inline const AtmosphereModelBruneton* getModel() const {return model;} private: diff --git a/src/render/software/LightSource.cpp b/src/render/software/LightSource.cpp new file mode 100644 index 0000000..934a276 --- /dev/null +++ b/src/render/software/LightSource.cpp @@ -0,0 +1 @@ +#include "LightSource.h" diff --git a/src/render/software/LightSource.h b/src/render/software/LightSource.h new file mode 100644 index 0000000..9cf8751 --- /dev/null +++ b/src/render/software/LightSource.h @@ -0,0 +1,28 @@ +#ifndef LIGHTSOURCE_H +#define LIGHTSOURCE_H + +#include "software_global.h" + +namespace paysages { +namespace software { + +/** + * Source of dynamic lights. + */ +class SOFTWARESHARED_EXPORT LightSource +{ +public: + LightSource() = default; + + /** + * Get the list of raw lights that may be applied at a given location. + * + * Returns true if lights were added to *result*. + */ + virtual bool getLightsAt(std::vector &result, const Vector3 &location) const = 0; +}; + +} +} + +#endif // LIGHTSOURCE_H diff --git a/src/render/software/LightingManager.cpp b/src/render/software/LightingManager.cpp index 040b0c3..e352489 100644 --- a/src/render/software/LightingManager.cpp +++ b/src/render/software/LightingManager.cpp @@ -2,6 +2,8 @@ #include "LightFilter.h" #include "LightComponent.h" +#include "LightStatus.h" +#include "LightSource.h" #include "Color.h" #include "SurfaceMaterial.h" @@ -10,9 +12,55 @@ LightingManager::LightingManager() specularity = true; } +int LightingManager::getStaticLightsCount() const +{ + return static_lights.size(); +} + +int LightingManager::getSourcesCount() const +{ + return sources.size(); +} + +int LightingManager::getFiltersCount() const +{ + return filters.size(); +} + +void LightingManager::clearStaticLights() +{ + static_lights.clear(); +} + +void LightingManager::addStaticLight(const LightComponent &light) +{ + static_lights.push_back(light); +} + +void LightingManager::registerSource(LightSource *source) +{ + if (std::find(sources.begin(), sources.end(), source) == sources.end()) + { + sources.push_back(source); + } +} + +void LightingManager::unregisterSource(LightSource *source) +{ + sources.erase(std::find(sources.begin(), sources.end(), source)); +} + void LightingManager::registerFilter(LightFilter* filter) { - filters.push_back(filter); + if (std::find(filters.begin(), filters.end(), filter) == filters.end()) + { + filters.push_back(filter); + } +} + +void LightingManager::unregisterFilter(LightFilter *filter) +{ + filters.erase(std::find(filters.begin(), filters.end(), filter)); } bool LightingManager::alterLight(LightComponent &component, const Vector3 &location) @@ -119,3 +167,26 @@ Color LightingManager::applyFinalComponent(const LightComponent &component, cons return result; } + +Color LightingManager::apply(const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material) +{ + LightStatus status(this, location, eye); + + for (auto &light: static_lights) + { + status.pushComponent(light); + } + for (auto source: sources) + { + std::vector lights; + if (source->getLightsAt(lights, location)) + { + for (auto &light: lights) + { + status.pushComponent(light); + } + } + } + + return status.apply(normal, material); +} diff --git a/src/render/software/LightingManager.h b/src/render/software/LightingManager.h index 8142abe..027d032 100644 --- a/src/render/software/LightingManager.h +++ b/src/render/software/LightingManager.h @@ -3,44 +3,86 @@ #include "software_global.h" +#include "LightComponent.h" + namespace paysages { namespace software { /** * @brief Global lighting manager. * - * This manager handles the light filters and final light rendering. + * This manager handles the lights, light filters and final light rendering. + * + * There are both static and dynamic lights. + * A dynamic light depends on the location at which the lighting occurs. */ class SOFTWARESHARED_EXPORT LightingManager { public: LightingManager(); - /** - * @brief Register a filter that will receive all alterable lights. - */ - void registerFilter(LightFilter* filter); + int getStaticLightsCount() const; + int getSourcesCount() const; + int getFiltersCount() const; /** - * @brief Alter the light component at a given location. - * @return true if the light is useful + * Clear the static lights. + */ + void clearStaticLights(); + + /** + * Add a static light. + */ + void addStaticLight(const LightComponent &light); + + /** + * Register a source of dynamic lighting. + */ + void registerSource(LightSource *source); + + /** + * Remove a registered light source. + */ + void unregisterSource(LightSource *source); + + /** + * Register a filter that will receive all alterable lights. + */ + void registerFilter(LightFilter *filter); + + /** + * Remove a registered light filter. + */ + void unregisterFilter(LightFilter *filter); + + /** + * Alter the light component at a given location. + * + * Returns true if the light is useful */ bool alterLight(LightComponent &component, const Vector3 &location); /** - * @brief Enable or disable the specularity lighting. + * Enable or disable the specularity lighting. */ void setSpecularity(bool enabled); /** - * @brief Apply a final component on a surface material. + * Apply a final component on a surface material. */ Color applyFinalComponent(const LightComponent &component, const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material); + /** + * Apply lighting to a surface at a given location. + */ + Color apply(const Vector3 &eye, const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material); + private: int specularity; + std::vector static_lights; + std::vector filters; + std::vector sources; - std::vector filters; }; } diff --git a/src/render/software/NightSky.cpp b/src/render/software/NightSky.cpp index c8b107b..6cb4bd9 100644 --- a/src/render/software/NightSky.cpp +++ b/src/render/software/NightSky.cpp @@ -95,7 +95,7 @@ const Color NightSky::getColor(double altitude, const Vector3 &direction) } -void NightSky::fillLightingStatus(LightStatus *status, const Vector3 &, int) +bool NightSky::getLightsAt(std::vector &result, const Vector3 &location) const { LightComponent moon, sky; @@ -107,12 +107,14 @@ void NightSky::fillLightingStatus(LightStatus *status, const Vector3 &, int) moon.reflection = 0.2; moon.altered = 1; - status->pushComponent(moon); + result.push_back(moon); sky.color = Color(0.01, 0.012, 0.03); sky.direction = VECTOR_DOWN; sky.reflection = 0.0; sky.altered = 0; - status->pushComponent(sky); + result.push_back(sky); + + return true; } diff --git a/src/render/software/NightSky.h b/src/render/software/NightSky.h index c1bc3c5..c305f21 100644 --- a/src/render/software/NightSky.h +++ b/src/render/software/NightSky.h @@ -3,13 +3,15 @@ #include "software_global.h" +#include "LightSource.h" + namespace paysages { namespace software { /*! * \brief Night sky renderer. */ -class SOFTWARESHARED_EXPORT NightSky +class SOFTWARESHARED_EXPORT NightSky: public LightSource { public: NightSky(SoftwareRenderer* renderer); @@ -26,7 +28,7 @@ public: */ virtual const Color getColor(double altitude, const Vector3 &direction); - virtual void fillLightingStatus(LightStatus *status, const Vector3 &normal, int opaque); + virtual bool getLightsAt(std::vector &result, const Vector3 &location) const override; private: SoftwareRenderer* renderer; diff --git a/src/render/software/SoftwareRenderer.cpp b/src/render/software/SoftwareRenderer.cpp index 83c59e8..d8509cc 100644 --- a/src/render/software/SoftwareRenderer.cpp +++ b/src/render/software/SoftwareRenderer.cpp @@ -41,6 +41,7 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery): lighting->registerFilter(water_renderer); lighting->registerFilter(terrain_renderer); lighting->registerFilter(clouds_renderer); + lighting->registerSource(atmosphere_renderer); setQuality(0.5); } @@ -66,7 +67,8 @@ void SoftwareRenderer::prepare() scenery->validate(); // Prepare sub renderers - // TODO Don't recreate the renderer each time + // TODO Don't recreate the renderer each time, only when it changes + lighting->unregisterSource(atmosphere_renderer); delete atmosphere_renderer; if (getScenery()->getAtmosphere()->model == AtmosphereDefinition::ATMOSPHERE_MODEL_BRUNETON) { @@ -76,6 +78,7 @@ void SoftwareRenderer::prepare() { atmosphere_renderer = new BaseAtmosphereRenderer(this); } + lighting->registerSource(atmosphere_renderer); clouds_renderer->update(); terrain_renderer->update(); @@ -98,50 +101,9 @@ void SoftwareRenderer::setQuality(double quality) render_quality = (int)(quality * 9.0) + 1; } -void SoftwareRenderer::disableAtmosphere() -{ - LightComponent light; - std::vector lights; - - light.color.r = 1.5; - light.color.g = 1.5; - light.color.b = 1.5; - light.direction.x = -1.0; - light.direction.y = -0.3; - light.direction.z = 1.0; - light.direction = light.direction.normalize(); - light.altered = 1; - light.reflection = 0.0; - lights.push_back(light); - - light.color.r = 0.25; - light.color.g = 0.25; - light.color.b = 0.265; - light.direction.x = 1.0; - light.direction.y = -0.5; - light.direction.z = -1.0; - light.direction = light.direction.normalize(); - light.altered = 0; - light.reflection = 0.0; - lights.push_back(light); - - disableAtmosphere(lights); -} - -void SoftwareRenderer::disableAtmosphere(const std::vector &lights) -{ - scenery->getAtmosphere()->model = AtmosphereDefinition::ATMOSPHERE_MODEL_DISABLED; - - delete atmosphere_renderer; - atmosphere_renderer = new BaseAtmosphereRenderer(this); - atmosphere_renderer->setStaticLights(lights); -} - Color SoftwareRenderer::applyLightingToSurface(const Vector3 &location, const Vector3 &normal, const SurfaceMaterial &material) { - LightStatus status(lighting, location, getCameraLocation(location)); - atmosphere_renderer->getLightingStatus(&status, normal, 0); - return status.apply(normal, material); + return lighting->apply(getCameraLocation(location), location, normal, material); } Color SoftwareRenderer::applyMediumTraversal(Vector3 location, Color color) diff --git a/src/render/software/SoftwareRenderer.h b/src/render/software/SoftwareRenderer.h index c61426c..5ac5a4d 100644 --- a/src/render/software/SoftwareRenderer.h +++ b/src/render/software/SoftwareRenderer.h @@ -45,16 +45,6 @@ public: */ virtual void setQuality(double quality); - /*! - * \brief Disable atmosphere and sky lighting, replacing it by static lights. - * - * This function needs to be called after each prepare(). - * - * WARNING : This method changes the scenery attached to the renderer ! - */ - void disableAtmosphere(); - void disableAtmosphere(const std::vector &lights); - inline Scenery* getScenery() const {return scenery;} inline BaseAtmosphereRenderer* getAtmosphereRenderer() const {return atmosphere_renderer;} diff --git a/src/render/software/software.pro b/src/render/software/software.pro index 0bc330a..9198949 100644 --- a/src/render/software/software.pro +++ b/src/render/software/software.pro @@ -51,7 +51,8 @@ SOURCES += SoftwareRenderer.cpp \ clouds/CloudModelAltoCumulus.cpp \ clouds/CloudModelCirrus.cpp \ clouds/CloudModelCumuloNimbus.cpp \ - RenderProgress.cpp + RenderProgress.cpp \ + LightSource.cpp HEADERS += SoftwareRenderer.h\ software_global.h \ @@ -92,7 +93,8 @@ HEADERS += SoftwareRenderer.h\ clouds/CloudModelAltoCumulus.h \ clouds/CloudModelCirrus.h \ clouds/CloudModelCumuloNimbus.h \ - RenderProgress.h + RenderProgress.h \ + LightSource.h unix:!symbian { maemo5 { diff --git a/src/render/software/software_global.h b/src/render/software/software_global.h index cce6d84..79c82b1 100644 --- a/src/render/software/software_global.h +++ b/src/render/software/software_global.h @@ -43,6 +43,7 @@ namespace software { class LightStatus; class LightFilter; class LightComponent; + class LightSource; class NightSky; diff --git a/src/tests/LightingManager_Test.cpp b/src/tests/LightingManager_Test.cpp new file mode 100644 index 0000000..784c033 --- /dev/null +++ b/src/tests/LightingManager_Test.cpp @@ -0,0 +1,62 @@ +#include "BaseTestCase.h" +#include "LightingManager.h" + +#include "LightSource.h" +#include "LightFilter.h" + +class FakeLightSource: public LightSource +{ + virtual bool getLightsAt(std::vector &, const Vector3 &) const override + { + return false; + } +}; + +TEST(LightingManager, registerSource) +{ + LightingManager manager; + FakeLightSource source; + + EXPECT_EQ(0, manager.getSourcesCount()); + + manager.registerSource(&source); + + EXPECT_EQ(1, manager.getSourcesCount()); + + manager.registerSource(&source); + + EXPECT_EQ(1, manager.getSourcesCount()); + + manager.unregisterSource(&source); + + EXPECT_EQ(0, manager.getSourcesCount()); +} + +class FakeLightFilter: public LightFilter +{ + virtual bool applyLightFilter(LightComponent &, const Vector3 &) override + { + return false; + } +}; + +TEST(LightingManager, registerFilter) +{ + LightingManager manager; + FakeLightFilter filter; + + EXPECT_EQ(0, manager.getFiltersCount()); + + manager.registerFilter(&filter); + + EXPECT_EQ(1, manager.getFiltersCount()); + + manager.registerFilter(&filter); + + EXPECT_EQ(1, manager.getFiltersCount()); + + manager.unregisterFilter(&filter); + + EXPECT_EQ(0, manager.getFiltersCount()); +} + diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 0431165..4c49dea 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -28,7 +28,8 @@ SOURCES += main.cpp \ DiffManager_Test.cpp \ ColorHSL_Test.cpp \ RenderProgress_Test.cpp \ - IntNode_Test.cpp + IntNode_Test.cpp \ + LightingManager_Test.cpp HEADERS += \ BaseTestCase.h