use mirage_engine::prelude::*;
const GROUND_SIZE: f32 = 10.0;
const GLOW_POSITION: Vec3 = Vec3::new(0.0, 0.6, 0.0);
const GLOW_SIZE: f32 = 0.9;
const GLOW_COLOR: Color = Color::rgb(4.0, 2.2, 0.6);
const SPHERE_POSITIONS: [Vec3; 2] = [Vec3::new(-1.6, 0.5, 0.4), Vec3::new(1.6, 0.5, -0.4)];
const SPHERE_SUBDIVISIONS: u32 = 3;
const SUN_DIRECTION: Vec3 = Vec3::new(0.5, -1.0, -0.3);
const SUN_COLOR: Color = Color::rgb(0.85, 0.8, 0.7);
const GROUND_COLOR: Color = Color::rgb(0.16, 0.17, 0.15);
const SPHERE_COLOR: Color = Color::rgb(0.5, 0.52, 0.55);
const SCENE_BLOOM: f32 = 0.5;
meshes! { enum Shape { Plane, Cube, Sphere } }
#[derive(ShaderValues)]
struct Vignette {
strength: f32,
}
impl PostEffect for Vignette {
const STAGE: EffectStage = EffectStage::ToneMapped;
const SHADER: &'static str = include_str!("post_effects_vignette.wgsl");
}
#[derive(ShaderValues)]
struct Grain {
strength: f32,
seed: u32,
}
impl PostEffect for Grain {
const STAGE: EffectStage = EffectStage::ToneMapped;
const SHADER: &'static str = include_str!("post_effects_grain.wgsl");
}
#[derive(ShaderValues)]
struct Scanlines {
strength: f32,
}
impl PostEffect for Scanlines {
const STAGE: EffectStage = EffectStage::ToneMapped;
const SHADER: &'static str = include_str!("post_effects_scanlines.wgsl");
}
post_effects! { enum Look { Vignette, Grain, Scanlines } }
struct PostEffectEffects {
ticks: u32,
vignette: f32,
grain: f32,
scanlines: f32,
}
impl PostEffectEffects {
fn init(_ctx: &mut InitContext<'_, Self>) -> Result<Self, Error> {
Ok(Self {
ticks: 0,
vignette: 0.5,
grain: 0.08,
scanlines: 0.3,
})
}
fn draw_scene(&self, ctx: &mut FrameContext<'_, Self>) {
ctx.light(Light::directional(SUN_DIRECTION, SUN_COLOR).shadow());
ctx.draw(
Plane
.at(Transform::from_scale(Vec3::new(
GROUND_SIZE,
1.0,
GROUND_SIZE,
)))
.material(Material::lit(GROUND_COLOR)),
);
ctx.draw(
Cube.at(Transform::from_scale_rotation_translation(
Vec3::splat(GLOW_SIZE),
Quat::IDENTITY,
GLOW_POSITION,
))
.material(Material::color(Color::BLACK).emissive(GLOW_COLOR)),
);
for position in SPHERE_POSITIONS {
ctx.draw(
Sphere {
subdivisions: SPHERE_SUBDIVISIONS,
}
.at(position)
.material(Material::lit(SPHERE_COLOR)),
);
}
}
fn panel(&mut self, ctx: &mut FrameContext<'_, Self>) {
ctx.ui(|ui| {
ui.add(egui::Slider::new(&mut self.vignette, 0.0..=1.0).text("vignette"));
ui.add(egui::Slider::new(&mut self.grain, 0.0..=1.0).text("grain"));
ui.add(egui::Slider::new(&mut self.scanlines, 0.0..=1.0).text("scanlines"));
});
ctx.set_post_effect(Vignette {
strength: self.vignette,
});
ctx.set_post_effect(Grain {
strength: self.grain,
seed: self.ticks,
});
ctx.set_post_effect(Scanlines {
strength: self.scanlines,
});
}
}
impl Game for PostEffectEffects {
type Meshes = Shape;
type Sounds = NoSounds;
type InputActions = Key;
type Skyboxes = NoSkyboxes;
type SurfaceStyles = ();
type PostEffects = Look;
fn tick(&mut self, _ctx: &mut TickContext<'_, Self>) {
self.ticks += 1;
}
fn frame(&mut self, ctx: &mut FrameContext<'_, Self>) {
ctx.set_camera(Camera::new(
View::look_at(Vec3::new(0.0, 3.4, 4.6), Vec3::new(0.0, 0.2, 0.0)),
Projection::perspective(45.0),
));
ctx.set_bloom(SCENE_BLOOM);
self.draw_scene(ctx);
self.panel(ctx);
}
}
fn main() {
run(
Config::new("Mirage: screen effects").with_size(1280, 720),
PostEffectEffects::init,
);
}