666 lines
21 KiB
GDScript3
666 lines
21 KiB
GDScript3
|
class_name ScreenEffects extends CanvasLayer
|
||
|
|
||
|
const DEFAULT_TRANSITION: float = 0.25
|
||
|
const DEFAULT_WEATHER_TRANSITION: float = 1.0
|
||
|
const DEFAULT_TIME_OF_DAY_TRANSITION: float = 6.0
|
||
|
const LONGEST_DEFAULT_TRANSITION: float = DEFAULT_TIME_OF_DAY_TRANSITION
|
||
|
const AVERAGE_LIGHTNING_TIMEOUT: float = 10.0
|
||
|
const LIGHTNING_MAX_TRANSITION: float = 1.0
|
||
|
const NORMAL_OVERCAST: float = 0.25
|
||
|
const NORMAL_WIND: float = 0.25
|
||
|
const NORMAL_BRIGHTNESS: float = 0.25
|
||
|
const NORMAL_TWIST: float = 0.0625
|
||
|
const NORMAL_PSYCHEDELIC: float = 0.0625
|
||
|
const SIGNIFICANT_OVERCAST: float = 0.75
|
||
|
const SIGNIFICANT_WIND: float = 0.75
|
||
|
const RAIN_FOG_COLOR := Color(0.15, 0.22, 0.24)
|
||
|
const SNOW_FOG_COLOR := Color(0.55, 0.59, 0.92)
|
||
|
const RAIN_VOLUME_DB: float = -15.0
|
||
|
const THUNDER_VOLUME_DB: float = 0.0
|
||
|
const SNOW_VOLUME_DB: float = -5.0
|
||
|
const NON_SOLID_SHADERS := {
|
||
|
"res://vfx/liquid.gdshader": true,
|
||
|
"res://vfx/underlay.gdshader": true
|
||
|
}
|
||
|
const MAX_FOG_DENSITY: float = 0.0625
|
||
|
const MAX_FOG_SKY_AFFECT: float = 0.98
|
||
|
|
||
|
enum _EffectType {NONE, RAIN, SNOW, TINT, FADE, FLASH}
|
||
|
enum _WeatherType {
|
||
|
NONE,
|
||
|
SNOW_LEVEL_1,
|
||
|
SNOW_LEVEL_2,
|
||
|
RAIN_LEVEL_1,
|
||
|
RAIN_LEVEL_2,
|
||
|
RAIN_LEVEL_3,
|
||
|
RAIN_LEVEL_4,
|
||
|
RAIN_LEVEL_5
|
||
|
}
|
||
|
|
||
|
@onready var _tint_sprite := $'Tint' as Sprite2D
|
||
|
@onready var _fade_sprite := $'Fade' as Sprite2D
|
||
|
@onready var _flash_sprite := $'Flash' as Sprite2D
|
||
|
@onready var _weather_parent := $'Weather' as Node2D
|
||
|
@onready var _rain_level_5_particles := $'Weather/RainLevel5' as GPUParticles2D
|
||
|
@onready var _rain_level_4_particles := $'Weather/RainLevel4' as GPUParticles2D
|
||
|
@onready var _rain_level_3_particles := $'Weather/RainLevel3' as GPUParticles2D
|
||
|
@onready var _rain_level_2_particles := $'Weather/RainLevel2' as GPUParticles2D
|
||
|
@onready var _rain_level_1_particles := $'Weather/RainLevel1' as GPUParticles2D
|
||
|
@onready var _snow_level_2_particles := $'Weather/SnowLevel2' as GPUParticles2D
|
||
|
@onready var _snow_level_1_particles := $'Weather/SnowLevel1' as GPUParticles2D
|
||
|
@onready var _rain_level_5_audio := (
|
||
|
$'Weather/RainLevel5/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _rain_level_4_audio := (
|
||
|
$'Weather/RainLevel4/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _rain_level_3_audio := (
|
||
|
$'Weather/RainLevel3/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _rain_level_2_audio := (
|
||
|
$'Weather/RainLevel2/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _rain_level_1_audio := (
|
||
|
$'Weather/RainLevel1/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _snow_level_2_audio := (
|
||
|
$'Weather/SnowLevel2/AudioStreamPlayer' as AudioStreamPlayer
|
||
|
)
|
||
|
@onready var _thunder_audio := $'Weather/Thunder' as AudioStreamPlayer
|
||
|
@onready var _rain_level_5_material := (
|
||
|
_rain_level_5_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _rain_level_4_material := (
|
||
|
_rain_level_4_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _rain_level_3_material := (
|
||
|
_rain_level_3_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _rain_level_2_material := (
|
||
|
_rain_level_2_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _rain_level_1_material := (
|
||
|
_rain_level_1_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _snow_level_2_material := (
|
||
|
_snow_level_2_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _snow_level_1_material := (
|
||
|
_snow_level_1_particles.process_material as ParticleProcessMaterial
|
||
|
)
|
||
|
@onready var _tint_gradient := (
|
||
|
_tint_sprite.texture as GradientTexture1D
|
||
|
).gradient
|
||
|
@onready var _fade_gradient := (
|
||
|
_fade_sprite.texture as GradientTexture1D
|
||
|
).gradient
|
||
|
@onready var _flash_gradient := (
|
||
|
_flash_sprite.texture as GradientTexture1D
|
||
|
).gradient
|
||
|
@onready var _environment := (
|
||
|
preload("res://vfx/Environment.tres") as Environment
|
||
|
)
|
||
|
@onready var _sky_material := (
|
||
|
_environment.sky.sky_material as ShaderMaterial
|
||
|
)
|
||
|
@onready var _solid_materials := {}
|
||
|
@onready var _light := $'DirectionalLight3D' as DirectionalLight3D
|
||
|
@onready var _tint_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _fade_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _flash_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _time_of_day_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _overcast_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _brightness_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _wind_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _fog_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _light_source_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _twist_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _psychedelic_lock := NonReentrantCoroutineMutex.new()
|
||
|
@onready var _lightning_lock := NonReentrantCoroutineMutex.new()
|
||
|
|
||
|
var _tint_color: Color:
|
||
|
get: return _tint_gradient.colors[0]
|
||
|
set(value): _tint_gradient.colors[0] = value
|
||
|
var _fade_color: Color:
|
||
|
get: return _fade_gradient.colors[0]
|
||
|
set(value): _fade_gradient.colors[0] = value
|
||
|
var _flash_color: Color:
|
||
|
get: return _flash_gradient.colors[0]
|
||
|
set(value): _flash_gradient.colors[0] = value
|
||
|
var _current_weather := _WeatherType.NONE
|
||
|
|
||
|
func _register_node_material_if_solid_object_with_shader(node: Node) -> void:
|
||
|
if node is MeshInstance3D:
|
||
|
for i in node.get_surface_override_material_count():
|
||
|
var material := node.get_active_material(i) as Material
|
||
|
if material is ShaderMaterial and not (
|
||
|
material.shader.resource_path in NON_SOLID_SHADERS
|
||
|
):
|
||
|
_solid_materials[material.get_rid()] = material
|
||
|
|
||
|
func _register_all_relevant_materials_starting_from_node(node: Node) -> void:
|
||
|
for child in node.get_children():
|
||
|
_register_all_relevant_materials_starting_from_node(child)
|
||
|
_register_node_material_if_solid_object_with_shader(node)
|
||
|
|
||
|
func _ready() -> void:
|
||
|
_reposition_children()
|
||
|
get_viewport().size_changed.connect(_reposition_children)
|
||
|
_tint_color = Color.TRANSPARENT
|
||
|
_fade_color = Color.TRANSPARENT
|
||
|
_flash_color = Color.TRANSPARENT
|
||
|
get_tree().node_added.connect(
|
||
|
_register_node_material_if_solid_object_with_shader
|
||
|
)
|
||
|
_register_all_relevant_materials_starting_from_node(get_tree().root)
|
||
|
await brightness(NORMAL_BRIGHTNESS, 0.0)
|
||
|
await stop_weather(0.0)
|
||
|
|
||
|
func _reposition_children() -> void:
|
||
|
var view := get_viewport().get_visible_rect()
|
||
|
_tint_sprite.position = view.position
|
||
|
_fade_sprite.position = view.position
|
||
|
_flash_sprite.position = view.position
|
||
|
_weather_parent.position = view.position + Vector2(view.size.x/2.0, 0.0)
|
||
|
_tint_sprite.scale = view.size
|
||
|
_fade_sprite.scale = view.size
|
||
|
_flash_sprite.scale = view.size
|
||
|
_rain_level_5_material.emission_shape_scale.x = view.size.x
|
||
|
_rain_level_4_material.emission_shape_scale.x = view.size.x
|
||
|
_rain_level_3_material.emission_shape_scale.x = view.size.x
|
||
|
_rain_level_2_material.emission_shape_scale.x = view.size.x
|
||
|
_rain_level_1_material.emission_shape_scale.x = view.size.x
|
||
|
_snow_level_2_material.emission_shape_scale.x = view.size.x
|
||
|
_snow_level_1_material.emission_shape_scale.x = view.size.x
|
||
|
|
||
|
func _weather_get_particles(type: _WeatherType) -> GPUParticles2D:
|
||
|
match type:
|
||
|
_WeatherType.NONE: return null
|
||
|
_WeatherType.SNOW_LEVEL_1: return _snow_level_1_particles
|
||
|
_WeatherType.SNOW_LEVEL_2: return _snow_level_2_particles
|
||
|
_WeatherType.RAIN_LEVEL_1: return _rain_level_1_particles
|
||
|
_WeatherType.RAIN_LEVEL_2: return _rain_level_2_particles
|
||
|
_WeatherType.RAIN_LEVEL_3: return _rain_level_3_particles
|
||
|
_WeatherType.RAIN_LEVEL_4: return _rain_level_4_particles
|
||
|
_WeatherType.RAIN_LEVEL_5: return _rain_level_5_particles
|
||
|
_: return null
|
||
|
|
||
|
func _weather_get_audio(type: _WeatherType) -> AudioStreamPlayer:
|
||
|
match type:
|
||
|
_WeatherType.NONE: return null
|
||
|
_WeatherType.SNOW_LEVEL_1: return null
|
||
|
_WeatherType.SNOW_LEVEL_2: return _snow_level_2_audio
|
||
|
_WeatherType.RAIN_LEVEL_1: return _rain_level_1_audio
|
||
|
_WeatherType.RAIN_LEVEL_2: return _rain_level_2_audio
|
||
|
_WeatherType.RAIN_LEVEL_3: return _rain_level_3_audio
|
||
|
_WeatherType.RAIN_LEVEL_4: return _rain_level_4_audio
|
||
|
_WeatherType.RAIN_LEVEL_5: return _rain_level_5_audio
|
||
|
_: return null
|
||
|
|
||
|
func _weather_has_lightning(type: _WeatherType) -> bool:
|
||
|
return type == _WeatherType.RAIN_LEVEL_5
|
||
|
|
||
|
func _change_weather(type: _WeatherType) -> void:
|
||
|
for other in _WeatherType:
|
||
|
other = _WeatherType.get(other)
|
||
|
if other != type:
|
||
|
var other_particles := _weather_get_particles(other)
|
||
|
if other_particles:
|
||
|
other_particles.emitting = false
|
||
|
var other_audio := _weather_get_audio(other)
|
||
|
if other_audio and other_audio.playing:
|
||
|
FX.audio_fade_out(other_audio)
|
||
|
var particles := _weather_get_particles(type)
|
||
|
if particles:
|
||
|
particles.emitting = true
|
||
|
var audio := _weather_get_audio(type)
|
||
|
if audio:
|
||
|
FX.audio_fade_in(audio, AudioFader.DEFAULT_FADE, (
|
||
|
SNOW_VOLUME_DB if type == _WeatherType.SNOW_LEVEL_2
|
||
|
else RAIN_VOLUME_DB
|
||
|
))
|
||
|
if _weather_has_lightning(type):
|
||
|
FX.audio_fade_in(
|
||
|
_thunder_audio,
|
||
|
AudioFader.DEFAULT_FADE,
|
||
|
THUNDER_VOLUME_DB
|
||
|
)
|
||
|
elif _thunder_audio.playing:
|
||
|
FX.audio_fade_out(_thunder_audio)
|
||
|
_current_weather = type
|
||
|
|
||
|
func _process(delta: float) -> void:
|
||
|
if _weather_has_lightning(_current_weather):
|
||
|
_do_lightning(delta)
|
||
|
|
||
|
func _do_lightning(delta: float) -> void:
|
||
|
var roll: float = randf()
|
||
|
var limit: float = delta/AVERAGE_LIGHTNING_TIMEOUT
|
||
|
if roll < limit:
|
||
|
lightning(1.0 - roll/limit)
|
||
|
|
||
|
func tint(
|
||
|
color: Color = Color.WHITE,
|
||
|
transition: float = DEFAULT_TRANSITION
|
||
|
) -> void:
|
||
|
await _tint_lock.acquire()
|
||
|
var current_color := _tint_color
|
||
|
if color.a == 0.0:
|
||
|
color = Color(current_color)
|
||
|
color.a = 1.0
|
||
|
color = color.lerp(Color.WHITE, 1.0 - color.a)
|
||
|
color.a = 1.0
|
||
|
var rate := (color - current_color)/transition
|
||
|
while transition > 0.0:
|
||
|
var delta: float = await Wait.tick()
|
||
|
_tint_color = current_color
|
||
|
current_color += rate*delta
|
||
|
transition -= delta
|
||
|
_tint_color = color
|
||
|
_tint_lock.relinquish()
|
||
|
|
||
|
func clear_tint(transition: float = DEFAULT_TRANSITION) -> void:
|
||
|
await tint(Color.WHITE, transition)
|
||
|
|
||
|
func fade(
|
||
|
color: Color = Color.TRANSPARENT,
|
||
|
transition: float = DEFAULT_TRANSITION
|
||
|
) -> void:
|
||
|
await _fade_lock.acquire()
|
||
|
var current_color := _fade_color
|
||
|
if color.a == 0.0:
|
||
|
color = Color(current_color)
|
||
|
color.a = 0.0
|
||
|
var rate := (color - current_color)/transition
|
||
|
while transition > 0.0:
|
||
|
var delta: float = await Wait.tick()
|
||
|
_fade_color = current_color
|
||
|
current_color += rate*delta
|
||
|
transition -= delta
|
||
|
_fade_color = color
|
||
|
_fade_lock.relinquish()
|
||
|
|
||
|
func clear_fade(transition: float = DEFAULT_TRANSITION) -> void:
|
||
|
await fade(Color.TRANSPARENT, transition)
|
||
|
|
||
|
func flash(
|
||
|
color: Color = Color.TRANSPARENT,
|
||
|
transition: float = DEFAULT_TRANSITION
|
||
|
) -> void:
|
||
|
await _flash_lock.acquire()
|
||
|
var old_color := _flash_color
|
||
|
if old_color.a == 0.0:
|
||
|
old_color = Color(color)
|
||
|
old_color.a = 0.0
|
||
|
_flash_color = color
|
||
|
var rate := (old_color - _flash_color)/transition
|
||
|
while transition > 0.0:
|
||
|
var delta: float = await Wait.tick()
|
||
|
_flash_color += rate*delta
|
||
|
transition -= delta
|
||
|
_flash_color = old_color
|
||
|
_flash_lock.relinquish()
|
||
|
|
||
|
func rain(
|
||
|
magnitude: int = 3,
|
||
|
transition: float = DEFAULT_TRANSITION,
|
||
|
do_not_adjust_overcast: bool = false,
|
||
|
do_not_adjust_brightness: bool = false,
|
||
|
do_not_adjust_wind: bool = false
|
||
|
) -> void:
|
||
|
var do_overcast := func():
|
||
|
if not do_not_adjust_overcast:
|
||
|
await overcast(
|
||
|
0.5 + float(magnitude)*0.1, transition,
|
||
|
bool(do_not_adjust_brightness)
|
||
|
)
|
||
|
var do_wind := func():
|
||
|
if not do_not_adjust_wind:
|
||
|
await wind(0.5 + float(magnitude)*0.1, transition)
|
||
|
var do_shader := func():
|
||
|
await _animate_solid_shader_universal_param(
|
||
|
&'wet', float(magnitude)/5.0, transition
|
||
|
)
|
||
|
var do_weather := func():
|
||
|
match magnitude:
|
||
|
1: _change_weather(_WeatherType.RAIN_LEVEL_1)
|
||
|
2: _change_weather(_WeatherType.RAIN_LEVEL_2)
|
||
|
3: _change_weather(_WeatherType.RAIN_LEVEL_3)
|
||
|
4: _change_weather(_WeatherType.RAIN_LEVEL_4)
|
||
|
5: _change_weather(_WeatherType.RAIN_LEVEL_5)
|
||
|
_: push_error("Invalid rain magnitude %d" % magnitude)
|
||
|
var do_fog := func():
|
||
|
await _animate_fog(
|
||
|
RAIN_FOG_COLOR,
|
||
|
float(magnitude)*MAX_FOG_DENSITY/5.0,
|
||
|
transition
|
||
|
)
|
||
|
await Promise.new([
|
||
|
do_overcast,
|
||
|
do_wind,
|
||
|
do_shader,
|
||
|
do_weather,
|
||
|
do_fog
|
||
|
]).join()
|
||
|
|
||
|
func snow(
|
||
|
magnitude: int = 1,
|
||
|
transition: float = DEFAULT_TRANSITION,
|
||
|
do_not_adjust_overcast: bool = false,
|
||
|
do_not_adjust_brightness: bool = false,
|
||
|
do_not_adjust_wind: bool = false
|
||
|
) -> void:
|
||
|
var do_overcast := func():
|
||
|
if not do_not_adjust_overcast:
|
||
|
await overcast(
|
||
|
0.25*float(magnitude + 1), transition,
|
||
|
bool(do_not_adjust_brightness)
|
||
|
)
|
||
|
var do_wind := func():
|
||
|
if not do_not_adjust_wind:
|
||
|
await wind(0.5*float(magnitude + 1), transition)
|
||
|
var do_shader := func():
|
||
|
await _animate_solid_shader_universal_param(&'wet', 0.0, transition)
|
||
|
var do_weather := func():
|
||
|
match magnitude:
|
||
|
1: _change_weather(_WeatherType.SNOW_LEVEL_1)
|
||
|
2: _change_weather(_WeatherType.SNOW_LEVEL_2)
|
||
|
_: push_error("Invalid snow magnitude %d" % magnitude)
|
||
|
var do_fog := func():
|
||
|
await _animate_fog(
|
||
|
SNOW_FOG_COLOR,
|
||
|
float(magnitude)*MAX_FOG_DENSITY/3.0,
|
||
|
transition
|
||
|
)
|
||
|
await Promise.new([
|
||
|
do_overcast,
|
||
|
do_wind,
|
||
|
do_shader,
|
||
|
do_weather,
|
||
|
do_fog
|
||
|
]).join()
|
||
|
|
||
|
func stop_weather(
|
||
|
transition: float = DEFAULT_TRANSITION,
|
||
|
do_not_adjust_overcast: bool = false,
|
||
|
do_not_adjust_brightness: bool = false,
|
||
|
do_not_adjust_wind: bool = false
|
||
|
) -> void:
|
||
|
var do_weather := func():
|
||
|
_change_weather(_WeatherType.NONE)
|
||
|
var do_shader := func():
|
||
|
await _animate_solid_shader_universal_param(&'wet', 0.0, transition)
|
||
|
var do_overcast := func():
|
||
|
if not do_not_adjust_overcast:
|
||
|
await overcast(
|
||
|
NORMAL_OVERCAST, transition, bool(do_not_adjust_brightness)
|
||
|
)
|
||
|
var do_wind := func():
|
||
|
if not do_not_adjust_wind:
|
||
|
await wind(NORMAL_WIND, transition)
|
||
|
var do_fog := func():
|
||
|
await _animate_fog(Color.BLACK, 0.0, transition)
|
||
|
await Promise.new([
|
||
|
do_overcast,
|
||
|
do_wind,
|
||
|
do_shader,
|
||
|
do_weather,
|
||
|
do_fog
|
||
|
]).join()
|
||
|
|
||
|
func _animate_shader_param(
|
||
|
material: ShaderMaterial,
|
||
|
param: StringName,
|
||
|
magnitude: float,
|
||
|
transition: float
|
||
|
) -> void:
|
||
|
magnitude = clampf(magnitude, 0.0, 1.0)
|
||
|
var current_v = material.get_shader_parameter(param)
|
||
|
var current: float = 0.0
|
||
|
if current_v and current_v is float:
|
||
|
current = current_v
|
||
|
var rate: float = (magnitude - current)/transition
|
||
|
while (magnitude - current)*signf(rate) > 0.0:
|
||
|
material.set_shader_parameter(param, current)
|
||
|
current += rate*(await Wait.tick())
|
||
|
material.set_shader_parameter(param, magnitude)
|
||
|
|
||
|
func _animate_sky_shader_param(
|
||
|
param: StringName,
|
||
|
magnitude: float,
|
||
|
transition: float
|
||
|
) -> void:
|
||
|
await _animate_shader_param(_sky_material, param, magnitude, transition)
|
||
|
|
||
|
func _animate_solid_shader_universal_param(
|
||
|
param: StringName,
|
||
|
magnitude: float,
|
||
|
transition: float
|
||
|
) -> void:
|
||
|
for rid in _solid_materials:
|
||
|
_animate_shader_param(
|
||
|
_solid_materials[rid], param, magnitude, transition
|
||
|
)
|
||
|
var countdown: float = transition
|
||
|
while countdown > 0.0:
|
||
|
countdown -= await Wait.tick()
|
||
|
|
||
|
func _animate_fog(
|
||
|
color: Color,
|
||
|
magnitude: float,
|
||
|
transition: float
|
||
|
) -> void:
|
||
|
await _fog_lock.acquire()
|
||
|
magnitude = clampf(magnitude, 0.0, 1.0)
|
||
|
var current: float = _environment.fog_density
|
||
|
var current_color := _environment.fog_light_color
|
||
|
var rate: float = (magnitude - current)/transition
|
||
|
var color_rate := (color - current_color)/transition
|
||
|
while (magnitude - current)*signf(rate) > 0.0:
|
||
|
_environment.fog_density = current
|
||
|
_environment.fog_sky_affect = (
|
||
|
current*MAX_FOG_SKY_AFFECT/MAX_FOG_DENSITY
|
||
|
)
|
||
|
_environment.fog_light_color = current_color
|
||
|
var delta: float = await Wait.tick()
|
||
|
current += rate*delta
|
||
|
current_color += color_rate*delta
|
||
|
_environment.fog_density = magnitude
|
||
|
_environment.fog_sky_affect = magnitude*MAX_FOG_SKY_AFFECT/MAX_FOG_DENSITY
|
||
|
_environment.fog_light_color = color
|
||
|
_fog_lock.relinquish()
|
||
|
|
||
|
func wind(
|
||
|
magnitude: float = SIGNIFICANT_WIND,
|
||
|
transition: float = DEFAULT_WEATHER_TRANSITION
|
||
|
) -> void:
|
||
|
await _wind_lock.acquire()
|
||
|
await _animate_shader_param(
|
||
|
_sky_material, &'windy', magnitude, transition
|
||
|
)
|
||
|
_wind_lock.relinquish()
|
||
|
|
||
|
func overcast(
|
||
|
magnitude: float = SIGNIFICANT_OVERCAST,
|
||
|
transition: float = DEFAULT_WEATHER_TRANSITION,
|
||
|
do_not_adjust_brightness: bool = false
|
||
|
) -> void:
|
||
|
await _overcast_lock.acquire()
|
||
|
var do_brightness := func():
|
||
|
if not do_not_adjust_brightness:
|
||
|
await brightness(
|
||
|
lerpf(
|
||
|
NORMAL_BRIGHTNESS, NORMAL_BRIGHTNESS/2.0,
|
||
|
(magnitude - NORMAL_OVERCAST)*4.0/3.0
|
||
|
),
|
||
|
transition
|
||
|
)
|
||
|
var do_shader := func():
|
||
|
await _animate_shader_param(
|
||
|
_sky_material, &'overcast', magnitude, transition
|
||
|
)
|
||
|
await Promise.new([
|
||
|
do_brightness,
|
||
|
do_shader
|
||
|
]).join()
|
||
|
_overcast_lock.relinquish()
|
||
|
|
||
|
func stop_wind(transition: float = DEFAULT_WEATHER_TRANSITION) -> void:
|
||
|
await wind(NORMAL_WIND, transition)
|
||
|
|
||
|
func clear_overcast(
|
||
|
transition: float = DEFAULT_WEATHER_TRANSITION,
|
||
|
do_not_adjust_brightness: bool = false
|
||
|
) -> void:
|
||
|
await overcast(NORMAL_OVERCAST, transition, bool(do_not_adjust_brightness))
|
||
|
|
||
|
func morning(transition: float = DEFAULT_TIME_OF_DAY_TRANSITION) -> void:
|
||
|
await _time_of_day_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'night', 0.5, transition)
|
||
|
_time_of_day_lock.relinquish()
|
||
|
|
||
|
func day(transition: float = DEFAULT_TIME_OF_DAY_TRANSITION) -> void:
|
||
|
await _time_of_day_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'night', 0.0, transition)
|
||
|
_time_of_day_lock.relinquish()
|
||
|
|
||
|
func afternoon(transition: float = DEFAULT_TIME_OF_DAY_TRANSITION) -> void:
|
||
|
await _time_of_day_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'night', 0.25, transition)
|
||
|
_time_of_day_lock.relinquish()
|
||
|
|
||
|
func evening(transition: float = DEFAULT_TIME_OF_DAY_TRANSITION) -> void:
|
||
|
await _time_of_day_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'night', 0.75, transition)
|
||
|
_time_of_day_lock.relinquish()
|
||
|
|
||
|
func night(transition: float = DEFAULT_TIME_OF_DAY_TRANSITION) -> void:
|
||
|
await _time_of_day_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'night', 1.0, transition)
|
||
|
_time_of_day_lock.relinquish()
|
||
|
|
||
|
func light_source(
|
||
|
point_at_infinity: Vector3,
|
||
|
transition: float = DEFAULT_TIME_OF_DAY_TRANSITION
|
||
|
) -> void:
|
||
|
await _light_source_lock.acquire()
|
||
|
var up := Vector3.UP
|
||
|
if up.cross(point_at_infinity).is_zero_approx():
|
||
|
up = Vector3.RIGHT
|
||
|
if up.cross(point_at_infinity).is_zero_approx():
|
||
|
up = Vector3.BACK
|
||
|
var countdown: float = transition
|
||
|
while countdown > 0.0:
|
||
|
_light.basis = _light.basis.slerp(
|
||
|
Basis.looking_at(-point_at_infinity, up),
|
||
|
1.0 - countdown/transition
|
||
|
)
|
||
|
var delta: float = await Wait.tick()
|
||
|
countdown -= delta
|
||
|
_light.look_at(-point_at_infinity, up)
|
||
|
_light_source_lock.relinquish()
|
||
|
|
||
|
func _light_source_brightness(magnitude: float, transition: float) -> void:
|
||
|
magnitude = clampf(magnitude, 0.0, 1.0)
|
||
|
var current: float = _light.light_energy
|
||
|
var rate: float = (magnitude - current)/transition
|
||
|
while (magnitude - current)*signf(rate) > 0.0:
|
||
|
_light.light_energy = current
|
||
|
current += rate*(await Wait.tick())
|
||
|
_light.light_energy = magnitude
|
||
|
|
||
|
func brightness(
|
||
|
magnitude: float = NORMAL_BRIGHTNESS,
|
||
|
transition: float = DEFAULT_TIME_OF_DAY_TRANSITION
|
||
|
) -> void:
|
||
|
await _brightness_lock.acquire()
|
||
|
var do_shader := func():
|
||
|
await _animate_sky_shader_param(&'bright', magnitude, transition)
|
||
|
var do_light_source := func():
|
||
|
await _light_source_brightness(
|
||
|
lerpf(NORMAL_BRIGHTNESS/1.5, 4.0*NORMAL_BRIGHTNESS/3.0, magnitude),
|
||
|
transition
|
||
|
)
|
||
|
await Promise.new([
|
||
|
do_shader,
|
||
|
do_light_source
|
||
|
]).join()
|
||
|
_brightness_lock.relinquish()
|
||
|
|
||
|
func twist(
|
||
|
magnitude: float = NORMAL_TWIST,
|
||
|
transition: float = DEFAULT_WEATHER_TRANSITION
|
||
|
) -> void:
|
||
|
await _twist_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'twist', magnitude, transition)
|
||
|
_twist_lock.relinquish()
|
||
|
|
||
|
func psychedelic(
|
||
|
magnitude: float = NORMAL_PSYCHEDELIC,
|
||
|
transition: float = DEFAULT_TIME_OF_DAY_TRANSITION
|
||
|
) -> void:
|
||
|
await _psychedelic_lock.acquire()
|
||
|
await _animate_sky_shader_param(&'twist', magnitude, transition)
|
||
|
_psychedelic_lock.relinquish()
|
||
|
|
||
|
func lightning(intensity: float = 1.0) -> void:
|
||
|
await _lightning_lock.acquire()
|
||
|
var transition: float = intensity*LIGHTNING_MAX_TRANSITION
|
||
|
var do_shader := func():
|
||
|
var old_night: float = (
|
||
|
_sky_material.get_shader_parameter(&'night')
|
||
|
)
|
||
|
var scaled_intensity: float = lerpf(0.875, 1.0, intensity)
|
||
|
_sky_material.set_shader_parameter(
|
||
|
&'night',
|
||
|
lerpf(old_night, 0.0, scaled_intensity)
|
||
|
)
|
||
|
await _animate_sky_shader_param(&'night', old_night, transition)
|
||
|
var do_fog := func():
|
||
|
var old_fog: float = _environment.fog_density
|
||
|
_environment.fog_density = 0.0
|
||
|
await _animate_fog(
|
||
|
_environment.fog_light_color,
|
||
|
old_fog,
|
||
|
transition
|
||
|
)
|
||
|
var do_brightness := func():
|
||
|
var old_brightness: float = (
|
||
|
_sky_material.get_shader_parameter(&'bright')
|
||
|
)
|
||
|
await brightness(
|
||
|
lerpf(old_brightness, 1.0, lerpf(0.875, 1.0, intensity)),
|
||
|
0.0
|
||
|
)
|
||
|
await brightness(old_brightness, transition)
|
||
|
await Promise.new([
|
||
|
do_shader,
|
||
|
do_fog,
|
||
|
do_brightness
|
||
|
]).join()
|
||
|
_lightning_lock.relinquish()
|
||
|
|
||
|
func hide_weather_particles() -> void:
|
||
|
_rain_level_1_particles.visible = false
|
||
|
_rain_level_2_particles.visible = false
|
||
|
_rain_level_3_particles.visible = false
|
||
|
_rain_level_4_particles.visible = false
|
||
|
_rain_level_5_particles.visible = false
|
||
|
_snow_level_1_particles.visible = false
|
||
|
_snow_level_2_particles.visible = false
|
||
|
|
||
|
func unhide_weather_particles() -> void:
|
||
|
_rain_level_1_particles.visible = true
|
||
|
_rain_level_2_particles.visible = true
|
||
|
_rain_level_3_particles.visible = true
|
||
|
_rain_level_4_particles.visible = true
|
||
|
_rain_level_5_particles.visible = true
|
||
|
_snow_level_1_particles.visible = true
|
||
|
_snow_level_2_particles.visible = true
|
||
|
|
||
|
func current_tint() -> Color:
|
||
|
return _tint_color
|
||
|
|
||
|
func current_fade() -> Color:
|
||
|
return _fade_color
|