use bevy_materialize::{GenericMaterial, MaterializePlugin};
use bevy_materialize::prelude::TomlMaterialDeserializer;
use bevy_magic_fx::magic_fx_beam::MagicFxBeamComponent;
use std::f32::consts::PI;
use bevy::asset::{AssetPath, LoadedFolder};
use bevy::core_pipeline::prepass::DepthPrepass;
use bevy::{gltf::GltfMesh, utils::HashMap};
use bevy::core_pipeline::bloom::{Bloom };
use bevy::core_pipeline::tonemapping::Tonemapping;
use bevy::{core_pipeline::bloom::BloomCompositeMode, prelude::*};
use bevy_magic_fx::magic_fx::{MagicFxNoAutoTransform,MagicFxVariantComponent,MagicFxBillboardTarget};
use bevy_magic_fx::{ MagicFxPlugin};
use bevy_magic_fx::{
magic_fx_variant::{MagicFxVariant, MagicFxVariantManifest},
};
use bevy_magic_fx::camera;
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(bevy_obj::ObjPlugin)
.add_plugins( MaterializePlugin::new(TomlMaterialDeserializer)
.with_simple_loader_settings(None) )
.init_state::<LoadingState>()
.add_plugins( MagicFxPlugin )
.init_resource::<BuiltMaterialsResource>()
.init_resource::<BuiltVfxResource>()
.init_resource::<AssetLoadingResource>()
.init_resource::<FolderLoadingResource>()
.add_systems(Update, update_load_folders)
.add_systems(OnEnter(LoadingState::FundamentalAssetsLoad), update_loading_magic_fx_variant_manifest)
.add_systems(OnEnter(LoadingState::Complete) , spawn_magic_fx)
.add_systems(Startup, setup)
.add_systems(Update, camera::update_camera_look)
.add_systems(Update, camera::update_camera_move)
.run();
}
#[derive(Resource, Default)]
struct BuiltVfxResource {
magic_fx_variants: HashMap<String, MagicFxVariant>
}
#[derive(Resource )]
struct BuiltMaterialsResource ( HashMap< String, Handle<GenericMaterial> > );
impl FromWorld for BuiltMaterialsResource {
fn from_world(world: &mut World) -> Self {
let mut built_map = HashMap::new();
built_map.insert("beam".to_string(), world.load_asset( "materialize_defs/beam.material.toml" ) );
built_map.insert("portal_1".to_string(), world.load_asset( "materialize_defs/portal_1.material.toml" ) );
Self(built_map)
}
}
#[derive(Resource, Default)]
struct AssetLoadingResource {
texture_handles_map: HashMap<String, Handle<Image>>,
mesh_handles_map: HashMap<String, Handle<Mesh>>,
magic_fx_variants_map: HashMap<String, Handle<MagicFxVariantManifest>>,
}
#[derive(Resource, Default)]
struct FolderLoadingResource {
textures_folder_handle: Handle<LoadedFolder>,
meshes_folder_handle: Handle<LoadedFolder>,
magicfx_folder_handle: Handle<LoadedFolder>,
}
#[derive(States,Hash,Eq,PartialEq,Debug,Clone,Default)]
pub enum LoadingState {
#[default]
Init,
FundamentalAssetsLoad,
Complete
}
fn setup(
mut commands: Commands,
asset_server: ResMut<AssetServer>,
mut folder_loading_resource: ResMut<FolderLoadingResource>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let textures_folder = asset_server.load_folder("textures/");
let meshes_folder = asset_server.load_folder("meshes/");
let magic_fx_variants_folder = asset_server.load_folder("magic_fx_variants/");
folder_loading_resource.textures_folder_handle = textures_folder;
folder_loading_resource.meshes_folder_handle = meshes_folder;
folder_loading_resource.magicfx_folder_handle = magic_fx_variants_folder;
commands.spawn(
(
PointLight {
intensity: 2000.0,
range: 100.,
shadows_enabled: false,
..default()
},
Transform::from_xyz(8.0, 16.0, 8.0)
)
);
commands.insert_resource(AmbientLight {
color: Color::linear_rgba(1.0, 1.0, 1.0, 1.0),
brightness: 4000.0,
});
let silver_color = Color::linear_rgba(0.22, 0.22, 0.22, 0.2);
commands.spawn(
(
Mesh3d( meshes.add(Plane3d::default().mesh().size(50.0, 50.0)) ) ,
MeshMaterial3d( materials.add( silver_color ) )
)
);
commands.spawn((
Camera3d::default() ,
Camera {
hdr: true, ..default()
},
Tonemapping::TonyMcMapface,
Transform::from_xyz(0.0, 6., 12.0)
.looking_at(Vec3::new(0., 1., 0.), Vec3::Y),
Bloom::OLD_SCHOOL,
DepthPrepass,
MagicFxBillboardTarget {},
));
}
fn update_load_folders(
mut ev_asset: EventReader<AssetEvent<LoadedFolder>>,
asset_server: ResMut<AssetServer>,
loaded_folder_assets: Res<Assets<LoadedFolder>>,
mut asset_loading_resource: ResMut<AssetLoadingResource>,
mut next_state: ResMut<NextState<LoadingState>>
){
for ev in ev_asset.read() {
match ev {
AssetEvent::LoadedWithDependencies { id } => {
let loaded_folder = loaded_folder_assets.get( *id ).unwrap();
for handle in &loaded_folder.handles {
let asset_path = asset_server.get_path( handle.id() ).unwrap();
info!("asset path {:?}", asset_path);
if (&asset_path.path()).starts_with("meshes") {
asset_loading_resource.mesh_handles_map.insert((&asset_path.path().to_str().unwrap().to_string()).clone(), asset_server.load( &asset_path ) ) ;
}
if (&asset_path.path()).starts_with("textures") {
asset_loading_resource.texture_handles_map.insert((&asset_path.path().to_str().unwrap().to_string()).clone(), asset_server.load( &asset_path ) ) ;
}
if (&asset_path.path()).starts_with("magic_fx_variants") {
asset_loading_resource.magic_fx_variants_map.insert((&asset_path.path().to_str().unwrap().to_string()).clone(), asset_server.load( &asset_path ) ) ;
}
}
if ! asset_loading_resource.mesh_handles_map.is_empty()
&& !asset_loading_resource.texture_handles_map.is_empty()
&& !asset_loading_resource.magic_fx_variants_map.is_empty()
{
next_state.set(LoadingState::FundamentalAssetsLoad);
}
}
_ => {}
}
}
}
fn update_loading_magic_fx_variant_manifest(
fx_variant_assets: ResMut<Assets<MagicFxVariantManifest>>,
mut commands: Commands,
mut built_vfx_resource: ResMut<BuiltVfxResource>,
built_materials_resource: Res<BuiltMaterialsResource>,
asset_loading_resource: Res<AssetLoadingResource>,
mut next_state: ResMut<NextState<LoadingState>>,
generic_materials_assets: Res<Assets<GenericMaterial>>,
mut asset_server: ResMut<AssetServer>,
) {
info!("update_loading_magic_fx_variant_manifest ");
for (file_path, magic_fx_handle) in asset_loading_resource.magic_fx_variants_map.clone().iter() {
let magic_fx_variant_manifest: &MagicFxVariantManifest = fx_variant_assets
.get( magic_fx_handle.id() )
.unwrap();
let mesh_handles_map = &asset_loading_resource.mesh_handles_map;
let generic_materials_map = &built_materials_resource.0;
let Some( magic_fx ) = MagicFxVariant::from_manifest(
magic_fx_variant_manifest,
&mesh_handles_map,
&generic_materials_map,
&generic_materials_assets,
&mut asset_server
) else {
warn!( "could not load {:?}",file_path.to_string() );
continue
};
info!("loaded {:?}",file_path.to_string());
built_vfx_resource.magic_fx_variants.insert(file_path.to_string(), magic_fx);
}
next_state.set(LoadingState::Complete);
}
fn spawn_magic_fx(
mut commands: Commands,
built_vfx_resource: Res <BuiltVfxResource>,
time: Res<Time>
){
println!("spawning magic fx ");
let waterfall_fx = built_vfx_resource.magic_fx_variants.get("magic_fx_variants/portal_1.magicfx.ron").unwrap();
commands .spawn(
(Transform::from_xyz(0.0,0.0,0.0), Visibility::default( ) )
)
.insert(MagicFxVariantComponent {
magic_fx: waterfall_fx.clone(),
start_time: time.elapsed(),
}) ;
}