Skip to content

Commit

Permalink
Added app config file
Browse files Browse the repository at this point in the history
- Config file can change window size, resizable, fullscreen, vsync, window scale and texture size
- Embedded shader files in executable. This means the simulation can be shipped as just a single executable
  • Loading branch information
caelwarner committed Apr 7, 2023
1 parent 5f07b4f commit c3e3ccf
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 105 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ edition = "2021"

[dependencies]
bevy = "0.8.1"
bytemuck = "1.12.2"
bevy_embedded_assets = "0.4.0"
bevy-inspector-egui = "0.13.0"
bevy-inspector-egui-derive = "0.13.0"
bytemuck = "1.12.2"
rand = "0.8.5"
serde = { version = "1.0.159", features = ["derive"] }
toml = "0.7.3"
5 changes: 1 addition & 4 deletions assets/shaders/simulation.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ struct Context {
senseDistance: f32,
turnSpeed: f32,
turnRandomness: f32,
r: f32,
g: f32,
b: f32,
}

struct Agent {
Expand Down Expand Up @@ -99,7 +96,7 @@ fn update(@builtin(global_invocation_id) id: vec3<u32>) {
agents[id.x].position = newPosition;

let location = vec2<i32>(agents[id.x].position);
let color = vec4<f32>(context.r, context.g, context.b, 1.0);
let color = vec4<f32>(1.0, 1.0, 1.0, 1.0);

storageBarrier();
textureStore(textureOut, location, color);
Expand Down
11 changes: 11 additions & 0 deletions slime_simulation_config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[window]
width = 1280
height = 720
fullscreen = false
resizable = false
vsync = true
override_scale_factor = false

[texture]
width = 2560
height = 1440
107 changes: 87 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
extern crate core;
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::fs;

use bevy::asset::AssetPlugin;
use bevy::DefaultPlugins;
use bevy::prelude::*;
use bevy::window::WindowMode;
use bevy::window::{PresentMode, WindowMode, WindowResized};
use bevy_embedded_assets::EmbeddedAssetPlugin;
use serde::{Deserialize, Serialize};

use crate::pipeline::PipelineImages;
use crate::plugin::SlimeSimulationPlugin;

mod plugin;
mod pipeline;

const SETTINGS: AppSettings = AppSettings {
window_size: (2560, 1440),
texture_size: (2560, 1440),
};
const CONFIG_FILE_NAME: &str = "slime_simulation_config.toml";

fn main() {
let config: AppConfig = match fs::read_to_string(CONFIG_FILE_NAME) {
Ok(contents) => {
toml::from_str(contents.as_str()).unwrap()
},
Err(..) => {
fs::write(CONFIG_FILE_NAME, toml::to_string(&AppConfig::default()).unwrap()).unwrap();
AppConfig::default()
},
};

App::new()
.insert_resource(ClearColor(Color::BLACK))
.insert_resource(WindowDescriptor {
title: "Slime Simulation".to_string(),
width: SETTINGS.window_size.0 as f32,
height: SETTINGS.window_size.1 as f32,
mode: WindowMode::Windowed,
scale_factor_override: Some(1.0),
title: String::from("Slime Simulation"),
width: config.window.width as f32,
height: config.window.height as f32,
resizable: config.window.resizable,
mode: if config.window.fullscreen { WindowMode::Fullscreen } else { WindowMode::Windowed },
present_mode: if config.window.vsync { PresentMode::AutoVsync } else { PresentMode::AutoNoVsync },
scale_factor_override: if config.window.override_scale_factor { Some(1.0) } else { None },
..default()
})
.add_plugins(DefaultPlugins)
.insert_resource(config)
.add_plugins_with(DefaultPlugins, |group| group.add_before::<AssetPlugin, _>(EmbeddedAssetPlugin))
.add_plugin(SlimeSimulationPlugin)
.add_startup_system_to_stage(
StartupStage::PostStartup,
setup
setup,
)
.add_system(on_window_resize)
.run();
}

fn setup(mut commands: Commands, images: Res<PipelineImages>) {
fn setup(mut commands: Commands, images: Res<PipelineImages>, config: Res<AppConfig>) {
commands.spawn_bundle(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(
SETTINGS.window_size.0 as f32,
SETTINGS.window_size.1 as f32,
config.window.width as f32,
config.window.height as f32,
)),
..default()
},
Expand All @@ -51,8 +67,59 @@ fn setup(mut commands: Commands, images: Res<PipelineImages>) {
commands.spawn_bundle(Camera2dBundle::default());
}

#[derive(Copy, Clone)]
struct AppSettings {
window_size: (u32, u32),
texture_size: (u32, u32),
fn on_window_resize(
mut resize_events: EventReader<WindowResized>,
mut query: Query<&mut Sprite>,
) {
for event in resize_events.iter() {
let mut sprite = query.single_mut();
sprite.custom_size = Some(Vec2::new(
event.width,
event.height,
));
}
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct AppConfig {
window: WindowConfig,
texture: TextureConfig,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct WindowConfig {
width: u32,
height: u32,
fullscreen: bool,
resizable: bool,
vsync: bool,
override_scale_factor: bool,
}

impl Default for WindowConfig {
fn default() -> Self {
Self {
width: 1280,
height: 720,
fullscreen: false,
resizable: false,
vsync: true,
override_scale_factor: false,
}
}
}

#[derive(Clone, Serialize, Deserialize)]
pub struct TextureConfig {
width: u32,
height: u32,
}

impl Default for TextureConfig {
fn default() -> Self {
Self {
width: 2560,
height: 1440,
}
}
}
22 changes: 7 additions & 15 deletions src/pipeline/blur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use bevy::render::render_asset::RenderAssets;
use bevy::render::render_resource::*;
use bevy::render::renderer::{RenderDevice, RenderQueue};

use crate::pipeline::{get_compute_pipeline_id, PipelineData, SubShaderPipeline, WorkgroupSize};
use crate::plugin::{PluginSettings, PluginTime};
use crate::SETTINGS;
use crate::AppConfig;
use crate::pipeline::{get_compute_pipeline_id, PipelineData, SubShaderPipeline};
use crate::plugin::{PluginTime, SimulationSettings};

pub struct BlurShaderPipeline {
bind_group_layout: BindGroupLayout,
Expand Down Expand Up @@ -39,7 +39,7 @@ impl BlurShaderPipeline {
}

impl SubShaderPipeline for BlurShaderPipeline {
fn init_data(&mut self, render_device: &RenderDevice, _settings: &PluginSettings) {
fn init_data(&mut self, render_device: &RenderDevice, _app_config: &AppConfig, _settings: &SimulationSettings) {
self.context.buffer = Some(render_device
.create_buffer(
&BufferDescriptor {
Expand All @@ -52,11 +52,11 @@ impl SubShaderPipeline for BlurShaderPipeline {
);
}

fn prepare_data(&mut self, render_queue: &RenderQueue, settings: &PluginSettings, _time: &PluginTime) {
fn prepare_data(&mut self, render_queue: &RenderQueue, app_config: &AppConfig, settings: &SimulationSettings, _time: &PluginTime) {
self.context.data = Some(BlurPipelineContext {
pause: if settings.pause { 1 } else { 0 },
width: SETTINGS.texture_size.0,
height: SETTINGS.texture_size.1,
width: app_config.texture.width,
height: app_config.texture.height,
blur_radius: settings.blur_radius,
});

Expand Down Expand Up @@ -113,14 +113,6 @@ impl SubShaderPipeline for BlurShaderPipeline {
fn get_bind_group(&self) -> Option<&BindGroup> {
self.bind_group.as_ref()
}

fn get_workgroup_size(&self, _settings: &PluginSettings) -> WorkgroupSize {
WorkgroupSize {
x: SETTINGS.texture_size.0 / 8,
y: SETTINGS.texture_size.1 / 8,
z: 1,
}
}
}

fn get_bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout {
Expand Down
18 changes: 5 additions & 13 deletions src/pipeline/fade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use bevy::render::render_asset::RenderAssets;
use bevy::render::render_resource::*;
use bevy::render::renderer::{RenderDevice, RenderQueue};

use crate::pipeline::{get_compute_pipeline_id, PipelineData, SubShaderPipeline, WorkgroupSize};
use crate::plugin::{PluginSettings, PluginTime};
use crate::SETTINGS;
use crate::AppConfig;
use crate::pipeline::{get_compute_pipeline_id, PipelineData, SubShaderPipeline};
use crate::plugin::{PluginTime, SimulationSettings};

pub struct FadeShaderPipeline {
bind_group_layout: BindGroupLayout,
Expand Down Expand Up @@ -39,7 +39,7 @@ impl FadeShaderPipeline {
}

impl SubShaderPipeline for FadeShaderPipeline {
fn init_data(&mut self, render_device: &RenderDevice, _settings: &PluginSettings) {
fn init_data(&mut self, render_device: &RenderDevice, _app_config: &AppConfig, _settings: &SimulationSettings) {
self.context.buffer = Some(render_device
.create_buffer(
&BufferDescriptor {
Expand All @@ -52,7 +52,7 @@ impl SubShaderPipeline for FadeShaderPipeline {
);
}

fn prepare_data(&mut self, render_queue: &RenderQueue, settings: &PluginSettings, time: &PluginTime) {
fn prepare_data(&mut self, render_queue: &RenderQueue, _app_config: &AppConfig, settings: &SimulationSettings, time: &PluginTime) {
self.context.data = Some(FadePipelineContext {
pause: if settings.pause { 1 } else { 0 },
fade_rate: settings.fade_rate,
Expand Down Expand Up @@ -107,14 +107,6 @@ impl SubShaderPipeline for FadeShaderPipeline {
fn get_bind_group(&self) -> Option<&BindGroup> {
self.bind_group.as_ref()
}

fn get_workgroup_size(&self, _settings: &PluginSettings) -> WorkgroupSize {
WorkgroupSize {
x: SETTINGS.texture_size.0 / 8,
y: SETTINGS.texture_size.1 / 8,
z: 1,
}
}
}

fn get_bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout {
Expand Down
33 changes: 23 additions & 10 deletions src/pipeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use bevy::render::render_graph::{Node, NodeRunError, RenderGraphContext};
use bevy::render::render_resource::*;
use bevy::render::renderer::{RenderContext, RenderDevice, RenderQueue};

use crate::AppConfig;
use crate::pipeline::blur::BlurShaderPipeline;
use crate::pipeline::fade::FadeShaderPipeline;
use crate::pipeline::recolor::RecolorShaderPipeline;
use crate::pipeline::simulation::SimulationShaderPipeline;
use crate::plugin::{PluginSettings, PluginTime};
use crate::plugin::{PluginTime, SimulationSettings};

pub mod blur;
pub mod fade;
Expand All @@ -33,21 +34,26 @@ impl FromWorld for MainShaderPipeline {
],
};

pipeline.init_data(world.resource::<RenderDevice>(), world.resource::<PluginSettings>());
pipeline.init_data(world.resource::<RenderDevice>(), world.resource::<AppConfig>(), world.resource::<SimulationSettings>());
pipeline
}
}

impl MainShaderPipeline {
pub fn init_data(&mut self, render_device: &RenderDevice, settings: &PluginSettings) {
pub fn init_data(&mut self, render_device: &RenderDevice, app_config: &AppConfig, settings: &SimulationSettings) {
for sub_pipeline in &mut self.sub_pipelines {
sub_pipeline.init_data(render_device, settings);
sub_pipeline.init_data(render_device, app_config, settings);
}
}

pub fn prepare_data(&mut self, render_queue: Res<RenderQueue>, settings: Res<PluginSettings>, time: Res<PluginTime>) {
pub fn prepare_data(&mut self,
render_queue: &RenderQueue,
app_config: &AppConfig,
settings: &SimulationSettings,
time: &PluginTime,
) {
for sub_pipeline in &mut self.sub_pipelines {
sub_pipeline.prepare_data(render_queue.as_ref(), settings.as_ref(), time.as_ref());
sub_pipeline.prepare_data(render_queue, app_config, settings, time);
}
}

Expand Down Expand Up @@ -75,7 +81,7 @@ impl MainShaderPipeline {
pipeline_cache,
sub_pipeline.get_pipeline(),
sub_pipeline.get_bind_group(),
sub_pipeline.get_workgroup_size(world.resource::<PluginSettings>()),
sub_pipeline.get_workgroup_size(world.resource::<AppConfig>(), world.resource::<SimulationSettings>()),
)
}
}
Expand Down Expand Up @@ -127,13 +133,20 @@ fn get_compute_pipeline_id(
}

pub trait SubShaderPipeline: Send + Sync {
fn init_data(&mut self, _render_device: &RenderDevice, _settings: &PluginSettings) {}
fn prepare_data(&mut self, _render_queue: &RenderQueue, _settings: &PluginSettings, _time: &PluginTime) {}
fn init_data(&mut self, _render_device: &RenderDevice, _app_config: &AppConfig, _settings: &SimulationSettings) {}
fn prepare_data(&mut self, _render_queue: &RenderQueue, _app_config: &AppConfig, _settings: &SimulationSettings, _time: &PluginTime) {}

fn queue_bind_groups(&mut self, render_device: &RenderDevice, gpu_images: &RenderAssets<Image>, images: &Vec<Handle<Image>>);
fn get_pipeline(&self) -> CachedComputePipelineId;
fn get_bind_group(&self) -> Option<&BindGroup>;
fn get_workgroup_size(&self, settings: &PluginSettings) -> WorkgroupSize;

fn get_workgroup_size(&self, app_config: &AppConfig, _settings: &SimulationSettings) -> WorkgroupSize {
WorkgroupSize {
x: app_config.texture.width / 8,
y: app_config.texture.height / 8,
z: 1,
}
}
}

pub struct PipelineData<T> {
Expand Down
Loading

0 comments on commit c3e3ccf

Please sign in to comment.