Feature flag, conditional compilation attributes

This commit is contained in:
Danny McGee
2023-11-13 19:29:06 -05:00
parent 8bf4abc3a4
commit 580f0dee81
5 changed files with 102 additions and 57 deletions
+2
View File
@@ -34,6 +34,8 @@ web-sys = { version = "0.3.65", optional = true, features = [
] } ] }
[features] [features]
default = []
headless = []
wasm = [ wasm = [
"dep:console_error_panic_hook", "dep:console_error_panic_hook",
"dep:js-sys", "dep:js-sys",
+6 -4
View File
@@ -9,13 +9,15 @@
"targets": { "targets": {
"build": { "build": {
"executor": "@nxrs/cargo:build", "executor": "@nxrs/cargo:build",
"inputs": ["assets"], "options": {},
"options": {
"release": false
},
"configurations": { "configurations": {
"production": { "production": {
"release": true "release": true
},
"headless": {
"bin": "studio-standalone",
"release": true,
"features": "headless"
} }
} }
}, },
+31 -10
View File
@@ -1,29 +1,34 @@
#![allow(clippy::type_complexity, clippy::too_many_arguments)] #![allow(clippy::type_complexity, clippy::too_many_arguments)]
use bevy::prelude::*; use bevy::prelude::*;
use bevy_mod_picking::DefaultPickingPlugins;
use camera_controller::CameraControllerPlugin;
use debug::DebugPlugin;
use input::StudioInputPlugin;
use interaction::InteractionPlugin;
use math::InterpolationPlugin;
use scene::ScenePlugin;
use skybox::SkyboxPlugin;
use ui::UiLayerPlugin;
use viewport::ViewportSize;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
#[cfg(not(feature = "headless"))]
mod camera_controller; mod camera_controller;
#[cfg(not(feature = "headless"))]
mod debug; mod debug;
#[cfg(not(feature = "headless"))]
mod design_system; mod design_system;
#[cfg(not(feature = "headless"))]
mod input; mod input;
#[cfg(not(feature = "headless"))]
mod interaction; mod interaction;
mod math; mod math;
mod scene; mod scene;
mod skybox; mod skybox;
#[cfg(not(feature = "headless"))]
mod ui; mod ui;
mod viewport; mod viewport;
#[cfg(not(feature = "headless"))]
use crate::{
camera_controller::CameraControllerPlugin, debug::DebugPlugin, input::StudioInputPlugin,
interaction::InteractionPlugin, ui::UiLayerPlugin,
};
use crate::{
math::InterpolationPlugin, scene::ScenePlugin, skybox::SkyboxPlugin, viewport::ViewportSize,
};
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
mod wasm; mod wasm;
@@ -40,6 +45,7 @@ pub fn init(viewport_size: ViewportSize) {
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
app.add_plugins(viewport::wasm::ViewportPlugin); app.add_plugins(viewport::wasm::ViewportPlugin);
#[cfg(not(feature = "headless"))]
app.add_plugins(( app.add_plugins((
DefaultPlugins.set(WindowPlugin { DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window { primary_window: Some(Window {
@@ -61,4 +67,19 @@ pub fn init(viewport_size: ViewportSize) {
UiLayerPlugin, UiLayerPlugin,
)) ))
.run(); .run();
#[cfg(feature = "headless")]
app.add_plugins((
bevy::log::LogPlugin::default(),
bevy::core::TaskPoolPlugin::default(),
bevy::core::TypeRegistrationPlugin,
bevy::time::TimePlugin,
bevy::transform::TransformPlugin,
bevy::hierarchy::HierarchyPlugin,
bevy::diagnostic::DiagnosticsPlugin,
InterpolationPlugin,
ScenePlugin,
SkyboxPlugin,
))
.run();
} }
+1 -1
View File
@@ -6,12 +6,12 @@ pub use traits::*;
mod ecs; mod ecs;
mod traits; mod traits;
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum Easing { pub enum Easing {
Linear, Linear,
Sine, Sine,
SineOut, SineOut,
#[allow(dead_code)]
SineIn, SineIn,
} }
+62 -42
View File
@@ -1,35 +1,43 @@
#[cfg(not(feature = "headless"))]
use bevy::{ use bevy::{
asset::LoadState, asset::LoadState,
gltf,
pbr::NotShadowCaster,
reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef},
utils::HashSet,
};
use bevy::{
core_pipeline::{ core_pipeline::{
bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings}, bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings},
fxaa::Fxaa, fxaa::Fxaa,
tonemapping::Tonemapping, tonemapping::Tonemapping,
}, },
gltf::{self, Gltf}, gltf::Gltf,
math::vec3, math::vec3,
pbr::NotShadowCaster,
prelude::*, prelude::*,
reflect::{TypePath, TypeUuid},
render::render_resource::{AsBindGroup, ShaderRef},
utils::HashSet,
}; };
#[cfg(not(feature = "headless"))]
use bevy_mod_picking::PickableBundle; use bevy_mod_picking::PickableBundle;
#[cfg(not(feature = "headless"))]
use crate::{ use crate::{
camera_controller::{CameraController, CameraControllerBundle, CameraMotionSystem}, camera_controller::{CameraController, CameraControllerBundle, CameraMotionSystem},
interaction::Selectable, interaction::Selectable,
skybox::SkyboxId,
MainCamera,
}; };
use crate::{skybox::SkyboxId, MainCamera};
pub struct ScenePlugin; pub struct ScenePlugin;
impl Plugin for ScenePlugin { impl Plugin for ScenePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(ClearColor(Color::hsl(0.0, 0.0, 0.25))) app.insert_resource(ClearColor(Color::hsl(0.0, 0.0, 0.25)))
.insert_resource(Msaa::Off) .add_systems(Startup, initialize);
#[cfg(not(feature = "headless"))]
app.insert_resource(Msaa::Off)
.add_plugins(MaterialPlugin::<ProceduralGridMaterial>::default()) .add_plugins(MaterialPlugin::<ProceduralGridMaterial>::default())
.add_systems(Startup, initialize)
.add_systems( .add_systems(
Update, Update,
mark_scene_objects.run_if( mark_scene_objects.run_if(
@@ -45,6 +53,7 @@ impl Plugin for ScenePlugin {
} }
} }
#[cfg(not(feature = "headless"))]
#[derive(Component)] #[derive(Component)]
struct WorldGridPlane; struct WorldGridPlane;
@@ -57,8 +66,8 @@ struct Inspectable;
fn initialize( fn initialize(
mut cmd: Commands, mut cmd: Commands,
assets: Res<AssetServer>, assets: Res<AssetServer>,
mut ra_meshes: ResMut<Assets<Mesh>>, #[cfg(not(feature = "headless"))] mut ra_meshes: ResMut<Assets<Mesh>>,
mut ra_mat_proc_grid: ResMut<Assets<ProceduralGridMaterial>>, #[cfg(not(feature = "headless"))] mut ra_mat_proc_grid: ResMut<Assets<ProceduralGridMaterial>>,
) { ) {
// Skybox // Skybox
cmd.insert_resource(SkyboxId("test_scene".into())); cmd.insert_resource(SkyboxId("test_scene".into()));
@@ -89,6 +98,7 @@ fn initialize(
}, },
..default() ..default()
}, },
#[cfg(not(feature = "headless"))]
CameraControllerBundle::new(focus, camera_xform.translation), CameraControllerBundle::new(focus, camera_xform.translation),
BloomSettings { BloomSettings {
composite_mode: BloomCompositeMode::EnergyConserving, composite_mode: BloomCompositeMode::EnergyConserving,
@@ -106,6 +116,7 @@ fn initialize(
// TODO: get Blender to export enough metadata to automate light placements // TODO: get Blender to export enough metadata to automate light placements
cmd.spawn(( cmd.spawn((
Name::new("Ceiling Light"), Name::new("Ceiling Light"),
#[cfg(not(feature = "headless"))]
Selectable, Selectable,
Inspectable, Inspectable,
PointLightBundle { PointLightBundle {
@@ -124,6 +135,7 @@ fn initialize(
// Monitor glow // Monitor glow
cmd.spawn(( cmd.spawn((
Name::new("Monitor Glow"), Name::new("Monitor Glow"),
#[cfg(not(feature = "headless"))]
Selectable, Selectable,
Inspectable, Inspectable,
PointLightBundle { PointLightBundle {
@@ -140,43 +152,48 @@ fn initialize(
)); ));
// Plane // Plane
let plane = ra_meshes.add(Mesh::from(shape::Plane { #[cfg(not(feature = "headless"))]
size: 200.0, {
subdivisions: 0, let plane = ra_meshes.add(Mesh::from(shape::Plane {
})); size: 200.0,
let proc_grid = ra_mat_proc_grid.add(ProceduralGridMaterial {}); subdivisions: 0,
}));
let proc_grid = ra_mat_proc_grid.add(ProceduralGridMaterial {});
cmd.spawn(( cmd.spawn((
Name::new("World Grid"), Name::new("World Grid"),
SpatialBundle::from_transform(Transform::IDENTITY), SpatialBundle::from_transform(Transform::IDENTITY),
WorldGridPlane, WorldGridPlane,
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(( parent.spawn((
MaterialMeshBundle { MaterialMeshBundle {
mesh: plane.clone(), mesh: plane.clone(),
material: proc_grid.clone(), material: proc_grid.clone(),
transform: Transform::IDENTITY, transform: Transform::IDENTITY,
..default() ..default()
}, },
NotShadowCaster, NotShadowCaster,
)); ));
parent.spawn(( parent.spawn((
MaterialMeshBundle { MaterialMeshBundle {
mesh: plane, mesh: plane,
material: proc_grid, material: proc_grid,
transform: Transform::IDENTITY.looking_to(Vec3::Z, Vec3::NEG_Y), transform: Transform::IDENTITY.looking_to(Vec3::Z, Vec3::NEG_Y),
..default() ..default()
}, },
NotShadowCaster, NotShadowCaster,
)); ));
}); });
}
} }
#[cfg(not(feature = "headless"))]
fn gltf_loaded(assets: Res<AssetServer>, gltf: Res<NewGltf>) -> bool { fn gltf_loaded(assets: Res<AssetServer>, gltf: Res<NewGltf>) -> bool {
assets.get_load_state(&**gltf) == LoadState::Loaded assets.get_load_state(&**gltf) == LoadState::Loaded
} }
#[cfg(not(feature = "headless"))]
fn gltf_scene_spawned( fn gltf_scene_spawned(
r_assets: Res<AssetServer>, r_assets: Res<AssetServer>,
r_gltf: Res<NewGltf>, r_gltf: Res<NewGltf>,
@@ -200,6 +217,7 @@ fn gltf_scene_spawned(
}) })
} }
#[cfg(not(feature = "headless"))]
fn mark_scene_objects( fn mark_scene_objects(
mut cmd: Commands, mut cmd: Commands,
r_gltf: Res<NewGltf>, r_gltf: Res<NewGltf>,
@@ -255,7 +273,6 @@ fn mark_scene_objects(
}) })
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
// If the sets match, this is the entity that represents the glTF mesh // If the sets match, this is the entity that represents the glTF mesh
if prims_from_gltf == prims_from_ecs { if prims_from_gltf == prims_from_ecs {
cmd.entity(ent_parent).insert(Selectable); cmd.entity(ent_parent).insert(Selectable);
@@ -271,6 +288,7 @@ fn mark_scene_objects(
cmd.remove_resource::<NewGltf>(); cmd.remove_resource::<NewGltf>();
} }
#[cfg(not(feature = "headless"))]
fn move_plane_with_camera( fn move_plane_with_camera(
mut plane: Query<(&WorldGridPlane, &mut Transform)>, mut plane: Query<(&WorldGridPlane, &mut Transform)>,
camera: Query<&CameraController, Changed<CameraController>>, camera: Query<&CameraController, Changed<CameraController>>,
@@ -283,10 +301,12 @@ fn move_plane_with_camera(
} }
} }
#[cfg(not(feature = "headless"))]
#[derive(AsBindGroup, Clone, TypePath, TypeUuid)] #[derive(AsBindGroup, Clone, TypePath, TypeUuid)]
#[uuid = "CE331A13-F247-4F5B-A75E-670B2BD5776A"] #[uuid = "CE331A13-F247-4F5B-A75E-670B2BD5776A"]
struct ProceduralGridMaterial {} struct ProceduralGridMaterial {}
#[cfg(not(feature = "headless"))]
impl Material for ProceduralGridMaterial { impl Material for ProceduralGridMaterial {
fn fragment_shader() -> ShaderRef { fn fragment_shader() -> ShaderRef {
"shaders/procedural_grid.wgsl".into() "shaders/procedural_grid.wgsl".into()