3GAL4KPRWFKBWY2AT4YE53JHQGT6H46UEKUPIT4CHKZY3NSVLHZAC
QTBM4XITUDUC3645V26MOLQZLTXGAI5KRHHMRKKPBUYKTF66OQIQC
OM6475B3O4T22Z22CPMOW4AN54JWQ34HXPMIV26MLRXRIKKBSTAAC
L6RIUKGLJZLAOKFGUDTZKBPP4HUBPEZAKHJEQHO34WFF62AB2ZIQC
X5EMQBC4BFNJOOHS2QMF4UB4QH6JKSALK6RXLK6B7SP6MNYSAP6QC
GROTV3H2V6BHU5CA7WSLVYDCWAR7GHUP5JV2QOGPLJ6N3553T4MAC
LJD76LBNKTWSAHLRGL7EXNMM5HYRSOD6VXWYQSX2XVK7TQROTZ6QC
GHIHJCWBCGFZI4AG66L7WG4WKJ467DXFBRBNLT4ZULSN7ZVBJI6AC
EEO6C4YSWFW3JOZ3JH6K7X4TKAUTVJD53CQNYZHI2QY6REGEXUCAC
7CBRRVV3GLVLBHNPQNRHSA2ZCLHIMCHFEMWMZNOICY2OZLB7DGPAC
KMU4E426CB2NDRJEK7B4GSL22P62CJPPZRK45X3JV5WP5NIBIGRQC
MT6IBX7SGLE26XIFZY53WYNHSJZMSDVDRJP3VYPXIQ4DKY75XVXAC
BTZ5WJPNRJ4Y3JB77XZXQWDZV2SJ4WBMSYPITUYOWSR4GLRHU4GAC
OGNLZ5CUNFD7X43S4VTMCCEMJA2R76O35XACIR7AUBHPGME27E3AC
O5P6HCPWGMGJBFJEMC3SYQJ5OEW2AQV4KEJCMRVTTS3K6M45Z3BAC
SSJKQR6X6L2KUJI2YPLMBQU3PTR2RYAQQR6N35MDMOCOTV6ZDUEAC
6YVIIRYC6FQP7ET7AMJHG4XCIDI4KIJMOKUDAUMVBLYFEULRDQEAC
42S2A7MCAEX5QBEWP72MK3HBY3FCANOPVHLUPWK4FIZZ3NMIOQ4AC
Q6Z5IQJ3SUI7BUJCKT377EPIRO7UVZFI7UB74ZEEGTCTUKC7WGKQC
WQIQA2TNWNSNGKQC22XPTECAZEWG6PG5QWQECUVXDUQRSCV6RUZQC
PAOLWMH7TLJLNAWBJBWP7KB7YGDFUPASMTFU33KZ3QW5JXJMPXCAC
DKGUNP6LG3DJ35VMHU42K3VJO5JJ5UVYI4PLM72HO5ZNAQ4P366AC
KID2E3YKLHUFPHWYYGRQZTX73THWMAXQWPT5XZEJJO46BCQD27HQC
N7AJTLSWYZDDPB3JDCRGZVLGX7GCUMHYQB4OAKNETMDHENAZAJCQC
7B5SB3V7YC4HKFX6PIX6IHJ4U3BKYLD5EBMEY6O5FQ7YGN4VVI4AC
ER6ZNH7MRH3CT66LQR72NYUXOTC2NDKHHDV72VBUHSJGE2VNUXCAC
AGYP6KTCCMVHH2CJ3XA6NYNTTX22MJKGZJ4FTFNET35CEZIKV5MAC
DZPGVVKGX6QS4HX5GVF3DR3UZAV2EOMMVRUDEGTR2OPJVDG3FNXQC
HTDZ53HWD4X3DSFZX7MMC7DPFJNHQPGBVLJD2S325SQRRVIQ3CLAC
DOR7S6M2PZ5FQ7TFGWIK7FUFUZENXKU4G42I5HQITODPBBEJB4YQC
L5SVCVPJMJPDARA4H43U5INQMAKHUIB5PUP55IDRKAPQDB35MXZQC
34CROJEM52NB7TGBCGGMIYAQ2AZUI44FWO25MGYYUSCMHLCLJNAQC
BYFMGWJ5ZPXZTCIFDHP66KK7JTEKT2NO7HR2XY7T5WRAAG3L5WYQC
ELBXLSZ3LKHEXX7T7FU2EE6UTZI2QXUTV4ZM66PGSKVLHSHXQVWAC
ERVDDYMSDOMRHCJYLXDFGE34YV26TKAWL6NFA2ELPUW6ECN5AOBQC
use crate::{
screen::{Camera, RenderError, RenderInput, RenderOptions, Screen},
text::{TextSystem, TextSystemData},
};
use winit::{
event::{ElementState, KeyEvent, WindowEvent},
keyboard::{Key, NamedKey},
window::Window,
};
screen: Screen,
}
let mut camera = Camera::default();
let mut render_options = RenderOptions::default();
// The *only* time we need to manually do this, all others should use extract_view!
let mut view = GameView {
camera: &mut camera,
render_options: &mut render_options,
// executor: &mut executor,
};
initial_scene.on_enter(&mut view);
let egui = egui::Context::default();
let egui_winit =
egui_winit::State::new(egui.clone(), egui::ViewportId::ROOT, &window, None, None);
let screen = Screen::new(window).await?;
Ok(Self {
egui,
egui_winit,
screen,
scene_library,
current_scene: initial_scene,
// systems
show_debug: false,
internal_state: GameState {
camera,
render_options,
},
text: TextSystem::new()?,
})
}
}
pub fn screen(&self) -> &Screen {
&self.screen
}
pub fn screen_mut(&mut self) -> &mut Screen {
&mut self.screen
}
/// Runs egui code
egui_winit::update_viewport_info(
self.egui_winit
.egui_input_mut()
.viewports
.get_mut(&egui::ViewportId::ROOT)
.unwrap(),
&self.egui,
self.screen.window(),
);
let input = self.egui_winit.take_egui_input(self.screen.window());
let full_output = self.egui.run(input, |ctx| {
egui::Window::new("Debug Tools")
.open(&mut self.show_debug)
.show(ctx, |ui| {
ui.horizontal(|ui| {
let mut vsync = self.screen.is_vsync();
let text = if vsync { "yes" } else { "no" };
ui.label("VSync");
ui.toggle_value(&mut vsync, text);
self.screen.vsync(vsync);
});
ui.add(
egui::Slider::new(&mut self.internal_state.render_options.gamma, 0.0..=2.0)
.text("Gamma"),
);
});
let mut view = extract_view!(self);
self.current_scene.gui_egui(ctx, &mut view)
});
let prims = self
.egui
.tessellate(full_output.shapes.clone(), full_output.pixels_per_point);
(full_output, prims)
}
/// Returns true if the event was handled
#[cfg(debug_assertions)]
if matches!(
event,
WindowEvent::KeyboardInput {
event: KeyEvent {
logical_key: Key::Named(NamedKey::F1),
state: ElementState::Pressed,
repeat: false,
..
},
..
}
) {
self.show_debug = !self.show_debug;
return true;
}
if self
.egui_winit
.on_window_event(self.screen.window(), event)
.consumed
{
return true;
}
self.current_scene.input(event, &mut view)
}
puffin::profile_function!();
// Run any in-progress tasks from the async executor
// self.executor.run_until_stall(&mut self.internal_state);
if let Some(reference) = self.current_scene.update(dt, &mut view) {
let new_scene = self.scene_library.get_scene(&mut view, reference);
self.current_scene.on_exit(&mut view);
self.current_scene = new_scene;
self.current_scene.on_enter(&mut view);
}
}
puffin::profile_function!();
// Any resources only used for the rendering process go here
let camera_text_data = camera_text_data_info
.iter()
.map(|(buf, mapper)| mapper.produce(buf))
.collect();
let world_text_data = world_text_data_info
.iter()
.map(|(buf, mapper)| mapper.produce(buf))
.collect();
// Build the renderer input
let input = RenderInput {
paint_jobs: &paint_jobs,
textures_delta: &egui_output.textures_delta,
font_system: &mut self.text.fonts,
swash_cache: &mut self.text.swash,
camera_text_data,
world_text_data,
};
self.screen.render(input)
}
}
// methods here might query the world to produce
// rendering data ready for Screen to use
camera: &mut self.internal_state.camera,
render_options: &self.internal_state.render_options,
let world_text_data_info: Vec<_> =
self.text.produce_world(&text_data).into_iter().collect();
let camera_text_data_info: Vec<_> =
self.text.produce_camera(&text_data).into_iter().collect();
self.text.prepare(&text_data);
let (egui_output, paint_jobs) = self.gui_egui();
let text_data = TextSystemData::extract();
pub fn render(&mut self) -> Result<(), RenderError> {
let mut view = extract_view!(self);
pub fn update(&mut self, dt: std::time::Duration) {
let mut view = extract_view!(self);
pub fn input(&mut self, event: &WindowEvent) -> bool {
self.egui_winit
.handle_platform_output(self.screen.window(), full_output.platform_output.clone());
pub fn gui_egui(&mut self) -> (egui::FullOutput, Vec<egui::ClippedPrimitive>) {
pub async fn create_surface(&mut self) -> color_eyre::Result<()> {
self.screen.create_surface().await
let mut initial_scene = scene_library.get_scene(&mut view, ModeReference::Init);
impl Game {
pub async fn new(window: Window) -> color_eyre::Result<Self> {
let scene_library = ModeLibrary;
egui: egui::Context,
egui_winit: egui_winit::State,
internal_state: GameState,
// executor: Cosync<GameState<S>>,
// systems
text: TextSystem,
// internal controls
show_debug: bool,
}
pub struct GameState {
pub camera: Camera,
pub render_options: RenderOptions,
}
pub camera: &'a mut Camera,
pub render_options: &'a mut RenderOptions,
}
macro_rules! extract_view {
GameView {
camera: &mut $game.internal_state.camera,
render_options: &mut $game.internal_state.render_options,
// executor: &mut $game.executor,
}
};
($game: expr) => {
// pub executor: &'a mut Cosync<GameState<S>>,
pub struct GameView<'a> {
scene_library: ModeLibrary,
current_scene: Box<dyn Mode + Send>,
pub struct Game {
use self::mode::{Mode, ModeLibrary, ModeReference};
mod mode;
fn meets_thresh(color: vec4<f32>) -> bool {
// stack overflow magic \sqrt{0.299\cdot r^{2}+0.587\cdot g^{2}+0.114\cdot b^{2}}
let brightness = sqrt(dot(color.rgb * color.rgb, vec3<f32>(0.299, 0.587, 0.114)));
return brightness > 0.1;
}
const PI = 3.14159265359;
const STD_DEV: f32 = 50.0;
let strength = 3.0;
var added: vec4<f32>;
// let offset = vec2<f32>(textureOffset.x, textureOffset.y);
// Turns out this might be a cool astigmatism shader, gotta remember that
let offset_y = vec2<f32>(0.0, textureOffset.y);
let offset_x = vec2<f32>(textureOffset.x, 0.0);
for(var i: u32 = 0; i < 9; i++) {
let new_color_a = textureSample(t_world, s_world, t_tex_coords + offset_x * f32(i));
let new_color_b = textureSample(t_world, s_world, t_tex_coords - offset_x * f32(i));
if (meets_thresh(new_color_a)) {
// result += vec4<f32>(new_color_a.rgb * weight[i], 0);
added += vec4<f32>(new_color_a.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
if (meets_thresh(new_color_b)) {
// result += vec4<f32>(new_color_b.rgb * weight[i], 0);
added += vec4<f32>(new_color_b.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
let new_color_c = textureSample(t_world, s_world, t_tex_coords + offset_y * f32(i));
let new_color_d = textureSample(t_world, s_world, t_tex_coords - offset_y * f32(i));
if (meets_thresh(new_color_c)) {
// result += vec4<f32>(new_color_a.rgb * weight[i], 0);
added += vec4<f32>(new_color_c.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
if (meets_thresh(new_color_d)) {
// result += vec4<f32>(new_color_b.rgb * weight[i], 0);
added += vec4<f32>(new_color_d.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
let new_color_e = textureSample(t_world, s_world, t_tex_coords + offset_x * f32(i) + offset_y * f32(i));
let new_color_f = textureSample(t_world, s_world, t_tex_coords + offset_x * f32(i) - offset_y * f32(i));
if (meets_thresh(new_color_e)) {
// result += vec4<f32>(new_color_a.rgb * weight[i], 0);
added += vec4<f32>(new_color_e.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
if (meets_thresh(new_color_f)) {
// result += vec4<f32>(new_color_b.rgb * weight[i], 0);
added += vec4<f32>(new_color_f.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
let new_color_g = textureSample(t_world, s_world, t_tex_coords + offset_x * f32(i) + offset_y * f32(i));
let new_color_h = textureSample(t_world, s_world, t_tex_coords - offset_x * f32(i) + offset_y * f32(i));
if (meets_thresh(new_color_g)) {
// result += vec4<f32>(new_color_a.rgb * weight[i], 0);
added += vec4<f32>(new_color_g.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
if (meets_thresh(new_color_h)) {
// result += vec4<f32>(new_color_b.rgb * weight[i], 0);
added += vec4<f32>(new_color_h.rgb, 1.0 / strength) * weight_calc(i) * strength;
}
}
// We do it this weird way, cuz the world texture is *not* HDR atm
let hdr = result + added;
let sdr = hdr::aces_tone_map(hdr.rgb);
// Map gamma while, we're at it
result = vec4<f32>(pow(sdr, vec3<f32>(render_options.gamma)), hdr.a);
// return in.color;
// return in.color * textureSample(t_world, s_world, in.tex_coords);
glyphon_to_world: (glam::Affine3A::from_translation(glam::Vec3::new(
-(WORLD_HALF_EXTENTS.x as f32),
-(WORLD_HALF_EXTENTS.y as f32),
0.0,
)) * glam::Affine3A::from_scale(glam::Vec3::new(
2.0 * WORLD_HALF_EXTENTS.x as f32,
2.0 * WORLD_HALF_EXTENTS.y as f32,
1.0,
)))
.inverse(),
let attrs = Attrs::new().family(glyphon::Family::Name("Poiret One"));
let srgb_red: palette::Srgb<u8> = palette::named::WHITE.into_format();
let (r, g, b) = srgb_red.into_components();
let color = glyphon::Color::rgb(r, g, b);
let attrs = Attrs::new()
.family(glyphon::Family::Name("Poiret One"))
.color(color);
-1.0 * WORLD_HALF_EXTENTS.x as f32,
1.0 * WORLD_HALF_EXTENTS.x as f32,
-1.0 * WORLD_HALF_EXTENTS.y as f32,
1.0 * WORLD_HALF_EXTENTS.y as f32,
-0.5 * self.world_width as f32,
0.5 * self.world_width as f32,
-0.5 * self.world_height as f32,
0.5 * self.world_height as f32,