use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum ViewportFocusPolicy {
#[default]
FocusedAlways,
Manual,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum PbrDebugMode {
#[default]
None,
BaseColor,
Normal,
Metallic,
Roughness,
Occlusion,
Emissive,
F,
G,
D,
Diffuse,
Specular,
MipRainbow,
}
impl PbrDebugMode {
pub const ALL: &'static [PbrDebugMode] = &[
PbrDebugMode::None,
PbrDebugMode::BaseColor,
PbrDebugMode::Normal,
PbrDebugMode::Metallic,
PbrDebugMode::Roughness,
PbrDebugMode::Occlusion,
PbrDebugMode::Emissive,
PbrDebugMode::F,
PbrDebugMode::G,
PbrDebugMode::D,
PbrDebugMode::Diffuse,
PbrDebugMode::Specular,
PbrDebugMode::MipRainbow,
];
pub fn name(&self) -> &'static str {
match self {
PbrDebugMode::None => "None",
PbrDebugMode::BaseColor => "Base Color",
PbrDebugMode::Normal => "Normal",
PbrDebugMode::Metallic => "Metallic",
PbrDebugMode::Roughness => "Roughness",
PbrDebugMode::Occlusion => "Occlusion",
PbrDebugMode::Emissive => "Emissive",
PbrDebugMode::F => "Fresnel (F)",
PbrDebugMode::G => "Geometry (G)",
PbrDebugMode::D => "Distribution (D)",
PbrDebugMode::Diffuse => "Diffuse",
PbrDebugMode::Specular => "Specular",
PbrDebugMode::MipRainbow => "Mip Rainbow",
}
}
pub fn as_u32(&self) -> u32 {
match self {
PbrDebugMode::None => 0,
PbrDebugMode::BaseColor => 1,
PbrDebugMode::Normal => 2,
PbrDebugMode::Metallic => 3,
PbrDebugMode::Roughness => 4,
PbrDebugMode::Occlusion => 5,
PbrDebugMode::Emissive => 6,
PbrDebugMode::F => 7,
PbrDebugMode::G => 8,
PbrDebugMode::D => 9,
PbrDebugMode::Diffuse => 10,
PbrDebugMode::Specular => 11,
PbrDebugMode::MipRainbow => 12,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum DepthOfFieldQuality {
Low,
#[default]
Medium,
High,
}
impl DepthOfFieldQuality {
pub const ALL: &'static [DepthOfFieldQuality] = &[
DepthOfFieldQuality::Low,
DepthOfFieldQuality::Medium,
DepthOfFieldQuality::High,
];
pub fn name(&self) -> &'static str {
match self {
DepthOfFieldQuality::Low => "Low",
DepthOfFieldQuality::Medium => "Medium",
DepthOfFieldQuality::High => "High",
}
}
pub fn sample_count(&self) -> u32 {
match self {
DepthOfFieldQuality::Low => 8,
DepthOfFieldQuality::Medium => 16,
DepthOfFieldQuality::High => 32,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct DepthOfField {
pub enabled: bool,
pub focus_distance: f32,
pub focus_range: f32,
pub max_blur_radius: f32,
pub bokeh_threshold: f32,
pub bokeh_intensity: f32,
pub quality: DepthOfFieldQuality,
pub visualize_coc: bool,
pub tilt_shift_enabled: bool,
pub tilt_shift_angle: f32,
pub tilt_shift_center: f32,
pub tilt_shift_blur_amount: f32,
pub visualize_tilt_shift: bool,
}
impl Default for DepthOfField {
fn default() -> Self {
Self {
enabled: false,
focus_distance: 10.0,
focus_range: 5.0,
max_blur_radius: 8.0,
bokeh_threshold: 0.8,
bokeh_intensity: 1.0,
quality: DepthOfFieldQuality::Medium,
visualize_coc: false,
tilt_shift_enabled: false,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
}
impl DepthOfField {
pub fn portrait() -> Self {
Self {
enabled: true,
focus_distance: 3.0,
focus_range: 1.5,
max_blur_radius: 12.0,
bokeh_threshold: 0.6,
bokeh_intensity: 1.2,
quality: DepthOfFieldQuality::High,
visualize_coc: false,
tilt_shift_enabled: false,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
pub fn cinematic() -> Self {
Self {
enabled: true,
focus_distance: 8.0,
focus_range: 4.0,
max_blur_radius: 10.0,
bokeh_threshold: 0.7,
bokeh_intensity: 1.0,
quality: DepthOfFieldQuality::Medium,
visualize_coc: false,
tilt_shift_enabled: false,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
pub fn macro_shot() -> Self {
Self {
enabled: true,
focus_distance: 0.5,
focus_range: 0.2,
max_blur_radius: 16.0,
bokeh_threshold: 0.5,
bokeh_intensity: 1.5,
quality: DepthOfFieldQuality::High,
visualize_coc: false,
tilt_shift_enabled: false,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
pub fn landscape() -> Self {
Self {
enabled: true,
focus_distance: 50.0,
focus_range: 100.0,
max_blur_radius: 4.0,
bokeh_threshold: 0.9,
bokeh_intensity: 0.5,
quality: DepthOfFieldQuality::Low,
visualize_coc: false,
tilt_shift_enabled: false,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
pub fn tilt_shift() -> Self {
Self {
enabled: true,
focus_distance: 10.0,
focus_range: 5.0,
max_blur_radius: 12.0,
bokeh_threshold: 0.8,
bokeh_intensity: 0.8,
quality: DepthOfFieldQuality::Medium,
visualize_coc: false,
tilt_shift_enabled: true,
tilt_shift_angle: 0.0,
tilt_shift_center: 0.0,
tilt_shift_blur_amount: 1.0,
visualize_tilt_shift: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum TonemapAlgorithm {
#[default]
Aces,
Aces2,
Reinhard,
ReinhardExtended,
Uncharted2,
AgX,
Neutral,
None,
}
impl TonemapAlgorithm {
pub const ALL: &'static [TonemapAlgorithm] = &[
TonemapAlgorithm::Aces,
TonemapAlgorithm::Aces2,
TonemapAlgorithm::Reinhard,
TonemapAlgorithm::ReinhardExtended,
TonemapAlgorithm::Uncharted2,
TonemapAlgorithm::AgX,
TonemapAlgorithm::Neutral,
TonemapAlgorithm::None,
];
pub fn as_u32(&self) -> u32 {
match self {
TonemapAlgorithm::Aces => 0,
TonemapAlgorithm::Aces2 => 7,
TonemapAlgorithm::Reinhard => 1,
TonemapAlgorithm::ReinhardExtended => 2,
TonemapAlgorithm::Uncharted2 => 3,
TonemapAlgorithm::AgX => 4,
TonemapAlgorithm::Neutral => 5,
TonemapAlgorithm::None => 6,
}
}
pub fn name(&self) -> &'static str {
match self {
TonemapAlgorithm::Aces => "ACES",
TonemapAlgorithm::Aces2 => "ACES (Fitted)",
TonemapAlgorithm::Reinhard => "Reinhard",
TonemapAlgorithm::ReinhardExtended => "Reinhard Extended",
TonemapAlgorithm::Uncharted2 => "Uncharted 2",
TonemapAlgorithm::AgX => "AgX",
TonemapAlgorithm::Neutral => "Neutral",
TonemapAlgorithm::None => "None",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum ColorGradingPreset {
#[default]
Default,
Vibrant,
Cinematic,
Muted,
HighContrast,
Warm,
Cool,
Retro,
Desaturated,
Custom,
}
impl ColorGradingPreset {
pub const ALL: &'static [ColorGradingPreset] = &[
ColorGradingPreset::Default,
ColorGradingPreset::Vibrant,
ColorGradingPreset::Cinematic,
ColorGradingPreset::Muted,
ColorGradingPreset::HighContrast,
ColorGradingPreset::Warm,
ColorGradingPreset::Cool,
ColorGradingPreset::Retro,
ColorGradingPreset::Desaturated,
ColorGradingPreset::Custom,
];
pub fn name(&self) -> &'static str {
match self {
ColorGradingPreset::Default => "Default",
ColorGradingPreset::Vibrant => "Vibrant",
ColorGradingPreset::Cinematic => "Cinematic",
ColorGradingPreset::Muted => "Muted",
ColorGradingPreset::HighContrast => "High Contrast",
ColorGradingPreset::Warm => "Warm",
ColorGradingPreset::Cool => "Cool",
ColorGradingPreset::Retro => "Retro",
ColorGradingPreset::Desaturated => "Desaturated",
ColorGradingPreset::Custom => "Custom",
}
}
pub fn to_color_grading(&self) -> ColorGrading {
let preset = *self;
match self {
ColorGradingPreset::Default => ColorGrading {
preset,
..ColorGrading::default()
},
ColorGradingPreset::Vibrant => ColorGrading {
saturation: 1.3,
brightness: 0.02,
contrast: 1.1,
vibrance: 0.4,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Cinematic => ColorGrading {
gamma: 2.4,
saturation: 0.9,
brightness: -0.02,
contrast: 1.15,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Muted => ColorGrading {
saturation: 0.7,
contrast: 0.9,
tonemap_algorithm: TonemapAlgorithm::Reinhard,
preset,
..ColorGrading::default()
},
ColorGradingPreset::HighContrast => ColorGrading {
saturation: 1.1,
contrast: 1.4,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Warm => ColorGrading {
gamma: 2.1,
saturation: 1.1,
brightness: 0.03,
contrast: 1.05,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Cool => ColorGrading {
gamma: 2.3,
saturation: 0.95,
brightness: -0.01,
contrast: 1.05,
tonemap_algorithm: TonemapAlgorithm::Neutral,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Retro => ColorGrading {
gamma: 2.0,
saturation: 0.8,
brightness: 0.05,
contrast: 1.2,
tonemap_algorithm: TonemapAlgorithm::Reinhard,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Desaturated => ColorGrading {
saturation: 0.3,
preset,
..ColorGrading::default()
},
ColorGradingPreset::Custom => ColorGrading::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ColorGrading {
pub exposure: f32,
pub exposure_compensation_ev: f32,
pub auto_exposure: bool,
pub auto_exposure_target: f32,
pub auto_exposure_rate: f32,
pub auto_exposure_min_ev: f32,
pub auto_exposure_max_ev: f32,
pub gamma: f32,
pub saturation: f32,
pub brightness: f32,
pub contrast: f32,
pub vibrance: f32,
pub vignette_intensity: f32,
pub vignette_radius: f32,
pub vignette_smoothness: f32,
pub chromatic_aberration: f32,
pub color_lut_weight: f32,
pub tonemap_algorithm: TonemapAlgorithm,
pub preset: ColorGradingPreset,
}
impl Default for ColorGrading {
fn default() -> Self {
Self {
exposure: 1.0,
exposure_compensation_ev: 0.0,
auto_exposure: false,
auto_exposure_target: 0.18,
auto_exposure_rate: 1.5,
auto_exposure_min_ev: -3.0,
auto_exposure_max_ev: 5.0,
gamma: 2.2,
saturation: 1.0,
brightness: 0.0,
contrast: 1.0,
vibrance: 0.0,
vignette_intensity: 0.0,
vignette_radius: 0.6,
vignette_smoothness: 0.4,
chromatic_aberration: 0.0,
color_lut_weight: 0.0,
tonemap_algorithm: TonemapAlgorithm::Aces,
preset: ColorGradingPreset::Default,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct VertexSnap {
pub resolution: [f32; 2],
}
impl Default for VertexSnap {
fn default() -> Self {
Self {
resolution: [160.0, 120.0],
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Fog {
pub color: [f32; 3],
pub start: f32,
pub end: f32,
#[serde(default)]
pub mode: FogMode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum FogMode {
#[default]
Linear,
Exponential,
ExponentialSquared,
}
impl FogMode {
pub fn as_u32(self) -> u32 {
match self {
FogMode::Linear => 1,
FogMode::Exponential => 2,
FogMode::ExponentialSquared => 3,
}
}
pub fn from_u32(value: u32) -> Self {
match value {
2 => FogMode::Exponential,
3 => FogMode::ExponentialSquared,
_ => FogMode::Linear,
}
}
}
impl Default for Fog {
fn default() -> Self {
Self {
color: [0.5, 0.5, 0.55],
start: 2.0,
end: 15.0,
mode: FogMode::Linear,
}
}
}
#[derive(Clone)]
pub struct DayNightState {
pub hour: f32,
pub speed: f32,
pub auto_cycle: bool,
pub sun_entity: Option<crate::entity::RenderEntity>,
pub ibl_snapshot_hours: Vec<f32>,
}
impl Default for DayNightState {
fn default() -> Self {
Self {
hour: 12.0,
speed: 0.0,
auto_cycle: false,
sun_entity: None,
ibl_snapshot_hours: vec![0.0, 4.0, 7.0, 10.0, 14.0, 17.0, 20.0],
}
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, enum2schema::Schema,
)]
#[schema(string_enum)]
pub enum Atmosphere {
#[default]
None,
Sky,
CloudySky,
Space,
Nebula,
Sunset,
DayNight,
Hdr,
HdrMip0,
HdrMip1,
HdrMip2,
HdrMip3,
HdrMip4,
Irradiance,
PrefilterMip0,
PrefilterMip1,
PrefilterMip2,
PrefilterMip3,
PrefilterMip4,
}
impl Atmosphere {
pub const ALL: &'static [Atmosphere] = &[
Atmosphere::None,
Atmosphere::Sky,
Atmosphere::CloudySky,
Atmosphere::Space,
Atmosphere::Nebula,
Atmosphere::Sunset,
Atmosphere::DayNight,
Atmosphere::Hdr,
Atmosphere::HdrMip0,
Atmosphere::HdrMip1,
Atmosphere::HdrMip2,
Atmosphere::HdrMip3,
Atmosphere::HdrMip4,
Atmosphere::Irradiance,
Atmosphere::PrefilterMip0,
Atmosphere::PrefilterMip1,
Atmosphere::PrefilterMip2,
Atmosphere::PrefilterMip3,
Atmosphere::PrefilterMip4,
];
pub fn mip_level(&self) -> f32 {
match self {
Atmosphere::HdrMip0 | Atmosphere::PrefilterMip0 => 0.0,
Atmosphere::HdrMip1 | Atmosphere::PrefilterMip1 => 1.0,
Atmosphere::HdrMip2 | Atmosphere::PrefilterMip2 => 2.0,
Atmosphere::HdrMip3 | Atmosphere::PrefilterMip3 => 3.0,
Atmosphere::HdrMip4 | Atmosphere::PrefilterMip4 => 4.0,
_ => 0.0,
}
}
pub fn next(self) -> Self {
let all = Self::ALL;
let current_index = all.iter().position(|&a| a == self).unwrap_or(0);
let next_index = (current_index + 1) % all.len();
all[next_index]
}
pub fn previous(self) -> Self {
let all = Self::ALL;
let current_index = all.iter().position(|&a| a == self).unwrap_or(0);
let prev_index = if current_index == 0 {
all.len() - 1
} else {
current_index - 1
};
all[prev_index]
}
pub fn is_procedural(&self) -> bool {
matches!(
self,
Atmosphere::Sky
| Atmosphere::CloudySky
| Atmosphere::Space
| Atmosphere::Nebula
| Atmosphere::Sunset
| Atmosphere::DayNight
)
}
pub fn as_procedural_cubemap_type(&self) -> Option<u32> {
match self {
Atmosphere::Sky => Some(0),
Atmosphere::CloudySky => Some(1),
Atmosphere::Space => Some(2),
Atmosphere::Nebula => Some(3),
Atmosphere::Sunset => Some(4),
Atmosphere::DayNight => Some(5),
_ => None,
}
}
}
#[derive(Default)]
pub struct IblViews {
pub brdf_lut_view: Option<wgpu::TextureView>,
pub irradiance_view: Option<wgpu::TextureView>,
pub prefiltered_view: Option<wgpu::TextureView>,
}
impl Clone for IblViews {
fn clone(&self) -> Self {
Self {
brdf_lut_view: self.brdf_lut_view.clone(),
irradiance_view: self.irradiance_view.clone(),
prefiltered_view: self.prefiltered_view.clone(),
}
}
}
#[derive(Clone)]
pub struct MeshLodLevel {
pub mesh_name: String,
pub min_screen_pixels: f32,
}
#[derive(Clone)]
pub struct MeshLodChain {
pub base_mesh: String,
pub levels: Vec<MeshLodLevel>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct EffectsUniforms {
pub time: f32,
pub chromatic_aberration: f32,
pub wave_distortion: f32,
pub color_shift: f32,
pub kaleidoscope_segments: f32,
pub crt_scanlines: f32,
pub vignette: f32,
pub plasma_intensity: f32,
pub glitch_intensity: f32,
pub mirror_mode: f32,
pub invert: f32,
pub hue_rotation: f32,
pub raymarch_mode: f32,
pub raymarch_blend: f32,
pub film_grain: f32,
pub sharpen: f32,
pub pixelate: f32,
pub color_posterize: f32,
pub radial_blur: f32,
pub tunnel_speed: f32,
pub fractal_iterations: f32,
pub glow_intensity: f32,
pub screen_shake: f32,
pub zoom_pulse: f32,
pub speed_lines: f32,
pub color_grade_mode: f32,
pub vhs_distortion: f32,
pub lens_flare: f32,
pub edge_glow: f32,
pub saturation: f32,
pub warp_speed: f32,
pub pulse_rings: f32,
pub heat_distortion: f32,
pub digital_rain: f32,
pub strobe: f32,
pub color_cycle_speed: f32,
pub feedback_amount: f32,
pub ascii_mode: f32,
}
impl Default for EffectsUniforms {
fn default() -> Self {
Self {
time: 0.0,
chromatic_aberration: 0.0,
wave_distortion: 0.0,
color_shift: 0.0,
kaleidoscope_segments: 0.0,
crt_scanlines: 0.0,
vignette: 0.0,
plasma_intensity: 0.0,
glitch_intensity: 0.0,
mirror_mode: 0.0,
invert: 0.0,
hue_rotation: 0.0,
raymarch_mode: 0.0,
raymarch_blend: 0.0,
film_grain: 0.0,
sharpen: 0.0,
pixelate: 0.0,
color_posterize: 0.0,
radial_blur: 0.0,
tunnel_speed: 1.0,
fractal_iterations: 4.0,
glow_intensity: 0.0,
screen_shake: 0.0,
zoom_pulse: 0.0,
speed_lines: 0.0,
color_grade_mode: 0.0,
vhs_distortion: 0.0,
lens_flare: 0.0,
edge_glow: 0.0,
saturation: 1.0,
warp_speed: 0.0,
pulse_rings: 0.0,
heat_distortion: 0.0,
digital_rain: 0.0,
strobe: 0.0,
color_cycle_speed: 1.0,
feedback_amount: 0.0,
ascii_mode: 0.0,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RaymarchMode {
Off = 0,
Tunnel = 1,
Fractal = 2,
Mandelbulb = 3,
PlasmaVortex = 4,
Geometric = 5,
}
impl From<u32> for RaymarchMode {
fn from(value: u32) -> Self {
match value {
1 => RaymarchMode::Tunnel,
2 => RaymarchMode::Fractal,
3 => RaymarchMode::Mandelbulb,
4 => RaymarchMode::PlasmaVortex,
5 => RaymarchMode::Geometric,
_ => RaymarchMode::Off,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ColorGradeMode {
None = 0,
Cyberpunk = 1,
Sunset = 2,
Grayscale = 3,
Sepia = 4,
Matrix = 5,
HotMetal = 6,
}
impl From<u32> for ColorGradeMode {
fn from(value: u32) -> Self {
match value {
1 => ColorGradeMode::Cyberpunk,
2 => ColorGradeMode::Sunset,
3 => ColorGradeMode::Grayscale,
4 => ColorGradeMode::Sepia,
5 => ColorGradeMode::Matrix,
6 => ColorGradeMode::HotMetal,
_ => ColorGradeMode::None,
}
}
}
#[derive(Clone, Debug)]
pub struct EffectsState {
pub uniforms: EffectsUniforms,
pub enabled: bool,
pub animate_hue: bool,
}
impl Default for EffectsState {
fn default() -> Self {
Self {
uniforms: EffectsUniforms::default(),
enabled: true,
animate_hue: false,
}
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct RenderSettings {
pub frame_rate_limit: Option<f32>,
pub atmosphere: Atmosphere,
pub show_sky: bool,
pub render_layer_world_enabled: bool,
pub render_layer_overlay_enabled: bool,
pub render_world_to_swapchain: bool,
pub clear_color: [f32; 4],
pub ui_scale: Option<f32>,
pub unlit_mode: bool,
pub vertex_snap: Option<VertexSnap>,
pub affine_texture_mapping: bool,
pub material_anisotropy_filtering: u16,
pub fog: Option<Fog>,
pub color_grading: ColorGrading,
pub bloom_enabled: bool,
pub bloom_intensity: f32,
pub bloom_threshold: f32,
pub bloom_knee: f32,
pub bloom_filter_radius: f32,
pub depth_of_field: DepthOfField,
pub ssao_enabled: bool,
pub ssao_radius: f32,
pub ssao_bias: f32,
pub ssao_intensity: f32,
pub ssao_sample_count: u32,
pub ssao_blur_depth_threshold: f32,
pub ssao_blur_normal_power: f32,
pub ssgi_enabled: bool,
pub ssgi_radius: f32,
pub ssgi_intensity: f32,
pub ssgi_max_steps: u32,
pub ssr_enabled: bool,
pub ssr_max_steps: u32,
pub ssr_thickness: f32,
pub ssr_max_distance: f32,
pub ssr_stride: f32,
pub ssr_fade_start: f32,
pub ssr_fade_end: f32,
pub ssr_intensity: f32,
pub ambient_light: [f32; 4],
pub taa_enabled: bool,
pub taa_blend: f32,
pub taa_sharpness: f32,
pub water_enabled: bool,
pub vsync_enabled: bool,
pub render_scale: f32,
pub ibl_blend_factor: f32,
}
#[derive(Clone)]
pub struct DebugDraw {
pub show_grid: bool,
pub show_bounding_volumes: bool,
pub show_selected_bounding_volume: bool,
pub show_normals: bool,
pub normal_line_length: f32,
pub normal_line_color: [f32; 4],
pub selection_outline_enabled: bool,
pub selection_outline_color: [f32; 4],
pub pbr_debug_mode: PbrDebugMode,
pub texture_debug_stripes: bool,
pub texture_debug_stripes_speed: f32,
pub ssao_visualization: bool,
}
#[derive(Clone, Default)]
pub struct EditorSelection {
pub bounding_volume_selected_entity: Option<crate::entity::RenderEntity>,
pub selected_entities: Vec<crate::entity::RenderEntity>,
pub culling_camera_override: Option<crate::entity::RenderEntity>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum GpuDeviceType {
#[default]
Other,
IntegratedGpu,
DiscreteGpu,
VirtualGpu,
Cpu,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum GpuBackend {
#[default]
Other,
Vulkan,
Metal,
Dx12,
Gl,
WebGpu,
WebGl,
}
#[derive(Debug, Clone, Default)]
pub struct GpuProfile {
pub backend: GpuBackend,
pub device_type: GpuDeviceType,
pub name: String,
}
impl GpuProfile {
pub fn is_webgl(&self) -> bool {
self.backend == GpuBackend::WebGl
}
pub fn is_low_power(&self) -> bool {
matches!(
self.device_type,
GpuDeviceType::IntegratedGpu | GpuDeviceType::VirtualGpu | GpuDeviceType::Cpu
)
}
}
#[derive(Clone, Debug)]
pub struct RenderView {
pub view: nalgebra_glm::Mat4,
pub projection: nalgebra_glm::Mat4,
pub view_projection: nalgebra_glm::Mat4,
pub inverse_view: nalgebra_glm::Mat4,
pub inverse_projection: nalgebra_glm::Mat4,
pub inverse_view_projection: nalgebra_glm::Mat4,
pub camera_position: nalgebra_glm::Vec3,
pub camera_right: nalgebra_glm::Vec3,
pub camera_up: nalgebra_glm::Vec3,
pub frustum_planes: [nalgebra_glm::Vec4; 6],
pub z_near: f32,
pub z_far: f32,
pub y_fov_rad: f32,
pub aspect: f32,
pub orthographic: Option<(f32, f32)>,
pub screen_size: (u32, u32),
pub constrained_aspect: Option<f32>,
}
#[cfg(feature = "wgpu")]
#[derive(Clone, Default)]
pub struct RenderLighting {
pub lights_data: Vec<crate::wgpu::passes::geometry::projection::LightData>,
pub num_directional_lights: u32,
pub directional_light_direction: [f32; 4],
pub has_directional_light: bool,
pub entity_to_lights_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
pub cascade_view_projections: [[[f32; 4]; 4]; crate::wgpu::passes::NUM_SHADOW_CASCADES],
pub cascade_diameters: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
pub cascade_split_distances: [f32; crate::wgpu::passes::NUM_SHADOW_CASCADES],
pub light_view_projection: [[f32; 4]; 4],
pub shadow_bias: f32,
pub shadow_normal_bias: f32,
pub directional_light_size: f32,
pub shadows_enabled: f32,
pub area_lights_data: Vec<crate::wgpu::passes::geometry::projection::AreaLightData>,
pub area_entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
pub sun_direction: nalgebra_glm::Vec3,
pub sun_color: nalgebra_glm::Vec3,
}
#[derive(Clone, Copy, Debug)]
pub struct DynamicObjectState {
pub visible: u32,
pub morph_weights: [f32; 8],
pub transform: nalgebra_glm::Mat4,
pub culling_mask: u32,
pub is_overlay: u32,
pub render_layer: u32,
}
#[derive(Clone, Default)]
pub struct InstancedObjectData {
pub world_models: Vec<[[f32; 4]; 4]>,
pub world_normals: Vec<[[f32; 4]; 3]>,
pub local_matrices: Vec<nalgebra_glm::Mat4>,
pub custom_tints: Vec<[f32; 4]>,
pub mesh_name: String,
pub render_layer: u32,
pub visible: u32,
pub parent_transform: nalgebra_glm::Mat4,
}
#[derive(Clone)]
pub struct SkinnedChannelData {
pub property: u32,
pub interpolation: u32,
pub input: Vec<f32>,
pub values: Vec<[f32; 4]>,
pub stride: u32,
}
#[derive(Clone)]
pub struct SkinnedJointData {
pub local_index: u32,
pub parent_local: Option<u32>,
pub rest_translation: [f32; 3],
pub rest_rotation: [f32; 4],
pub rest_scale: [f32; 3],
pub cur_channels: Vec<SkinnedChannelData>,
pub blend_channels: Vec<SkinnedChannelData>,
pub layer_channels: Vec<Vec<SkinnedChannelData>>,
}
#[derive(Clone)]
pub struct SkinnedSkeletonData {
pub skin_entity: crate::entity::RenderEntity,
pub player_entity: crate::entity::RenderEntity,
pub armature_parent: Option<crate::entity::RenderEntity>,
pub joint_count: u32,
pub layer_count: u32,
pub joints_ordered: Vec<SkinnedJointData>,
}
#[derive(Default, Clone)]
pub struct RenderSkinning {
pub cache: crate::skinning::SkinningCache,
pub bone_transforms: Vec<nalgebra_glm::Mat4>,
pub static_generation: u64,
pub bone_transforms_generation: u64,
}
#[derive(Clone, Default)]
pub struct SkinnedAnimationSnapshot {
pub signature: u64,
pub skeletons: Vec<SkinnedSkeletonData>,
pub player_runtime: std::collections::HashMap<crate::entity::RenderEntity, [f32; 3]>,
pub layer_runtime: std::collections::HashMap<(crate::entity::RenderEntity, usize), [f32; 2]>,
pub armature_roots: std::collections::HashMap<crate::entity::RenderEntity, nalgebra_glm::Mat4>,
}
#[derive(Clone, Default)]
pub struct RenderMaterialEntry {
pub material: crate::material::Material,
pub texture_ids: crate::material::MaterialTextureIds,
}
#[derive(Clone, Default)]
pub struct RenderMaterials {
pub entries: Vec<RenderMaterialEntry>,
pub name_to_id: std::collections::HashMap<String, u32>,
pub entity_to_id: std::collections::HashMap<crate::entity::RenderEntity, u32>,
pub entity_to_name: std::collections::HashMap<crate::entity::RenderEntity, String>,
pub transparent_ids: std::collections::HashSet<u32>,
pub mask_ids: std::collections::HashSet<u32>,
pub double_sided_ids: std::collections::HashSet<u32>,
pub generation: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum RenderLightType {
#[default]
Directional,
Point,
Spot,
Area,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum RenderAreaLightShape {
#[default]
Rectangle,
Disk,
Sphere,
Tube,
}
#[derive(Clone)]
pub struct RenderLightData {
pub light_type: RenderLightType,
pub color: nalgebra_glm::Vec3,
pub intensity: f32,
pub range: f32,
pub inner_cone_angle: f32,
pub outer_cone_angle: f32,
pub cast_shadows: bool,
pub shadow_bias: f32,
pub shadow_resolution: u32,
pub shadow_distance: f32,
pub cookie_texture: Option<String>,
pub area_shape: RenderAreaLightShape,
pub area_width: f32,
pub area_height: f32,
pub area_radius: f32,
pub area_two_sided: bool,
pub area_emissive_texture: Option<String>,
pub shadow_normal_bias: f32,
pub shadow_softness: f32,
}
#[derive(Clone)]
pub struct RenderLight {
pub entity: crate::entity::RenderEntity,
pub light: RenderLightData,
pub transform: nalgebra_glm::Mat4,
}
#[derive(Clone, Default)]
pub struct RenderLights {
pub lights: Vec<RenderLight>,
pub entity_to_index: std::collections::HashMap<crate::entity::RenderEntity, usize>,
}
#[derive(Clone)]
pub struct RenderDecalData {
pub texture: Option<String>,
pub emissive_texture: Option<String>,
pub emissive_strength: f32,
pub color: [f32; 4],
pub size: nalgebra_glm::Vec2,
pub depth: f32,
pub normal_threshold: f32,
pub fade_start: f32,
pub fade_end: f32,
}
#[derive(Clone)]
pub struct RenderDecal {
pub decal: RenderDecalData,
pub transform: nalgebra_glm::Mat4,
pub visible: bool,
}
#[derive(Clone, Debug)]
pub struct RenderWaterData {
pub half_extents: nalgebra_glm::Vec2,
pub tessellation: u32,
pub wave_amplitude: f32,
pub wave_steepness: f32,
pub wave_length: f32,
pub wave_speed: f32,
pub wave_direction_radians: f32,
pub shallow_color: [f32; 3],
pub deep_color: [f32; 3],
pub depth_fade_distance: f32,
pub edge_foam_distance: f32,
pub foam_amount: f32,
pub foam_color: [f32; 3],
pub roughness: f32,
pub fresnel_power: f32,
pub reflection_strength: f32,
pub refraction_strength: f32,
pub specular_strength: f32,
}
#[derive(Clone)]
pub struct RenderWater {
pub water: RenderWaterData,
pub transform: nalgebra_glm::Mat4,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum RenderClothPinning {
#[default]
TopRow,
TopCorners,
None,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RenderClothData {
pub columns: u32,
pub rows: u32,
pub width: f32,
pub height: f32,
pub pinning: RenderClothPinning,
pub stiffness: f32,
pub damping: f32,
pub substeps: u32,
pub solver_iterations: u32,
pub gravity: nalgebra_glm::Vec3,
pub wind_response: f32,
pub ground_height: Option<f32>,
pub texture_tiling: nalgebra_glm::Vec2,
pub reset_epoch: u32,
}
#[derive(Clone)]
pub struct RenderCloth {
pub entity: crate::entity::RenderEntity,
pub cloth: RenderClothData,
pub transform: nalgebra_glm::Mat4,
pub mesh_name: String,
}
#[derive(Clone)]
pub struct RenderParticleEmitter {
pub entity: crate::entity::RenderEntity,
pub emitter: crate::particles::ParticleEmitter,
}
#[derive(Clone, Default)]
pub struct RenderShadowCasters {
pub meshes: Vec<crate::entity::RenderEntity>,
pub instanced: Vec<crate::entity::RenderEntity>,
pub skinned: Vec<crate::entity::RenderEntity>,
}
#[derive(Clone)]
pub struct RenderText {
pub mesh: crate::text_data::TextMesh,
pub color: nalgebra_glm::Vec4,
pub outline_color: nalgebra_glm::Vec4,
pub outline_width: f32,
pub smoothing: f32,
pub billboard: bool,
pub transform: nalgebra_glm::Mat4,
pub char_count: usize,
pub character_colors: Option<Vec<Option<nalgebra_glm::Vec4>>>,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct RenderBounds {
pub center: nalgebra_glm::Vec3,
pub sphere_radius: f32,
}
#[derive(Clone)]
pub struct RendererState {
pub auto_frame_rate_limit_baseline: Option<f32>,
pub taa_jitter: [f32; 2],
pub view_projection: [[f32; 4]; 4],
pub prev_view_projection: [[f32; 4]; 4],
pub gpu_culling_enabled: bool,
pub occlusion_culling_enabled: bool,
pub gpu_batching_enabled: bool,
pub min_screen_pixel_size: f32,
pub min_window_size: Option<(u32, u32)>,
pub use_fullscreen: bool,
pub show_cursor: bool,
pub letterbox_amount: f32,
pub letterbox_target: f32,
pub day_night: DayNightState,
pub mesh_lod_chains: Vec<MeshLodChain>,
pub active_view: EffectiveShading,
pub render_view: Option<RenderView>,
pub render_dynamic_objects:
std::collections::HashMap<crate::entity::RenderEntity, DynamicObjectState>,
pub render_materials: RenderMaterials,
pub render_object_meshes: std::collections::HashMap<crate::entity::RenderEntity, String>,
pub render_instanced_objects:
std::collections::HashMap<crate::entity::RenderEntity, InstancedObjectData>,
pub render_lights: RenderLights,
pub render_decals: Vec<RenderDecal>,
pub render_particle_emitters: Vec<RenderParticleEmitter>,
pub render_water: Vec<RenderWater>,
pub render_cloth: Vec<RenderCloth>,
pub render_selection_outline_ids: Vec<u32>,
pub render_bounds: std::collections::HashMap<crate::entity::RenderEntity, RenderBounds>,
pub render_shadow_casters: RenderShadowCasters,
pub render_skinned_meshes: Vec<crate::entity::RenderEntity>,
pub render_regular_mesh_entities: Vec<crate::entity::RenderEntity>,
pub culling_camera_view_projection: Option<nalgebra_glm::Mat4>,
pub render_skinning: RenderSkinning,
pub render_texts: Vec<RenderText>,
pub render_animation: SkinnedAnimationSnapshot,
#[cfg(feature = "wgpu")]
pub render_lighting: Option<RenderLighting>,
pub skinned_objects_generation: u64,
pub settings_version: u64,
pub focus_policy: ViewportFocusPolicy,
pub adaptive_sampling: AdaptiveSamplingState,
pub effects: EffectsState,
pub gpu_profile: Option<GpuProfile>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PerformanceTarget {
#[default]
Unbounded,
Interactive,
Balanced,
Quality,
}
impl PerformanceTarget {
pub fn target_frame_time_ms(self) -> Option<f32> {
match self {
PerformanceTarget::Unbounded => None,
PerformanceTarget::Interactive => Some(1000.0 / 60.0),
PerformanceTarget::Balanced => Some(1000.0 / 30.0),
PerformanceTarget::Quality => Some(1000.0 / 15.0),
}
}
}
#[derive(Debug, Clone)]
pub struct AdaptiveSamplingState {
pub target: PerformanceTarget,
pub frame_time_rolling_ms: f32,
pub frame_time_sample_count: u32,
pub ssao_sample_scale: f32,
pub ssgi_sample_scale: f32,
pub ssr_step_scale: f32,
}
impl Default for AdaptiveSamplingState {
fn default() -> Self {
Self {
target: PerformanceTarget::Unbounded,
frame_time_rolling_ms: 16.67,
frame_time_sample_count: 0,
ssao_sample_scale: 1.0,
ssgi_sample_scale: 1.0,
ssr_step_scale: 1.0,
}
}
}
impl AdaptiveSamplingState {
pub fn record_frame_time(&mut self, frame_time_ms: f32) {
const WINDOW: u32 = 100;
if self.frame_time_sample_count == 0 {
self.frame_time_rolling_ms = frame_time_ms;
self.frame_time_sample_count = 1;
} else {
let alpha = 1.0 / (self.frame_time_sample_count.min(WINDOW) as f32 + 1.0);
self.frame_time_rolling_ms =
self.frame_time_rolling_ms * (1.0 - alpha) + frame_time_ms * alpha;
self.frame_time_sample_count = (self.frame_time_sample_count + 1).min(WINDOW);
}
let Some(target_ms) = self.target.target_frame_time_ms() else {
self.ssao_sample_scale = 1.0;
self.ssgi_sample_scale = 1.0;
self.ssr_step_scale = 1.0;
return;
};
let error = self.frame_time_rolling_ms - target_ms;
let sensitivity = 0.002;
let max_delta = 0.05;
let adjustment = (error * sensitivity).clamp(-max_delta, max_delta);
self.ssao_sample_scale = (self.ssao_sample_scale - adjustment).clamp(0.25, 1.0);
self.ssgi_sample_scale = (self.ssgi_sample_scale - adjustment).clamp(0.25, 1.0);
self.ssr_step_scale = (self.ssr_step_scale - adjustment).clamp(0.25, 1.0);
}
}
pub fn render_settings_signature(
render: &RenderSettings,
debug: &DebugDraw,
selection: &EditorSelection,
) -> u64 {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
selection
.bounding_volume_selected_entity
.map(|entity| (entity.id, entity.generation))
.hash(&mut hasher);
for entity in &selection.selected_entities {
(entity.id, entity.generation).hash(&mut hasher);
}
debug.show_grid.hash(&mut hasher);
debug.show_bounding_volumes.hash(&mut hasher);
debug.show_normals.hash(&mut hasher);
debug.normal_line_length.to_bits().hash(&mut hasher);
for component in debug.normal_line_color {
component.to_bits().hash(&mut hasher);
}
(render.atmosphere as u32).hash(&mut hasher);
render.show_sky.hash(&mut hasher);
render.render_layer_world_enabled.hash(&mut hasher);
render.render_layer_overlay_enabled.hash(&mut hasher);
render.render_world_to_swapchain.hash(&mut hasher);
for component in render.clear_color {
component.to_bits().hash(&mut hasher);
}
render.unlit_mode.hash(&mut hasher);
debug.selection_outline_enabled.hash(&mut hasher);
for component in debug.selection_outline_color {
component.to_bits().hash(&mut hasher);
}
render.vertex_snap.is_some().hash(&mut hasher);
if let Some(ref snap) = render.vertex_snap {
for component in snap.resolution {
component.to_bits().hash(&mut hasher);
}
}
render.affine_texture_mapping.hash(&mut hasher);
render.fog.is_some().hash(&mut hasher);
if let Some(ref fog) = render.fog {
for component in fog.color {
component.to_bits().hash(&mut hasher);
}
fog.start.to_bits().hash(&mut hasher);
fog.end.to_bits().hash(&mut hasher);
}
let cg = &render.color_grading;
cg.exposure.to_bits().hash(&mut hasher);
cg.exposure_compensation_ev.to_bits().hash(&mut hasher);
cg.auto_exposure.hash(&mut hasher);
cg.auto_exposure_target.to_bits().hash(&mut hasher);
cg.auto_exposure_rate.to_bits().hash(&mut hasher);
cg.auto_exposure_min_ev.to_bits().hash(&mut hasher);
cg.auto_exposure_max_ev.to_bits().hash(&mut hasher);
cg.gamma.to_bits().hash(&mut hasher);
cg.saturation.to_bits().hash(&mut hasher);
cg.brightness.to_bits().hash(&mut hasher);
cg.contrast.to_bits().hash(&mut hasher);
(cg.tonemap_algorithm as u32).hash(&mut hasher);
render.bloom_enabled.hash(&mut hasher);
render.bloom_intensity.to_bits().hash(&mut hasher);
render.bloom_threshold.to_bits().hash(&mut hasher);
render.bloom_knee.to_bits().hash(&mut hasher);
render.bloom_filter_radius.to_bits().hash(&mut hasher);
let dof = &render.depth_of_field;
dof.enabled.hash(&mut hasher);
dof.focus_distance.to_bits().hash(&mut hasher);
dof.focus_range.to_bits().hash(&mut hasher);
dof.max_blur_radius.to_bits().hash(&mut hasher);
dof.bokeh_threshold.to_bits().hash(&mut hasher);
dof.bokeh_intensity.to_bits().hash(&mut hasher);
(dof.quality as u32).hash(&mut hasher);
dof.visualize_coc.hash(&mut hasher);
dof.tilt_shift_enabled.hash(&mut hasher);
dof.tilt_shift_angle.to_bits().hash(&mut hasher);
dof.tilt_shift_center.to_bits().hash(&mut hasher);
dof.tilt_shift_blur_amount.to_bits().hash(&mut hasher);
dof.visualize_tilt_shift.hash(&mut hasher);
render.ssao_enabled.hash(&mut hasher);
render.ssao_radius.to_bits().hash(&mut hasher);
render.ssao_bias.to_bits().hash(&mut hasher);
render.ssao_intensity.to_bits().hash(&mut hasher);
render.ssao_sample_count.hash(&mut hasher);
debug.ssao_visualization.hash(&mut hasher);
render.ssao_blur_depth_threshold.to_bits().hash(&mut hasher);
render.ssao_blur_normal_power.to_bits().hash(&mut hasher);
render.ssgi_enabled.hash(&mut hasher);
render.ssgi_radius.to_bits().hash(&mut hasher);
render.ssgi_intensity.to_bits().hash(&mut hasher);
render.ssgi_max_steps.hash(&mut hasher);
render.ssr_enabled.hash(&mut hasher);
render.ssr_max_steps.hash(&mut hasher);
render.ssr_thickness.to_bits().hash(&mut hasher);
render.ssr_max_distance.to_bits().hash(&mut hasher);
render.ssr_stride.to_bits().hash(&mut hasher);
render.ssr_fade_start.to_bits().hash(&mut hasher);
render.ssr_fade_end.to_bits().hash(&mut hasher);
render.ssr_intensity.to_bits().hash(&mut hasher);
for component in render.ambient_light {
component.to_bits().hash(&mut hasher);
}
debug.pbr_debug_mode.as_u32().hash(&mut hasher);
debug.texture_debug_stripes.hash(&mut hasher);
debug
.texture_debug_stripes_speed
.to_bits()
.hash(&mut hasher);
render.taa_enabled.hash(&mut hasher);
render.render_scale.to_bits().hash(&mut hasher);
render.ibl_blend_factor.to_bits().hash(&mut hasher);
hasher.finish()
}
impl Default for RenderSettings {
fn default() -> Self {
Self {
frame_rate_limit: None,
atmosphere: Atmosphere::None,
show_sky: true,
render_layer_world_enabled: true,
render_layer_overlay_enabled: true,
render_world_to_swapchain: true,
clear_color: [0.0, 0.0, 0.0, 1.0],
ui_scale: None,
unlit_mode: false,
vertex_snap: None,
affine_texture_mapping: false,
material_anisotropy_filtering: 16,
fog: None,
color_grading: ColorGrading::default(),
bloom_enabled: true,
bloom_intensity: 0.04,
bloom_threshold: 1.0,
bloom_knee: 0.5,
bloom_filter_radius: 0.005,
depth_of_field: DepthOfField::default(),
ssao_enabled: false,
ssao_radius: 0.5,
ssao_bias: 0.025,
ssao_intensity: 1.0,
ssao_sample_count: 64,
ssao_blur_depth_threshold: 0.005,
ssao_blur_normal_power: 8.0,
ssgi_enabled: false,
ssgi_radius: 2.0,
ssgi_intensity: 1.0,
ssgi_max_steps: 16,
ssr_enabled: false,
ssr_max_steps: 64,
ssr_thickness: 0.3,
ssr_max_distance: 50.0,
ssr_stride: 1.0,
ssr_fade_start: 0.8,
ssr_fade_end: 1.0,
ssr_intensity: 1.0,
ambient_light: [0.1, 0.1, 0.1, 1.0],
taa_enabled: false,
taa_blend: 0.12,
taa_sharpness: 0.5,
water_enabled: true,
vsync_enabled: true,
render_scale: 1.0,
ibl_blend_factor: 0.0,
}
}
}
impl Default for DebugDraw {
fn default() -> Self {
Self {
show_grid: false,
show_bounding_volumes: false,
show_selected_bounding_volume: false,
show_normals: false,
normal_line_length: 0.1,
normal_line_color: [0.0, 1.0, 0.0, 1.0],
selection_outline_enabled: false,
selection_outline_color: [1.0, 0.45, 0.0, 1.0],
pbr_debug_mode: PbrDebugMode::None,
texture_debug_stripes: false,
texture_debug_stripes_speed: 100.0,
ssao_visualization: false,
}
}
}
impl Default for RendererState {
fn default() -> Self {
Self {
auto_frame_rate_limit_baseline: None,
taa_jitter: [0.0, 0.0],
view_projection: nalgebra_glm::Mat4::identity().into(),
prev_view_projection: nalgebra_glm::Mat4::identity().into(),
gpu_culling_enabled: true,
occlusion_culling_enabled: true,
gpu_batching_enabled: true,
min_screen_pixel_size: 0.0,
min_window_size: None,
use_fullscreen: false,
show_cursor: true,
letterbox_amount: 0.0,
letterbox_target: 0.0,
day_night: DayNightState::default(),
mesh_lod_chains: Vec::new(),
active_view: EffectiveShading::default(),
render_view: None,
render_dynamic_objects: std::collections::HashMap::new(),
render_materials: RenderMaterials::default(),
render_object_meshes: std::collections::HashMap::new(),
render_instanced_objects: std::collections::HashMap::new(),
render_lights: RenderLights::default(),
render_decals: Vec::new(),
render_particle_emitters: Vec::new(),
render_water: Vec::new(),
render_cloth: Vec::new(),
render_selection_outline_ids: Vec::new(),
render_bounds: std::collections::HashMap::new(),
render_shadow_casters: RenderShadowCasters::default(),
render_skinned_meshes: Vec::new(),
render_regular_mesh_entities: Vec::new(),
culling_camera_view_projection: None,
render_skinning: RenderSkinning::default(),
render_texts: Vec::new(),
render_animation: SkinnedAnimationSnapshot::default(),
#[cfg(feature = "wgpu")]
render_lighting: None,
skinned_objects_generation: 0,
settings_version: 0,
focus_policy: ViewportFocusPolicy::default(),
adaptive_sampling: AdaptiveSamplingState::default(),
effects: EffectsState::default(),
gpu_profile: None,
}
}
}
pub const FLAT_SHADING_COLOR: nalgebra_glm::Vec4 = nalgebra_glm::Vec4::new(0.72, 0.72, 0.72, 1.0);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum ViewportUpdateMode {
#[default]
Always,
WhenVisible,
WhenDirty,
Once,
Disabled,
}
pub const WIREFRAME_SENTINEL_COLOR: nalgebra_glm::Vec4 =
nalgebra_glm::Vec4::new(0.0, 0.0, 0.0, 2.0);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct EffectiveShading {
pub unlit_mode: bool,
pub bloom_enabled: bool,
pub ssao_enabled: bool,
pub ssgi_enabled: bool,
pub ssr_enabled: bool,
pub show_normals: bool,
pub show_bounding_volumes: bool,
pub show_wireframe: bool,
pub selection_outline_enabled: bool,
pub flat_shading_color: Option<nalgebra_glm::Vec4>,
pub shadow_depth_enabled: bool,
pub lines_enabled: bool,
pub color_grading: ColorGrading,
pub depth_of_field: DepthOfField,
pub bloom_intensity: f32,
pub bloom_threshold: f32,
pub bloom_knee: f32,
pub bloom_filter_radius: f32,
pub ssao_radius: f32,
pub ssao_bias: f32,
pub ssao_intensity: f32,
pub ssao_sample_count: u32,
pub ssao_visualization: bool,
pub ssao_blur_depth_threshold: f32,
pub ssao_blur_normal_power: f32,
pub ssgi_radius: f32,
pub ssgi_intensity: f32,
pub ssgi_max_steps: u32,
pub ssr_max_steps: u32,
pub ssr_thickness: f32,
pub ssr_max_distance: f32,
pub ssr_stride: f32,
pub ssr_fade_start: f32,
pub ssr_fade_end: f32,
pub ssr_intensity: f32,
pub ambient_light: [f32; 4],
pub culling_mask: u32,
pub fog: Option<Fog>,
pub atmosphere: Atmosphere,
}
impl Default for EffectiveShading {
fn default() -> Self {
Self {
unlit_mode: false,
bloom_enabled: true,
ssao_enabled: false,
ssgi_enabled: false,
ssr_enabled: false,
show_normals: false,
show_bounding_volumes: false,
show_wireframe: false,
selection_outline_enabled: false,
flat_shading_color: None,
shadow_depth_enabled: true,
lines_enabled: false,
color_grading: ColorGrading::default(),
depth_of_field: DepthOfField::default(),
bloom_intensity: 0.5,
bloom_threshold: 1.0,
bloom_knee: 0.5,
bloom_filter_radius: 0.005,
ssao_radius: 0.5,
ssao_bias: 0.025,
ssao_intensity: 1.0,
ssao_sample_count: 64,
ssao_visualization: false,
ssao_blur_depth_threshold: 0.005,
ssao_blur_normal_power: 8.0,
ssgi_radius: 2.0,
ssgi_intensity: 1.0,
ssgi_max_steps: 16,
ssr_max_steps: 64,
ssr_thickness: 0.3,
ssr_max_distance: 50.0,
ssr_stride: 1.0,
ssr_fade_start: 0.8,
ssr_fade_end: 1.0,
ssr_intensity: 1.0,
ambient_light: [0.1, 0.1, 0.1, 1.0],
culling_mask: !0,
fog: None,
atmosphere: Atmosphere::None,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ViewportRect {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl ViewportRect {
pub fn contains(&self, screen_pos: nalgebra_glm::Vec2) -> bool {
screen_pos.x >= self.x
&& screen_pos.x <= self.x + self.width
&& screen_pos.y >= self.y
&& screen_pos.y <= self.y + self.height
}
pub fn to_local(&self, screen_pos: nalgebra_glm::Vec2) -> nalgebra_glm::Vec2 {
nalgebra_glm::Vec2::new(screen_pos.x - self.x, screen_pos.y - self.y)
}
}