mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Clean up audio code, fix egui bug
This commit is contained in:
parent
72a0f56788
commit
ac82689f83
BIN
assets/voxygen/audio/ambience/leaves.ogg
(Stored with Git LFS)
BIN
assets/voxygen/audio/ambience/leaves.ogg
(Stored with Git LFS)
Binary file not shown.
@ -17,7 +17,7 @@
|
||||
),
|
||||
(
|
||||
path:"voxygen.audio.ambience.leaves",
|
||||
length: 27.0,
|
||||
length: 26.0,
|
||||
tag: Leaves,
|
||||
),
|
||||
]
|
||||
|
@ -108,44 +108,47 @@ void main() {
|
||||
vec2 view_pos = vec2(atan2(dir_2d.x, dir_2d.y), z);
|
||||
|
||||
vec3 cam_wpos = cam_pos.xyz + focus_off.xyz;
|
||||
float rain_dist = 50.0;
|
||||
for (int i = 0; i < 4; i ++) {
|
||||
float old_rain_dist = rain_dist;
|
||||
rain_dist *= 0.3;
|
||||
float rain = rain_density_at(cam_wpos.xy);
|
||||
if (rain > 0.0) {
|
||||
float rain_dist = 50.0;
|
||||
for (int i = 0; i < 4; i ++) {
|
||||
float old_rain_dist = rain_dist;
|
||||
rain_dist *= 0.3;
|
||||
|
||||
vec2 drop_density = vec2(30, 1);
|
||||
vec2 drop_density = vec2(30, 1);
|
||||
|
||||
vec2 rain_pos = (view_pos * rain_dist);
|
||||
rain_pos.y += integrated_rain_vel;
|
||||
vec2 rain_pos = (view_pos * rain_dist);
|
||||
rain_pos.y += integrated_rain_vel;
|
||||
|
||||
vec2 cell = floor(rain_pos * drop_density) / drop_density;
|
||||
vec2 cell = floor(rain_pos * drop_density) / drop_density;
|
||||
|
||||
float drop_depth = mix(
|
||||
old_rain_dist,
|
||||
rain_dist,
|
||||
fract(hash(fract(vec4(cell, rain_dist, 0) * 0.1)))
|
||||
);
|
||||
vec3 rpos = vec3(vec2(dir_2d), view_pos.y) * drop_depth;
|
||||
float dist_to_rain = length(rpos);
|
||||
if (dist < dist_to_rain || cam_wpos.z + rpos.z > CLOUD_AVG_ALT) {
|
||||
continue;
|
||||
float drop_depth = mix(
|
||||
old_rain_dist,
|
||||
rain_dist,
|
||||
fract(hash(fract(vec4(cell, rain_dist, 0) * 0.1)))
|
||||
);
|
||||
vec3 rpos = vec3(vec2(dir_2d), view_pos.y) * drop_depth;
|
||||
float dist_to_rain = length(rpos);
|
||||
if (dist < dist_to_rain || cam_wpos.z + rpos.z > CLOUD_AVG_ALT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dot(rpos * vec3(1, 1, 0.5), rpos) < 1.0) {
|
||||
break;
|
||||
}
|
||||
float rain_density = rain * rain_occlusion_at(cam_pos.xyz + rpos.xyz) * 10.0;
|
||||
|
||||
if (rain_density < 0.001 || fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
|
||||
continue;
|
||||
}
|
||||
vec2 near_drop = cell + (vec2(0.5) + (vec2(hash(vec4(cell, 0, 0)), 0.5) - 0.5) * vec2(2, 0)) / drop_density;
|
||||
|
||||
vec2 drop_size = vec2(0.0008, 0.03);
|
||||
float avg_alpha = (drop_size.x * drop_size.y) * 10 / 1;
|
||||
float alpha = sign(max(1 - length((rain_pos - near_drop) / drop_size * 0.1), 0));
|
||||
float light = sqrt(dot(old_color, vec3(1))) + (get_sun_brightness() + get_moon_brightness()) * 0.01;
|
||||
color.rgb = mix(color.rgb, vec3(0.3, 0.4, 0.5) * light, mix(avg_alpha, alpha, min(1000 / dist_to_rain, 1)) * 0.25);
|
||||
}
|
||||
|
||||
if (dot(rpos * vec3(1, 1, 0.5), rpos) < 1.0) {
|
||||
break;
|
||||
}
|
||||
float rain_density = rain_density_at(cam_wpos.xy + rpos.xy) * rain_occlusion_at(cam_pos.xyz + rpos.xyz) * 10.0;
|
||||
|
||||
if (rain_density < 0.001 || fract(hash(fract(vec4(cell, rain_dist, 0) * 0.01))) > rain_density) {
|
||||
continue;
|
||||
}
|
||||
vec2 near_drop = cell + (vec2(0.5) + (vec2(hash(vec4(cell, 0, 0)), 0.5) - 0.5) * vec2(2, 0)) / drop_density;
|
||||
|
||||
vec2 drop_size = vec2(0.0008, 0.03);
|
||||
float avg_alpha = (drop_size.x * drop_size.y) * 10 / 1;
|
||||
float alpha = sign(max(1 - length((rain_pos - near_drop) / drop_size * 0.1), 0));
|
||||
float light = sqrt(dot(old_color, vec3(1))) + (get_sun_brightness() + get_moon_brightness()) * 0.01;
|
||||
color.rgb = mix(color.rgb, vec3(0.3, 0.4, 0.5) * light, mix(avg_alpha, alpha, min(1000 / dist_to_rain, 1)) * 0.25);
|
||||
}
|
||||
|
||||
tgt_color = vec4(color.rgb, 1);
|
||||
|
@ -125,7 +125,7 @@ vec2 textureBicubic16(texture2D tex, sampler sampl, vec2 texCoords) {
|
||||
|
||||
// Gets the altitude at a position relative to focus_off.
|
||||
float alt_at(vec2 pos) {
|
||||
vec4 alt_sample = textureLod/*textureBicubic16*/(sampler2D(t_alt, s_alt), wpos_to_uv(t_alt, s_alt, focus_off.xy + pos), 0);
|
||||
vec4 alt_sample = textureLod/*textureBicubic16*/(sampler2D(t_alt, s_alt), wpos_to_uv(focus_off.xy + pos), 0);
|
||||
return (/*round*/((alt_sample.r / 256.0 + alt_sample.g) * (/*1300.0*//*1278.7266845703125*/view_distance.w)) + /*140.0*/view_distance.z - focus_off.z);
|
||||
//+ (texture(t_noise, pos * 0.002).x - 0.5) * 64.0;
|
||||
|
||||
|
@ -10,8 +10,8 @@ uniform samplerShadow s_directed_occlusion_maps;
|
||||
|
||||
layout (std140, set = 0, binding = 14)
|
||||
uniform u_rain_occlusion {
|
||||
mat4 occlusionMatrices;
|
||||
mat4 occlusion_texture_mat;
|
||||
mat4 rain_occlusion_matrices;
|
||||
mat4 rain_occlusion_texture_mat;
|
||||
mat4 rel_rain_dir_mat;
|
||||
float integrated_rain_vel;
|
||||
vec3 occlusion_dummy; // Fix alignment.
|
||||
@ -21,7 +21,7 @@ float rain_occlusion_at(in vec3 fragPos)
|
||||
{
|
||||
float bias = -0.2;
|
||||
|
||||
vec4 rain_pos = occlusion_texture_mat * vec4(fragPos, 1.0) - vec4(0, 0, bias, 0);
|
||||
vec4 rain_pos = rain_occlusion_texture_mat * vec4(fragPos, 1.0) - vec4(0, 0, bias, 0);
|
||||
|
||||
float visibility = textureProj(sampler2DShadow(t_directed_occlusion_maps, s_directed_occlusion_maps), rain_pos);
|
||||
|
||||
|
@ -102,9 +102,9 @@ layout(set = 0, binding = 5) uniform texture2D t_alt;
|
||||
layout(set = 0, binding = 6) uniform sampler s_alt;
|
||||
|
||||
// Transforms coordinate in the range 0..WORLD_SIZE to 0..1
|
||||
vec2 wpos_to_uv(texture2D tex, sampler s, vec2 wpos) {
|
||||
vec2 wpos_to_uv(vec2 wpos) {
|
||||
// Want: (pixel + 0.5) / W
|
||||
vec2 texSize = textureSize(sampler2D(tex, s), 0);
|
||||
vec2 texSize = textureSize(sampler2D(t_alt, s_alt), 0);
|
||||
vec2 uv_pos = (wpos + 16) / (32.0 * texSize);
|
||||
return vec2(uv_pos.x, /*1.0 - */uv_pos.y);
|
||||
}
|
||||
@ -114,7 +114,7 @@ layout(set = 0, binding = 12) uniform texture2D t_weather;
|
||||
layout(set = 0, binding = 13) uniform sampler s_weather;
|
||||
|
||||
vec4 sample_weather(vec2 wpos) {
|
||||
return textureLod(sampler2D(t_weather, s_weather), wpos_to_uv(t_alt, s_alt, wpos), 0);
|
||||
return textureLod(sampler2D(t_weather, s_weather), wpos_to_uv(wpos), 0);
|
||||
}
|
||||
|
||||
float cloud_tendency_at(vec2 wpos) {
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
layout (std140, set = 0, binding = 14)
|
||||
uniform u_rain_occlusion {
|
||||
mat4 rainOcclusionMatrices;
|
||||
mat4 texture_mat;
|
||||
mat4 rain_occlusion_matrices;
|
||||
mat4 rain_occlusion_texture_mat;
|
||||
mat4 rel_rain_dir_mat;
|
||||
float integrated_rain_vel;
|
||||
vec3 occlusion_dummy; // Fix alignment.
|
||||
@ -60,5 +60,5 @@ void main() {
|
||||
vec3 f_chunk_pos = vec3(v_pos_norm & 0x3Fu, (v_pos_norm >> 6) & 0x3Fu, float((v_pos_norm >> 12) & 0xFFFFu) - EXTRA_NEG_Z);
|
||||
vec3 f_pos = f_chunk_pos + (model_offs - focus_off.xyz);
|
||||
|
||||
gl_Position = rainOcclusionMatrices * vec4(f_pos, 1.0);
|
||||
gl_Position = rain_occlusion_matrices * vec4(f_pos, 1.0);
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ shaderc-from-source = ["shaderc/build-from-source"]
|
||||
|
||||
# We don't ship egui with published release builds so a separate feature is required that excludes it.
|
||||
default-publish = ["singleplayer", "native-dialog", "plugins", "simd"]
|
||||
default = ["default-publish", "egui-ui", "hot-reloading", "shaderc-from-source"]
|
||||
# Temp for bug on current wgpu version that has access violation in vulkan when constructing egui pipeline
|
||||
default-no-egui = ["default-publish", "hot-reloading", "shaderc-from-source"]
|
||||
default = ["default-no-egui", "egui-ui"]
|
||||
|
||||
[dependencies]
|
||||
client = {package = "veloren-client", path = "../client"}
|
||||
|
@ -1,9 +1,6 @@
|
||||
//! Handles ambient non-positional sounds
|
||||
use crate::{
|
||||
audio::{
|
||||
channel::{AmbientChannel, AmbientChannelTag},
|
||||
AudioFrontend,
|
||||
},
|
||||
audio::{channel::AmbientChannelTag, AudioFrontend},
|
||||
scene::Camera,
|
||||
};
|
||||
use client::Client;
|
||||
@ -44,97 +41,65 @@ impl AmbientMgr {
|
||||
client: &Client,
|
||||
camera: &Camera,
|
||||
) {
|
||||
// Checks if the ambience volume is set to zero or audio is disabled
|
||||
// This prevents us from running all the following code unnecessarily
|
||||
if !audio.ambience_enabled() {
|
||||
return;
|
||||
}
|
||||
let ambience_volume = audio.get_ambience_volume();
|
||||
let ambience = self.ambience.read();
|
||||
// Iterate through each tag
|
||||
for tag in AmbientChannelTag::iter() {
|
||||
// If the conditions warrant creating a channel of that tag
|
||||
if match tag {
|
||||
AmbientChannelTag::Wind => {
|
||||
AmbientChannelTag::get_tag_volume(tag, client, camera) > 0.0
|
||||
},
|
||||
AmbientChannelTag::Rain => {
|
||||
AmbientChannelTag::get_tag_volume(tag, client, camera) > 0.1
|
||||
},
|
||||
AmbientChannelTag::Thunder => {
|
||||
AmbientChannelTag::get_tag_volume(tag, client, camera) > 0.0
|
||||
},
|
||||
AmbientChannelTag::Leaves => {
|
||||
AmbientChannelTag::get_tag_volume(tag, client, camera) > 0.1
|
||||
},
|
||||
} && audio.get_ambient_channel(tag).is_none()
|
||||
if AmbientChannelTag::get_tag_volume(tag, client, camera)
|
||||
> match tag {
|
||||
AmbientChannelTag::Wind => 0.0,
|
||||
AmbientChannelTag::Rain => 0.1,
|
||||
AmbientChannelTag::Thunder => 0.0,
|
||||
AmbientChannelTag::Leaves => 0.1,
|
||||
}
|
||||
&& audio.get_ambient_channel(tag).is_none()
|
||||
{
|
||||
// Iterate through the supposed number of channels - one for each tag
|
||||
for index in 0..AmbientChannelTag::iter().len() {
|
||||
// If index would exceed current number of channels, create a new one with
|
||||
// current tag
|
||||
if index >= audio.ambient_channels.len() {
|
||||
audio.new_ambient_channel(tag);
|
||||
break;
|
||||
audio.new_ambient_channel(tag);
|
||||
}
|
||||
// If a channel exists run volume code
|
||||
if let Some(channel_index) = audio.get_ambient_channel_index(tag) {
|
||||
let channel = &mut audio.ambient_channels[channel_index];
|
||||
|
||||
// Maintain: get the correct multiplier of whatever the tag of the current
|
||||
// channel is
|
||||
let target_volume = get_target_volume(tag, state, client, camera);
|
||||
// Get multiplier of the current channel
|
||||
let initial_volume = channel.multiplier;
|
||||
|
||||
// Lerp multiplier of current channel
|
||||
// TODO: Make this not framerate dependent
|
||||
channel.multiplier = Lerp::lerp(initial_volume, target_volume, 0.02);
|
||||
|
||||
// Update with sfx volume
|
||||
channel.set_volume(ambience_volume);
|
||||
|
||||
// Set the duration of the loop to whatever the current value is (0.0 by
|
||||
// default)
|
||||
|
||||
// If the sound should loop at this point:
|
||||
if channel.began_playing.elapsed().as_secs_f32() > channel.next_track_change {
|
||||
let track = ambience.tracks.iter().find(|track| track.tag == tag);
|
||||
// Set the channel's start point at this instant
|
||||
channel.began_playing = Instant::now();
|
||||
if let Some(track) = track {
|
||||
// Set loop duration to the one specified in the ron
|
||||
channel.next_track_change = track.length;
|
||||
// Play the file of the current tag at the current multiplier;
|
||||
let current_multiplier = channel.multiplier;
|
||||
audio.play_ambient(tag, &track.path, current_multiplier);
|
||||
}
|
||||
}
|
||||
// If the conditions don't warrant the creation of a
|
||||
// channel with that tag, but a channel with
|
||||
// that tag remains nonetheless, run the volume code
|
||||
} else if audio.get_ambient_channel(tag).is_some() {
|
||||
for index in 0..AmbientChannelTag::iter().len() {
|
||||
// Update with sfx volume
|
||||
audio.ambient_channels[index].set_volume(ambience_volume);
|
||||
// If current channel's tag is not the current tag, move on to next channel
|
||||
if audio.ambient_channels[index].get_tag() == tag {
|
||||
// Maintain: get the correct multiplier of whatever the tag of the current
|
||||
// channel is
|
||||
let target_volume = AmbientChannel::maintain(tag, state, client, camera);
|
||||
// Get multiplier of the current channel
|
||||
let initial_volume = audio.ambient_channels[index].get_multiplier();
|
||||
};
|
||||
|
||||
// Lerp multiplier of current channel
|
||||
audio.ambient_channels[index].set_multiplier(Lerp::lerp(
|
||||
initial_volume,
|
||||
target_volume,
|
||||
0.02,
|
||||
));
|
||||
|
||||
// Set the duration of the loop to whatever the current value is (0.0 by
|
||||
// default)
|
||||
let next_track_change =
|
||||
audio.ambient_channels[index].get_next_track_change();
|
||||
|
||||
// If the sound should loop at this point:
|
||||
if audio.ambient_channels[index]
|
||||
.get_began_playing()
|
||||
.elapsed()
|
||||
.as_secs_f32()
|
||||
> next_track_change
|
||||
{
|
||||
let ambience = self.ambience.read();
|
||||
let track = ambience.tracks.iter().find(|track| track.tag == tag);
|
||||
// Set the channel's start point at this instant
|
||||
audio.ambient_channels[index].set_began_playing(Instant::now());
|
||||
if let Some(track) = track {
|
||||
// Set loop duration to the one specified in the ron
|
||||
audio.ambient_channels[index].set_next_track_change(track.length);
|
||||
// Play the file of the current tag at the current multiplier
|
||||
let current_multiplier =
|
||||
audio.ambient_channels[index].get_multiplier();
|
||||
audio.play_ambient(tag, &track.path, current_multiplier);
|
||||
}
|
||||
};
|
||||
|
||||
// Remove channel if not playing
|
||||
if audio.ambient_channels[index].get_multiplier() == 0.0 {
|
||||
audio.ambient_channels[index].stop();
|
||||
audio.ambient_channels.remove(index);
|
||||
};
|
||||
// Move on to next tag
|
||||
break;
|
||||
} else {
|
||||
// Channel tag and current tag don't match, move on to next channel
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No need to run code at all, move on to the next tag
|
||||
continue;
|
||||
// Remove channel if not playing
|
||||
if audio.ambient_channels[channel_index].multiplier <= 0.001 {
|
||||
audio.ambient_channels.remove(channel_index);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,10 +160,12 @@ impl AmbientChannelTag {
|
||||
rain_intensity.min(0.9)
|
||||
},
|
||||
AmbientChannelTag::Thunder => {
|
||||
if client.weather_at_player().rain * 500.0 < 0.7 {
|
||||
let rain_intensity = client.weather_at_player().rain * 500.0;
|
||||
|
||||
if rain_intensity < 0.7 {
|
||||
0.0
|
||||
} else {
|
||||
client.weather_at_player().rain * 500.0
|
||||
rain_intensity
|
||||
}
|
||||
},
|
||||
AmbientChannelTag::Leaves => {
|
||||
@ -229,51 +196,38 @@ impl AmbientChannelTag {
|
||||
}
|
||||
}
|
||||
|
||||
impl AmbientChannel {
|
||||
pub fn maintain(
|
||||
tag: AmbientChannelTag,
|
||||
state: &State,
|
||||
client: &Client,
|
||||
camera: &Camera,
|
||||
) -> f32 {
|
||||
let focus_off = camera.get_focus_pos().map(f32::trunc);
|
||||
let cam_pos = camera.dependents().cam_pos + focus_off;
|
||||
/// Checks various factors to determine the target volume to lerp to
|
||||
fn get_target_volume(
|
||||
tag: AmbientChannelTag,
|
||||
state: &State,
|
||||
client: &Client,
|
||||
camera: &Camera,
|
||||
) -> f32 {
|
||||
let focus_off = camera.get_focus_pos().map(f32::trunc);
|
||||
let cam_pos = camera.dependents().cam_pos + focus_off;
|
||||
|
||||
let mut target_volume: f32 = AmbientChannelTag::get_tag_volume(tag, client, camera);
|
||||
let mut volume_multiplier: f32 = AmbientChannelTag::get_tag_volume(tag, client, camera);
|
||||
|
||||
target_volume = AmbientChannel::check_camera(state, client, cam_pos, target_volume);
|
||||
|
||||
target_volume
|
||||
let terrain_alt = if let Some(chunk) = client.current_chunk() {
|
||||
chunk.meta().alt()
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// Checks if the camera is underwater to diminish ambient sounds
|
||||
if state
|
||||
.terrain()
|
||||
.get((cam_pos).map(|e| e.floor() as i32))
|
||||
.map(|b| b.is_liquid())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
volume_multiplier *= 0.1;
|
||||
}
|
||||
// Is the camera roughly under the terrain?
|
||||
if cam_pos.z < terrain_alt - 20.0 {
|
||||
volume_multiplier = 0.0;
|
||||
}
|
||||
|
||||
fn check_camera(
|
||||
state: &State,
|
||||
client: &Client,
|
||||
cam_pos: Vec3<f32>,
|
||||
initial_volume: f32,
|
||||
) -> f32 {
|
||||
let mut volume_multiplier = initial_volume;
|
||||
let terrain_alt = if let Some(chunk) = client.current_chunk() {
|
||||
chunk.meta().alt()
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
// Checks if the camera is underwater to diminish ambient sounds
|
||||
if state
|
||||
.terrain()
|
||||
.get((cam_pos).map(|e| e.floor() as i32))
|
||||
.map(|b| b.is_liquid())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
volume_multiplier *= 0.1;
|
||||
}
|
||||
// Is the camera roughly under the terrain?
|
||||
if cam_pos.z < terrain_alt - 20.0 {
|
||||
volume_multiplier = 0.0;
|
||||
}
|
||||
|
||||
volume_multiplier.clamped(0.0, 1.0)
|
||||
}
|
||||
volume_multiplier.clamped(0.0, 1.0)
|
||||
}
|
||||
|
||||
pub fn load_ambience_items() -> AssetHandle<AmbientCollection> {
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! [`AudioSettings`](../../settings/struct.AudioSettings.html)
|
||||
//!
|
||||
//! When the AudioFrontend's
|
||||
//! [`play_sfx`](../struct.AudioFrontend.html#method.play_sfx)
|
||||
//! [`emit_sfx`](../struct.AudioFrontend.html#method.emit_sfx)
|
||||
//! methods is called, it attempts to retrieve an SfxChannel for playback. If
|
||||
//! the channel capacity has been reached and all channels are occupied, a
|
||||
//! warning is logged, and no sound is played.
|
||||
@ -171,10 +171,10 @@ pub enum AmbientChannelTag {
|
||||
/// which are always heard at the camera's position.
|
||||
pub struct AmbientChannel {
|
||||
tag: AmbientChannelTag,
|
||||
multiplier: f32,
|
||||
pub multiplier: f32,
|
||||
sink: Sink,
|
||||
began_playing: Instant,
|
||||
next_track_change: f32,
|
||||
pub began_playing: Instant,
|
||||
pub next_track_change: f32,
|
||||
}
|
||||
|
||||
impl AmbientChannel {
|
||||
@ -215,27 +215,11 @@ impl AmbientChannel {
|
||||
|
||||
pub fn set_volume(&mut self, volume: f32) { self.sink.set_volume(volume * self.multiplier); }
|
||||
|
||||
pub fn set_multiplier(&mut self, multiplier: f32) { self.multiplier = multiplier; }
|
||||
|
||||
pub fn get_volume(&mut self) -> f32 { self.sink.volume() }
|
||||
|
||||
pub fn get_multiplier(&mut self) -> f32 { self.multiplier }
|
||||
// pub fn get_volume(&mut self) -> f32 { self.sink.volume() }
|
||||
|
||||
pub fn get_tag(&self) -> AmbientChannelTag { self.tag }
|
||||
|
||||
pub fn set_tag(&mut self, tag: AmbientChannelTag) { self.tag = tag }
|
||||
|
||||
pub fn get_began_playing(&self) -> Instant { self.began_playing }
|
||||
|
||||
pub fn get_next_track_change(&self) -> f32 { self.next_track_change }
|
||||
|
||||
pub fn set_began_playing(&mut self, began_playing: Instant) {
|
||||
self.began_playing = began_playing
|
||||
}
|
||||
|
||||
pub fn set_next_track_change(&mut self, next_track_change: f32) {
|
||||
self.next_track_change = next_track_change
|
||||
}
|
||||
// pub fn set_tag(&mut self, tag: AmbientChannelTag) { self.tag = tag }
|
||||
}
|
||||
|
||||
/// An SfxChannel uses a positional audio sink, and is designed for short-lived
|
||||
|
@ -81,14 +81,11 @@ impl AudioFrontend {
|
||||
};
|
||||
|
||||
let mut sfx_channels = Vec::with_capacity(num_sfx_channels);
|
||||
if let Some(audio_stream) = &audio_stream {
|
||||
sfx_channels.resize_with(num_sfx_channels, || SfxChannel::new(audio_stream));
|
||||
};
|
||||
|
||||
let mut ui_channels = Vec::with_capacity(num_ui_channels);
|
||||
if let Some(audio_stream) = &audio_stream {
|
||||
ui_channels.resize_with(num_ui_channels, || UiChannel::new(audio_stream))
|
||||
}
|
||||
ui_channels.resize_with(num_ui_channels, || UiChannel::new(audio_stream));
|
||||
sfx_channels.resize_with(num_sfx_channels, || SfxChannel::new(audio_stream));
|
||||
};
|
||||
|
||||
Self {
|
||||
// The following is for the disabled device switcher
|
||||
@ -219,39 +216,6 @@ impl AudioFrontend {
|
||||
self.music_channels.last_mut()
|
||||
}
|
||||
|
||||
/// Function to play sfx from external places. Useful for UI and
|
||||
/// inventory events
|
||||
pub fn emit_sfx_item(
|
||||
&mut self,
|
||||
trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
|
||||
vol: Option<f32>,
|
||||
) {
|
||||
if let Some((event, item)) = trigger_item {
|
||||
let sfx_file = match item.files.len() {
|
||||
0 => {
|
||||
debug!("Sfx event {:?} is missing audio file.", event);
|
||||
"voxygen.audio.sfx.placeholder"
|
||||
},
|
||||
1 => item
|
||||
.files
|
||||
.last()
|
||||
.expect("Failed to determine sound file for this trigger item."),
|
||||
_ => {
|
||||
// If more than one file is listed, choose one at random
|
||||
let rand_step = rand::random::<usize>() % item.files.len();
|
||||
&item.files[rand_step]
|
||||
},
|
||||
};
|
||||
|
||||
match self.play_ui_sfx(sfx_file, vol) {
|
||||
Ok(_) => {},
|
||||
Err(e) => warn!("Failed to play sfx '{:?}'. {}", sfx_file, e),
|
||||
}
|
||||
} else {
|
||||
debug!("Missing sfx trigger config for external sfx event.",);
|
||||
}
|
||||
}
|
||||
|
||||
/// Play an sfx file given the position, SfxEvent, and whether it is
|
||||
/// underwater or not
|
||||
pub fn emit_sfx(
|
||||
@ -262,6 +226,9 @@ impl AudioFrontend {
|
||||
underwater: bool,
|
||||
) {
|
||||
if let Some((event, item)) = trigger_item {
|
||||
// Find sound based on given trigger_item
|
||||
// Randomizes if multiple sounds are found
|
||||
// Errors if no sounds are found
|
||||
let sfx_file = match item.files.len() {
|
||||
0 => {
|
||||
debug!("Sfx event {:?} is missing audio file.", event);
|
||||
@ -277,10 +244,20 @@ impl AudioFrontend {
|
||||
&item.files[rand_step]
|
||||
},
|
||||
};
|
||||
// Play sound in empty channel at given position
|
||||
if self.audio_stream.is_some() {
|
||||
let sound = load_ogg(sfx_file).amplify(volume.unwrap_or(1.0));
|
||||
|
||||
match self.play_sfx(sfx_file, position, volume, underwater) {
|
||||
Ok(_) => {},
|
||||
Err(e) => warn!("Failed to play sfx '{:?}'. {}", sfx_file, e),
|
||||
let listener = self.listener.clone();
|
||||
if let Some(channel) = self.get_sfx_channel() {
|
||||
channel.set_pos(position);
|
||||
channel.update(&listener);
|
||||
if underwater {
|
||||
channel.play_with_low_pass_filter(sound.convert_samples());
|
||||
} else {
|
||||
channel.play(sound);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
@ -290,48 +267,47 @@ impl AudioFrontend {
|
||||
}
|
||||
}
|
||||
|
||||
/// Play (once) an sfx file by file path at the given position and volume.
|
||||
/// If `underwater` is true, the sound is played with a low pass filter
|
||||
pub fn play_sfx(
|
||||
/// Plays a sfx using a non-spatial sink at the given volume; doesn't need a
|
||||
/// position
|
||||
/// Passing no volume will default to 1.0
|
||||
pub fn emit_ui_sfx(
|
||||
&mut self,
|
||||
sound: &str,
|
||||
pos: Vec3<f32>,
|
||||
vol: Option<f32>,
|
||||
underwater: bool,
|
||||
) -> Result<(), rodio::decoder::DecoderError> {
|
||||
if self.audio_stream.is_some() {
|
||||
let sound = load_ogg(sound).amplify(vol.unwrap_or(1.0));
|
||||
trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
|
||||
volume: Option<f32>,
|
||||
) {
|
||||
// Find sound based on given trigger_item
|
||||
// Randomizes if multiple sounds are found
|
||||
// Errors if no sounds are found
|
||||
if let Some((event, item)) = trigger_item {
|
||||
let sfx_file = match item.files.len() {
|
||||
0 => {
|
||||
debug!("Sfx event {:?} is missing audio file.", event);
|
||||
"voxygen.audio.sfx.placeholder"
|
||||
},
|
||||
1 => item
|
||||
.files
|
||||
.last()
|
||||
.expect("Failed to determine sound file for this trigger item."),
|
||||
_ => {
|
||||
// If more than one file is listed, choose one at random
|
||||
let rand_step = rand::random::<usize>() % item.files.len();
|
||||
&item.files[rand_step]
|
||||
},
|
||||
};
|
||||
// Play sound in empty channel
|
||||
if self.audio_stream.is_some() {
|
||||
let sound = load_ogg(sfx_file).amplify(volume.unwrap_or(1.0));
|
||||
|
||||
let listener = self.listener.clone();
|
||||
if let Some(channel) = self.get_sfx_channel() {
|
||||
channel.set_pos(pos);
|
||||
channel.update(&listener);
|
||||
if underwater {
|
||||
channel.play_with_low_pass_filter(sound.convert_samples());
|
||||
} else {
|
||||
if let Some(channel) = self.get_ui_channel() {
|
||||
channel.play(sound);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("Missing sfx trigger config for external sfx event.",);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn play_ui_sfx(
|
||||
&mut self,
|
||||
sound: &str,
|
||||
vol: Option<f32>,
|
||||
) -> Result<(), rodio::decoder::DecoderError> {
|
||||
if self.audio_stream.is_some() {
|
||||
let sound = load_ogg(sound).amplify(vol.unwrap_or(1.0));
|
||||
|
||||
if let Some(channel) = self.get_ui_channel() {
|
||||
channel.play(sound);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Plays a file at a given volume in the channel with a given tag
|
||||
/// Plays a file at a given volume in the channel with a given tag
|
||||
fn play_ambient(
|
||||
&mut self,
|
||||
channel_tag: AmbientChannelTag,
|
||||
@ -346,7 +322,7 @@ impl AudioFrontend {
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a new ambient channel of the given tag at zero volume
|
||||
/// Adds a new ambient channel of the given tag at zero volume
|
||||
fn new_ambient_channel(&mut self, channel_tag: AmbientChannelTag) {
|
||||
if let Some(audio_stream) = &self.audio_stream {
|
||||
let ambient_channel = AmbientChannel::new(audio_stream, channel_tag, 0.0);
|
||||
@ -355,6 +331,7 @@ impl AudioFrontend {
|
||||
}
|
||||
|
||||
/// Retrieves the channel currently having the given tag
|
||||
/// If no channel with the given tag is found, returns None
|
||||
fn get_ambient_channel(
|
||||
&mut self,
|
||||
channel_tag: AmbientChannelTag,
|
||||
@ -368,6 +345,19 @@ impl AudioFrontend {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the index of the channel having the given tag in the array of
|
||||
/// ambient channels This is used for times when borrowing becomes
|
||||
/// difficult If no channel with the given tag is found, returns None
|
||||
fn get_ambient_channel_index(&self, channel_tag: AmbientChannelTag) -> Option<usize> {
|
||||
if self.audio_stream.is_some() {
|
||||
self.ambient_channels
|
||||
.iter()
|
||||
.position(|channel| channel.get_tag() == channel_tag)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Unused code that may be useful in the future:
|
||||
// Sets the volume of the channel with the given tag to the given volume
|
||||
// fn set_ambient_volume(&mut self, channel_tag: AmbientChannelTag,
|
||||
@ -470,12 +460,19 @@ impl AudioFrontend {
|
||||
pub fn set_sfx_volume(&mut self, sfx_volume: f32) {
|
||||
self.sfx_volume = sfx_volume;
|
||||
|
||||
self.update_sfx_volumes();
|
||||
let sfx_volume = self.get_sfx_volume();
|
||||
for channel in self.sfx_channels.iter_mut() {
|
||||
channel.set_volume(sfx_volume);
|
||||
}
|
||||
for channel in self.ui_channels.iter_mut() {
|
||||
channel.set_volume(sfx_volume);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ambience_volume(&mut self, ambience_volume: f32) {
|
||||
self.ambience_volume = ambience_volume;
|
||||
|
||||
let ambience_volume = self.get_ambience_volume();
|
||||
for channel in self.ambient_channels.iter_mut() {
|
||||
channel.set_volume(ambience_volume)
|
||||
}
|
||||
@ -490,6 +487,7 @@ impl AudioFrontend {
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates master volume in all channels
|
||||
pub fn set_master_volume(&mut self, master_volume: f32) {
|
||||
self.master_volume = master_volume;
|
||||
|
||||
@ -497,15 +495,17 @@ impl AudioFrontend {
|
||||
for channel in self.music_channels.iter_mut() {
|
||||
channel.set_volume(music_volume);
|
||||
}
|
||||
|
||||
self.update_sfx_volumes();
|
||||
}
|
||||
|
||||
fn update_sfx_volumes(&mut self) {
|
||||
let sfx_volume = self.get_sfx_volume();
|
||||
for channel in self.sfx_channels.iter_mut() {
|
||||
channel.set_volume(sfx_volume);
|
||||
}
|
||||
for channel in self.ui_channels.iter_mut() {
|
||||
channel.set_volume(sfx_volume);
|
||||
}
|
||||
let ambience_volume = self.get_ambience_volume();
|
||||
for channel in self.ambient_channels.iter_mut() {
|
||||
channel.set_volume(ambience_volume)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop_ambient_sounds(&mut self) {
|
||||
|
@ -228,6 +228,11 @@ impl MusicMgr {
|
||||
|
||||
use common::comp::{group::ENEMY, Group, Health, Pos};
|
||||
use specs::{Join, WorldExt};
|
||||
// Checks if the music volume is set to zero or audio is disabled
|
||||
// This prevents us from running all the following code unnecessarily
|
||||
if !audio.music_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut activity_state = MusicActivity::Explore;
|
||||
|
||||
|
@ -412,14 +412,13 @@ impl SfxMgr {
|
||||
outcome: &Outcome,
|
||||
audio: &mut AudioFrontend,
|
||||
client: &Client,
|
||||
state: &State,
|
||||
underwater: bool,
|
||||
) {
|
||||
if !audio.sfx_enabled() {
|
||||
return;
|
||||
}
|
||||
let triggers = self.triggers.read();
|
||||
let uids = state.ecs().read_storage::<Uid>();
|
||||
let uids = client.state().ecs().read_storage::<Uid>();
|
||||
|
||||
// TODO handle underwater
|
||||
match outcome {
|
||||
@ -495,7 +494,7 @@ impl SfxMgr {
|
||||
if let Some(client_uid) = uids.get(client.entity()) {
|
||||
if uid == client_uid {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::SkillPointGain);
|
||||
audio.emit_sfx_item(sfx_trigger_item, Some(0.4));
|
||||
audio.emit_ui_sfx(sfx_trigger_item, Some(0.4));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2386,11 +2386,11 @@ impl Hud {
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.set(self.ids.time, ui_widgets);
|
||||
|
||||
// Weather
|
||||
let weather = client.weather_at_player();
|
||||
Text::new(&format!(
|
||||
"Weather({kind:.5}): {{cloud: {cloud:.5}, rain: {rain:.5}, wind: <{wind_x:.5}, \
|
||||
{wind_y:.2}>}}",
|
||||
"Weather({kind}): {{cloud: {cloud:.2}, rain: {rain:.2}, wind: <{wind_x:.0}, \
|
||||
{wind_y:.0}>}}",
|
||||
kind = weather.get_kind(),
|
||||
cloud = weather.cloud,
|
||||
rain = weather.rain,
|
||||
@ -2521,7 +2521,7 @@ impl Hud {
|
||||
// Set debug box dimensions, only timings height is dynamic
|
||||
// TODO: Make the background box size fully dynamic
|
||||
|
||||
let debug_bg_size = [320.0, 370.0 + timings_height];
|
||||
let debug_bg_size = [320.0, 385.0 + timings_height];
|
||||
|
||||
Rectangle::fill(debug_bg_size)
|
||||
.rgba(0.0, 0.0, 0.0, global_state.settings.chat.chat_opacity)
|
||||
|
@ -65,7 +65,7 @@ impl LodData {
|
||||
lod_base: &[u32],
|
||||
lod_alt: &[u32],
|
||||
lod_horizon: &[u32],
|
||||
clouds_size: Vec2<u32>,
|
||||
weather_size: Vec2<u32>,
|
||||
tgt_detail: u32,
|
||||
//border_color: gfx::texture::PackedColor,
|
||||
) -> Self {
|
||||
@ -139,8 +139,8 @@ impl LodData {
|
||||
let texture_info = wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: clouds_size.x,
|
||||
height: clouds_size.y,
|
||||
width: weather_size.x,
|
||||
height: weather_size.y,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
@ -177,7 +177,7 @@ impl LodData {
|
||||
&texture_info,
|
||||
&view_info,
|
||||
&sampler_info,
|
||||
vec![0; clouds_size.x as usize * clouds_size.y as usize * 4].as_slice(),
|
||||
vec![0; weather_size.x as usize * weather_size.y as usize * 4].as_slice(),
|
||||
)
|
||||
};
|
||||
Self {
|
||||
|
@ -70,6 +70,8 @@ pub struct Globals {
|
||||
// To keep 16-byte-aligned.
|
||||
globals_dummy: [f32; 1],
|
||||
}
|
||||
/// Make sure Globals is 16-byte-aligned.
|
||||
const _: () = assert!(core::mem::size_of::<Globals>() % 16 == 0);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||
@ -110,7 +112,6 @@ impl Globals {
|
||||
cam_mode: CameraMode,
|
||||
sprite_render_distance: f32,
|
||||
) -> Self {
|
||||
// dbg!(core::mem::size_of::<Self>() % 16);
|
||||
Self {
|
||||
view_mat: view_mat.into_col_arrays(),
|
||||
proj_mat: proj_mat.into_col_arrays(),
|
||||
|
@ -7,25 +7,29 @@ use vek::*;
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Zeroable, Pod, Default)]
|
||||
pub struct Locals {
|
||||
shadow_matrices: [[f32; 4]; 4],
|
||||
texture_mats: [[f32; 4]; 4],
|
||||
rain_occlusion_matrices: [[f32; 4]; 4],
|
||||
rain_occlusion_texture_mat: [[f32; 4]; 4],
|
||||
/// A rotation of the direction of the rain, relative to the players
|
||||
/// velocity.
|
||||
rel_rain_dir_mat: [[f32; 4]; 4],
|
||||
/// A value to offset the rain, to make it move over time.
|
||||
integrated_rain_vel: f32,
|
||||
// To keep 16-byte-aligned.
|
||||
occlusion_dummy: [f32; 3],
|
||||
}
|
||||
/// Make sure Locals is 16-byte-aligned.
|
||||
const _: () = assert!(core::mem::size_of::<Locals>() % 16 == 0);
|
||||
|
||||
impl Locals {
|
||||
pub fn new(
|
||||
shadow_mat: Mat4<f32>,
|
||||
texture_mat: Mat4<f32>,
|
||||
rain_occlusion_matrices: Mat4<f32>,
|
||||
rain_occlusion_texture_mat: Mat4<f32>,
|
||||
rel_rain_dir_mat: Mat4<f32>,
|
||||
integrated_rain_vel: f32,
|
||||
) -> Self {
|
||||
// dbg!(core::mem::size_of::<Self>() % 16);
|
||||
Self {
|
||||
shadow_matrices: shadow_mat.into_col_arrays(),
|
||||
texture_mats: texture_mat.into_col_arrays(),
|
||||
rain_occlusion_matrices: rain_occlusion_matrices.into_col_arrays(),
|
||||
rain_occlusion_texture_mat: rain_occlusion_texture_mat.into_col_arrays(),
|
||||
rel_rain_dir_mat: rel_rain_dir_mat.into_col_arrays(),
|
||||
integrated_rain_vel,
|
||||
occlusion_dummy: [0.0; 3],
|
||||
@ -91,7 +95,7 @@ impl RainOcclusionFigurePipeline {
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Directed figure shadow pipeline layout"),
|
||||
label: Some("Rain occlusion pipeline layout"),
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&global_layout.globals, &figure_layout.locals],
|
||||
});
|
||||
@ -104,7 +108,7 @@ impl RainOcclusionFigurePipeline {
|
||||
};
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Directed shadow figure pipeline"),
|
||||
label: Some("Rain occlusion figure pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: vs_module,
|
||||
|
@ -49,10 +49,6 @@ pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u16>);
|
||||
const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
|
||||
const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
|
||||
|
||||
// For rain occlusion we only need to render the closest chunks.
|
||||
/// How many chunks are maximally rendered for rain occlusion.
|
||||
pub const RAIN_OCCLUSION_CHUNKS: usize = 9;
|
||||
|
||||
/// A type that stores all the layouts associated with this renderer that never
|
||||
/// change when the RenderMode is modified.
|
||||
struct ImmutableLayouts {
|
||||
@ -738,10 +734,8 @@ impl Renderer {
|
||||
|
||||
update_shadow_bind = true;
|
||||
},
|
||||
shadow => {
|
||||
if let Err(err) = shadow {
|
||||
warn!("Could not create shadow map views: {:?}", err);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Could not create shadow map views: {:?}", err);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -755,10 +749,8 @@ impl Renderer {
|
||||
|
||||
update_shadow_bind = true;
|
||||
},
|
||||
rain => {
|
||||
if let Err(err) = rain {
|
||||
warn!("Could not create rain occlusion map view: {:?}", err);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Could not create rain occlusion map view: {:?}", err);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -136,8 +136,8 @@ impl<'frame> Drawer<'frame> {
|
||||
/// Get the pipeline modes.
|
||||
pub fn pipeline_modes(&self) -> &super::super::PipelineModes { self.borrow.pipeline_modes }
|
||||
|
||||
/// Returns None if the shadow renderer is not enabled at some level or the
|
||||
/// pipelines are not available yet
|
||||
/// Returns None if the rain occlusion renderer is not enabled at some
|
||||
/// level, the pipelines are not available yet or clouds are disabled.
|
||||
pub fn rain_occlusion_pass(&mut self) -> Option<RainOcclusionPassDrawer> {
|
||||
if !self.borrow.pipeline_modes.cloud.is_enabled() {
|
||||
return None;
|
||||
@ -663,7 +663,7 @@ impl<'pass> ShadowPassDrawer<'pass> {
|
||||
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_figure_shadows", self.borrow.device);
|
||||
.scope("directed_figure_shadows", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
@ -674,7 +674,7 @@ impl<'pass> ShadowPassDrawer<'pass> {
|
||||
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_terrain_shadows", self.borrow.device);
|
||||
.scope("directed_terrain_shadows", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
@ -694,7 +694,7 @@ impl<'pass> RainOcclusionPassDrawer<'pass> {
|
||||
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_figure_rain_occlusion", self.borrow.device);
|
||||
.scope("directed_figure_rain_occlusion", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.rain_occlusion_renderer.figure_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
@ -705,7 +705,7 @@ impl<'pass> RainOcclusionPassDrawer<'pass> {
|
||||
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope("direcred_terrain_rain_occlusion", self.borrow.device);
|
||||
.scope("directed_terrain_rain_occlusion", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.rain_occlusion_renderer.terrain_pipeline.pipeline);
|
||||
set_quad_index_buffer::<terrain::Vertex>(&mut render_pass, self.borrow);
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::render::{pipelines::rain_occlusion, renderer::RAIN_OCCLUSION_CHUNKS};
|
||||
use crate::{render::pipelines::rain_occlusion, scene::terrain::RAIN_OCCLUSION_CHUNKS};
|
||||
|
||||
use super::{
|
||||
super::{texture::Texture, RenderError, ShadowMapMode},
|
||||
@ -7,8 +7,8 @@ use super::{
|
||||
use common::{terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use vek::*;
|
||||
|
||||
/// A type that holds shadow map data. Since shadow mapping may not be
|
||||
/// supported on all platforms, we try to keep it separate.
|
||||
/// A type that holds rain occlusion map data. Since rain occlusion mapping may
|
||||
/// not be supported on all platforms, we try to keep it separate.
|
||||
pub struct RainOcclusionMapRenderer {
|
||||
pub depth: Texture,
|
||||
|
||||
|
@ -420,7 +420,7 @@ impl Scene {
|
||||
.unwrap_or(false);
|
||||
self.particle_mgr.handle_outcome(outcome, scene_data);
|
||||
self.sfx_mgr
|
||||
.handle_outcome(outcome, audio, scene_data.client, state, underwater);
|
||||
.handle_outcome(outcome, audio, scene_data.client, underwater);
|
||||
|
||||
match outcome {
|
||||
Outcome::Explosion {
|
||||
@ -1022,6 +1022,8 @@ impl Scene {
|
||||
);
|
||||
|
||||
renderer.update_consts(&mut self.data.rain_occlusion_mats, &[rain_occlusion_locals]);
|
||||
} else {
|
||||
self.integrated_rain_vel = 0.0;
|
||||
}
|
||||
|
||||
let sun_dir = scene_data.get_sun_dir();
|
||||
@ -1106,25 +1108,19 @@ impl Scene {
|
||||
self.figure_mgr.clean(scene_data.tick);
|
||||
|
||||
// Maintain audio
|
||||
if audio.sfx_enabled() {
|
||||
self.sfx_mgr.maintain(
|
||||
audio,
|
||||
scene_data.state,
|
||||
scene_data.player_entity,
|
||||
&self.camera,
|
||||
&self.terrain,
|
||||
client,
|
||||
);
|
||||
}
|
||||
self.sfx_mgr.maintain(
|
||||
audio,
|
||||
scene_data.state,
|
||||
scene_data.player_entity,
|
||||
&self.camera,
|
||||
&self.terrain,
|
||||
client,
|
||||
);
|
||||
|
||||
if audio.ambience_enabled() {
|
||||
self.ambient_mgr
|
||||
.maintain(audio, scene_data.state, client, &self.camera);
|
||||
}
|
||||
self.ambient_mgr
|
||||
.maintain(audio, scene_data.state, client, &self.camera);
|
||||
|
||||
if audio.music_enabled() {
|
||||
self.music_mgr.maintain(audio, scene_data.state, client);
|
||||
}
|
||||
self.music_mgr.maintain(audio, scene_data.state, client);
|
||||
}
|
||||
|
||||
pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group }
|
||||
@ -1180,7 +1176,7 @@ impl Scene {
|
||||
prof_span!("rain occlusion");
|
||||
if let Some(mut occlusion_pass) = drawer.rain_occlusion_pass() {
|
||||
self.terrain
|
||||
.render_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
|
||||
.render_rain_occlusion(&mut occlusion_pass.draw_terrain_shadows(), cam_pos);
|
||||
|
||||
self.figure_mgr.render_shadows(
|
||||
&mut occlusion_pass.draw_figure_shadows(),
|
||||
|
@ -10,7 +10,6 @@ use crate::{
|
||||
},
|
||||
render::{
|
||||
pipelines::{self, ColLights},
|
||||
renderer::RAIN_OCCLUSION_CHUNKS,
|
||||
ColLightInfo, FirstPassDrawer, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model,
|
||||
RenderError, Renderer, SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts,
|
||||
TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
||||
@ -47,6 +46,10 @@ use vek::*;
|
||||
const SPRITE_SCALE: Vec3<f32> = Vec3::new(1.0 / 11.0, 1.0 / 11.0, 1.0 / 11.0);
|
||||
const SPRITE_LOD_LEVELS: usize = 5;
|
||||
|
||||
// For rain occlusion we only need to render the closest chunks.
|
||||
/// How many chunks are maximally rendered for rain occlusion.
|
||||
pub const RAIN_OCCLUSION_CHUNKS: usize = 9;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Visibility {
|
||||
in_range: bool,
|
||||
@ -1405,10 +1408,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// Check if there is rain near the camera
|
||||
let max_weather = scene_data.state.max_weather_near(focus_pos.xy());
|
||||
let visible_occlusion_volume = if max_weather.rain > 0.0 {
|
||||
let occlusion_box = visible_bounding_box;
|
||||
let visible_bounding_box = math::Aabb::<f32> {
|
||||
min: math::Vec3::from(occlusion_box.min - focus_off),
|
||||
max: math::Vec3::from(occlusion_box.max - focus_off),
|
||||
min: math::Vec3::from(visible_bounding_box.min - focus_off),
|
||||
max: math::Vec3::from(visible_bounding_box.max - focus_off),
|
||||
};
|
||||
let visible_bounds_fine = math::Aabb {
|
||||
min: visible_bounding_box.min.as_::<f64>(),
|
||||
@ -1490,7 +1492,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.for_each(|(model, locals)| drawer.draw(model, locals));
|
||||
}
|
||||
|
||||
pub fn render_occlusion<'a>(
|
||||
pub fn render_rain_occlusion<'a>(
|
||||
&'a self,
|
||||
drawer: &mut TerrainShadowDrawer<'_, 'a>,
|
||||
focus_pos: Vec3<f32>,
|
||||
|
@ -269,9 +269,7 @@ impl SessionState {
|
||||
| InventoryUpdateEvent::EntityCollectFailed { .. }
|
||||
| InventoryUpdateEvent::BlockCollectFailed { .. }
|
||||
| InventoryUpdateEvent::Craft => {
|
||||
global_state
|
||||
.audio
|
||||
.emit_sfx_item(sfx_trigger_item, Some(1.0));
|
||||
global_state.audio.emit_ui_sfx(sfx_trigger_item, Some(1.0));
|
||||
},
|
||||
_ => global_state.audio.emit_sfx(
|
||||
sfx_trigger_item,
|
||||
@ -1207,6 +1205,9 @@ impl PlayState for SessionState {
|
||||
},
|
||||
HudEvent::Logout => {
|
||||
self.client.borrow_mut().logout();
|
||||
// Stop all sounds
|
||||
// TODO: Abstract this behavior to all instances of PlayStateResult::Pop
|
||||
// somehow
|
||||
global_state.audio.stop_ambient_sounds();
|
||||
global_state.audio.stop_all_sfx();
|
||||
return PlayStateResult::Pop;
|
||||
|
Loading…
Reference in New Issue
Block a user