Peoplemon  0.1.0
Peoplemon 3 game source documentation
LightingSystem.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Math.hpp>
4 #include <BLIB/Render/Primitives/Color.hpp>
5 #include <BLIB/Util/Random.hpp>
6 #include <Core/Properties.hpp>
7 #include <cmath>
8 #include <limits>
9 
10 namespace core
11 {
12 namespace map
13 {
14 namespace
15 {
16 constexpr float AdjustSpeed = 30.f;
17 constexpr std::size_t GameBufferExtra = 0;
18 constexpr std::size_t EditorBufferExtra = 64;
19 constexpr float ThunderDuration = 1.3f;
20 } // namespace
21 
23 : minLevel(175)
24 , maxLevel(255)
25 , sunlight(1)
26 , tint(1.f)
27 , lightsActive(false)
28 , sunlightFactor(1.f)
29 , weatherModifier(0)
30 , targetWeatherModifier(0)
31 , weatherResidual(0.f)
32 , thunderTime(-1.f) {}
33 
34 void LightingSystem::addLight(const Light& light) {
35  rawLights.push_back(light);
36  addLightToScene(light);
37 }
38 
39 void LightingSystem::addLightToScene(const Light& light) {
40  if (sceneLighting) {
41  activeLights.emplace_back(sceneLighting->addLight(
42  glm::vec2(static_cast<float>(light.position.x), static_cast<float>(light.position.y)),
43  static_cast<float>(light.radius),
44  glm::vec3(static_cast<float>(light.color.x) / 255.f,
45  static_cast<float>(light.color.y) / 255.f,
46  static_cast<float>(light.color.z) / 255.f)));
47  }
48 }
49 
50 void LightingSystem::updateLight(Handle handle, const Light& light) {
51  rawLights[handle] = light;
52 
53  if (sceneLighting) {
54  bl::rc::lgt::Light2D& l = activeLights[handle];
55  l.setPosition(
56  glm::vec2(static_cast<float>(light.position.x), static_cast<float>(light.position.y)));
57  l.setRadius(static_cast<float>(light.radius));
58  l.setColor(glm::vec3(static_cast<float>(light.color.x) / 255.f,
59  static_cast<float>(light.color.y) / 255.f,
60  static_cast<float>(light.color.z) / 255.f));
61  }
62 }
63 
65  Handle closest = None;
66  unsigned long cdist = 10000000;
67 
68  for (unsigned int i = 0; i < rawLights.size(); ++i) {
69  const unsigned long dist = bl::math::magnitudeSquared(rawLights[i].position - position);
70  const unsigned int r = rawLights[i].radius;
71  if (dist < cdist && dist < r * r) {
72  cdist = dist;
73  closest = i;
74  }
75  }
76 
77  return closest;
78 }
79 
80 const Light& LightingSystem::getLight(Handle h) const { return rawLights[h]; }
81 
83  rawLights.erase(rawLights.begin() + handle);
84 
85  if (sceneLighting) {
86  activeLights[handle].removeFromScene();
87  activeLights.erase(activeLights.begin() + handle);
88  }
89 }
90 
91 bool LightingSystem::lightsAreOn() const { return computeAmbient() > 80; }
92 
93 void LightingSystem::setAmbientLevel(std::uint8_t lowLightLevel, std::uint8_t highLightLevel) {
94  minLevel = std::min(lowLightLevel, highLightLevel);
95  maxLevel = std::max(lowLightLevel, highLightLevel);
96  levelRange = maxLevel - minLevel;
97 }
98 
99 std::uint8_t LightingSystem::getMinLightLevel() const { return minLevel; }
100 
101 std::uint8_t LightingSystem::getMaxLightLevel() const { return maxLevel; }
102 
103 void LightingSystem::adjustForSunlight(bool a) { sunlight = a ? 1 : 0; }
104 
105 bool LightingSystem::adjustsForSunlight() const { return sunlight != 0; }
106 
107 void LightingSystem::activate(bl::rc::lgt::Scene2DLighting& lighting) {
108  sceneLighting = &lighting;
109  levelRange = maxLevel - minLevel;
110 
111  activeLights.reserve(rawLights.size() +
112  (Properties::InEditor() ? EditorBufferExtra : GameBufferExtra));
113  for (const auto& light : rawLights) { addLightToScene(light); }
114  for (auto& handle : activeLights) { handle.setColor(glm::vec3(0.f)); }
115  lightsActive = false;
116 
117  updateAmbientLighting();
118 }
119 
120 void LightingSystem::subscribe() { bl::event::Dispatcher::subscribe(this); }
121 
122 void LightingSystem::unsubscribe() { bl::event::Dispatcher::unsubscribe(this); }
123 
125  rawLights.clear();
126  maxLevel = 255;
127  minLevel = 75;
128  levelRange = maxLevel - minLevel;
129  sunlight = 1;
130  for (auto& light : activeLights) { light.removeFromScene(); }
131  activeLights.clear();
132 }
133 
134 void LightingSystem::update(float dt) {
135  if (weatherModifier != targetWeatherModifier) {
136  weatherResidual += AdjustSpeed * dt;
137  const float p = std::floor(weatherResidual);
138  if (p >= 1.f) {
139  weatherResidual -= p;
140  if (targetWeatherModifier > weatherModifier) {
141  weatherModifier += static_cast<int>(p);
142  if (weatherModifier > targetWeatherModifier) {
143  weatherModifier = targetWeatherModifier;
144  weatherResidual = 0.f;
145  }
146  }
147  else {
148  weatherModifier -= static_cast<int>(p);
149  if (weatherModifier < targetWeatherModifier) {
150  weatherModifier = targetWeatherModifier;
151  weatherResidual = 0.f;
152  }
153  }
154  }
155  }
156 
157  if (lightsAreOn() && !lightsActive) {
158  lightsActive = true;
159  Light* light = &rawLights.front();
160 
161  for (auto& handle : activeLights) {
162  handle.setColor(glm::vec3(static_cast<float>(light->color.x) / 255.f,
163  static_cast<float>(light->color.y) / 255.f,
164  static_cast<float>(light->color.z) / 255.f));
165  light += 1;
166  }
167  }
168  else if (!lightsAreOn() && lightsActive) {
169  lightsActive = false;
170  for (auto& handle : activeLights) { handle.setColor(glm::vec3(0.f)); }
171  }
172 
173  if (thunderTime >= 0.f) {
174  thunderTime += dt;
175  if (thunderTime >= ThunderDuration) { thunderTime = -1.f; }
176  }
177 
178  updateAmbientLighting();
179 }
180 
181 void LightingSystem::updateAmbientLighting() {
182  if (sceneLighting) {
183  const std::uint8_t ambient = computeAmbient();
184  float a = static_cast<float>(255 - ambient) / 255.f;
185  if (thunderTime >= 0.f) {
186  if (thunderTime <= 0.5f) {
187  const float x = thunderTime - 0.2f;
188  const float m = -3.92f * x * x + 1.88f;
189  a *= m;
190  }
191  else {
192  const float x = (thunderTime - 0.5f) - 0.2f;
193  const float m = -2.16f * x * x + 1.78f;
194  a *= m;
195  }
196  }
197 
198  glm::vec3 color(a);
199  color *= tint;
200  sceneLighting->setAmbientLight(color);
201  }
202 }
203 
204 std::uint8_t LightingSystem::computeAmbient() const {
205  const float preambient = 255.f - (static_cast<float>(minLevel) + levelRange * sunlightFactor);
206  return std::min(std::max(0, static_cast<int>(preambient) + weatherModifier), 255);
207 }
208 
210  if (adjustsForSunlight()) {
211  const float x = now.newTime.hour * 60 + now.newTime.minute;
212  const float n = 0.7f;
213  sunlightFactor = 1.f - (0.5 * std::cos(3.1415926 * x / 720) + 0.5) *
214  ((1 - n) * (720 - x) * (720 - x) / 518400 + n);
215  }
216  else { sunlightFactor = 1.f; }
217 }
218 
220  switch (event.type) {
221  case Weather::LightRain:
223  targetWeatherModifier = Properties::LightRainLightModifier();
224  break;
225 
226  case Weather::HardRain:
228  targetWeatherModifier = Properties::HardRainLightModifier();
229  break;
230 
231  case Weather::LightSnow:
233  targetWeatherModifier = Properties::LightSnowLightModifier();
234  break;
235 
236  case Weather::HardSnow:
238  targetWeatherModifier = Properties::HardSnowLightModifier();
239  break;
240 
241  case Weather::ThinFog:
242  targetWeatherModifier = Properties::ThinFogLightModifier();
243  break;
244 
245  case Weather::ThickFog:
246  targetWeatherModifier = Properties::ThickFogLightModifier();
247  break;
248 
249  case Weather::SandStorm:
250  targetWeatherModifier = Properties::SandstormLightModifier();
251  break;
252 
253  case Weather::Sunny:
254  targetWeatherModifier = Properties::SunnyLightModifier();
255  break;
256 
257  default:
258  targetWeatherModifier = 0;
259  break;
260  }
261 }
262 
263 void LightingSystem::observe(const event::WeatherStopped&) { targetWeatherModifier = 0; }
264 
265 void LightingSystem::observe(const event::Thundered&) { thunderTime = 0.f; }
266 
267 void LightingSystem::setColorTint(const glm::vec3& t) { tint = t; }
268 
269 } // namespace map
270 } // namespace core
Core classes and functionality for both the editor and game.
Basic event for when the game time changes.
Definition: TimeChange.hpp:24
const system::Clock::Time & newTime
A reference to the new time.
Definition: TimeChange.hpp:34
Fired when weather starts.
Definition: Weather.hpp:15
const map::Weather::Type type
The type of weather that started.
Definition: Weather.hpp:25
Fired when weather stops.
Definition: Weather.hpp:33
Fired when thunder happens.
Definition: Weather.hpp:51
Represents a renderable light in a Map.
Definition: Light.hpp:16
sf::Vector3i color
Definition: Light.hpp:19
std::uint16_t radius
Definition: Light.hpp:17
sf::Vector2i position
Definition: Light.hpp:18
std::uint16_t Handle
Handle representing a light in the map.
std::uint8_t getMaxLightLevel() const
Returns the maximum ambient light level of this map.
void setColorTint(const glm::vec3 &tint)
Sets a color tint to apply to the ambient lighting.
std::uint8_t getMinLightLevel() const
Returns the minimum ambient light level of this map.
LightingSystem()
Initializes the lighting system with no lights.
const Light & getLight(Handle handle) const
Returns the value of the light with the given handle. Invalid handles return a default value (a light...
void addLight(const Light &light)
Adds a light to the map and to the persistent map file.
void update(float dt)
Updates the lighting system.
void adjustForSunlight(bool adjust)
Set whether or not the light level is adjusted based on time of day. If not adjusting for sunlight th...
void unsubscribe()
Unsubscribes the lighting system from the event dispatcher.
void setAmbientLevel(std::uint8_t lowLightLevel, std::uint8_t highLightLevel)
The ambient light band. 0 is full darkness and 255 is full brightness.
void updateLight(Handle handle, const Light &value)
Updates the light with the given handle to the new information.
bool lightsAreOn() const
Returns whether lights are being shown or not based on how dark it is.
Handle getClosestLight(const sf::Vector2i &position)
Returns a handle to the light closest to the given position.
static constexpr Handle None
Special handle indicating that no light is referenced.
void removeLight(Handle light)
Remove the given light from the system and optionally persist the removal.
void activate(bl::rc::lgt::Scene2DLighting &sceneLighting)
Adds all lights into the scene.
void subscribe()
Subscribes the lighting system to time events for ambient light level.
virtual void observe(const event::TimeChange &timeChange) override
Updates the light level based on the new current time.
bool adjustsForSunlight() const
Returns whether or not this map is adjusted for time of day.
void clear()
Clears all lights from the map, including the persisted light data.
@ HardSnowThunder
Hard snow with thunder.
Definition: Weather.hpp:67
@ Sunny
A very sunny day with pulsating light.
Definition: Weather.hpp:76
@ ThinFog
Thin fog covers the area.
Definition: Weather.hpp:70
@ SandStorm
A sandstorm ravages you.
Definition: Weather.hpp:79
@ HardRain
Hard rain with no thunder.
Definition: Weather.hpp:52
@ HardRainThunder
Hard rain with thunder.
Definition: Weather.hpp:55
@ LightRainThunder
Light rain with thunder.
Definition: Weather.hpp:49
@ LightSnowThunder
Light snow with thunder.
Definition: Weather.hpp:61
@ LightRain
Light rain with no thunder.
Definition: Weather.hpp:46
@ ThickFog
Thick fog obscures everything.
Definition: Weather.hpp:73
@ LightSnow
Light snow with no thunder.
Definition: Weather.hpp:58
@ HardSnow
Hard snow with no thunder.
Definition: Weather.hpp:64
static int LightRainLightModifier()
Definition: Properties.cpp:475
static int SunnyLightModifier()
Definition: Properties.cpp:505
static bool InEditor()
Definition: Properties.cpp:266
static int HardRainLightModifier()
Definition: Properties.cpp:480
static int HardSnowLightModifier()
Definition: Properties.cpp:490
static int SandstormLightModifier()
Definition: Properties.cpp:510
static int ThickFogLightModifier()
Definition: Properties.cpp:500
static int ThinFogLightModifier()
Definition: Properties.cpp:495
static int LightSnowLightModifier()
Definition: Properties.cpp:485
unsigned int minute
Current minute of the hour. In range [0, 59].
Definition: Clock.hpp:40
unsigned int hour
Current hour of the day, in range [0, 23].
Definition: Clock.hpp:37