diff --git a/assets/Ryfjallet_cubemap.png b/assets/Ryfjallet_cubemap.png new file mode 100644 index 0000000..9f1ae59 --- /dev/null +++ b/assets/Ryfjallet_cubemap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4600bb26a92b642d227e0462fd45aa1cce1149190200d2e026b2fac6e83d585f +size 669336 diff --git a/assets/images/cube.jpg b/assets/images/cube.jpg new file mode 100644 index 0000000..ae88f23 Binary files /dev/null and b/assets/images/cube.jpg differ diff --git a/assets/images/cube.png b/assets/images/cube.png new file mode 100644 index 0000000..88ffee3 --- /dev/null +++ b/assets/images/cube.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:51b2cdc53fa672839be5bfbf4a113d6c56ba3885e29e07cc0703cd16675309c9 +size 11697929 diff --git a/assets/images/cubemap.blend b/assets/images/cubemap.blend new file mode 100644 index 0000000..1fe59f7 --- /dev/null +++ b/assets/images/cubemap.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85fde6c11c9257c2373b6ed009c3885eb38e50307f8a8ad9b47a9e3a7327edc6 +size 963672 diff --git a/assets/images/cubemap.blend1 b/assets/images/cubemap.blend1 new file mode 100644 index 0000000..d676056 --- /dev/null +++ b/assets/images/cubemap.blend1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b4af0bacd70583a374dc6679eb6795b33d88cb15c41bd41efbeb6389af64e44 +size 983020 diff --git a/assets/images/cubemap.png b/assets/images/cubemap.png new file mode 100644 index 0000000..5039364 --- /dev/null +++ b/assets/images/cubemap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:611d52e14af81d9ddfb5a5dd7df141043177b53e1a04e35d0c161a26a8db5a00 +size 298782 diff --git a/assets/images/mars-skybox.xcf b/assets/images/mars-skybox.xcf new file mode 100644 index 0000000..d3b2d43 --- /dev/null +++ b/assets/images/mars-skybox.xcf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc2da4f55847ed1be40f93f9cb56f962c0f88ade83c3db36350dd9b351771eee +size 1361524 diff --git a/assets/images/mars.hdr b/assets/images/mars.hdr index fd2cc2a..595c89d 100644 --- a/assets/images/mars.hdr +++ b/assets/images/mars.hdr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd5a9fcba6f562feea99e050326ae0ba633545e4211bd854eeffec1ae5279db3 -size 12559058 +oid sha256:d17e6f791d32194a72c3639d506404c0b0a7e98e7112412c5fbd1fcf2a58d127 +size 2359360 diff --git a/assets/images/skybox_negx.png b/assets/images/skybox_negx.png new file mode 100644 index 0000000..a3d5b52 --- /dev/null +++ b/assets/images/skybox_negx.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2713a42c96c12a9a493cf6c22382506abc3ae20c9e8e7158e6a03a36bdc50b9d +size 56271 diff --git a/assets/images/skybox_negy.png b/assets/images/skybox_negy.png new file mode 100644 index 0000000..6ddd452 --- /dev/null +++ b/assets/images/skybox_negy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:839ca79ede386fa05aef3ea15c1eeb1551231f1da0ed86f5073a866249c1929f +size 65329 diff --git a/assets/images/skybox_negz.png b/assets/images/skybox_negz.png new file mode 100644 index 0000000..131d191 --- /dev/null +++ b/assets/images/skybox_negz.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c20d30e6e01c4a21f600392ceee5f457a4424b0f40c82f1918e225ce39ad81d4 +size 56163 diff --git a/assets/images/skybox_posx.png b/assets/images/skybox_posx.png new file mode 100644 index 0000000..4dfe44b --- /dev/null +++ b/assets/images/skybox_posx.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e86f11a90be762e227b1d5210654e17e5daf68536a8c438b8eea389db48e536f +size 18713 diff --git a/assets/images/skybox_posy.png b/assets/images/skybox_posy.png new file mode 100644 index 0000000..af01c41 --- /dev/null +++ b/assets/images/skybox_posy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:556c480f44b11ad723e78c640d0d1f84443bf1cc6a598521ff7a23a1a8a3e88f +size 24263 diff --git a/assets/images/skybox_posz.png b/assets/images/skybox_posz.png new file mode 100644 index 0000000..5270036 --- /dev/null +++ b/assets/images/skybox_posz.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c9764a04df2189fd05b5d5c5af6a01b730642413790b1d99867c3183d375319 +size 43118 diff --git a/assets/models/Martian Chess.glb b/assets/models/Martian Chess.glb index db3b9bc..e69e2d6 100644 --- a/assets/models/Martian Chess.glb +++ b/assets/models/Martian Chess.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9a3447fe51d9af0cf74e71ddb0ebeb72d0a48f202cba7580190545124faaef3 -size 18557524 +oid sha256:ddf012ed8fd66bd1fc0ae468584a1bc7167e1a682d1ee4176d66801f799dd59e +size 38887344 diff --git a/src/display3d.rs b/src/display3d.rs index 445105b..db46fc9 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -1,19 +1,32 @@ -use crate::{game::BoardIndex, prelude::*}; +use crate::{ + game::{Board, BoardIndex, Piece, Side}, + prelude::*, +}; +use bevy::{ + core_pipeline::Skybox, + render::render_resource::{TextureViewDescriptor, TextureViewDimension}, +}; pub(crate) struct Display3dPlugin; impl Plugin for Display3dPlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, initialize_camera) - .add_systems(OnEnter(GameState::Loading), load_models) - .add_systems(OnExit(GameState::Loading), initialize_board) + app.add_systems(OnEnter(GameState::Loading), load_assets) + .add_systems( + OnExit(GameState::Loading), + (initialize, fix_skybox.before(initialize)), + ) .add_systems( Update, menu::exit_to_menu.run_if(in_state(GameState::Display3d)), ) .add_systems( Update, - set_piece_position.run_if(in_state(GameState::Display3d)), + ( + set_piece_position.run_if(any_component_changed::), + set_piece_model.run_if(any_component_changed::), + set_board_model.run_if(any_component_added::), + ), ) .add_systems( Update, @@ -32,7 +45,29 @@ struct Display3d; #[derive(Debug, Component)] pub(crate) struct Piece3d; -fn initialize_camera(mut commands: Commands) { +#[derive(Debug, Component)] +pub(crate) struct Board3d; + +#[derive(Debug, Resource)] +struct AssetsMap { + models: Handle, + skybox: Handle, +} + +/// Load 3d models +/// This is kind of pulling double duty. +/// Both loads the GLTF file _and_ populates the ModelMap once that is loaded. +fn load_assets(server: Res, mut commands: Commands) { + commands.insert_resource(AssetsMap { + models: server.load("models/Martian Chess.glb"), + skybox: server.load("images/cubemap.png"), + }); +} + +/// Initialize the 3d board +fn initialize(mut commands: Commands, board: Option>, assets: Res) { + info!("Initialize 3d camera"); + // let handle = server.load("images/mars.hdr"); commands.spawn(( Display3d, Camera3dBundle { @@ -48,6 +83,11 @@ fn initialize_camera(mut commands: Commands) { transform: Transform::from_xyz(0.0, 20.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, + Skybox(assets.skybox.clone()), + // EnvironmentMapLight { + // diffuse_map: server.load("images/pisa_diffuse_rgb9e5_zstd.ktx2"), + // specular_map: server.load("images/pisa_specular_rgb9e5_zstd.ktx2"), + // }, UiCameraConfig { show_ui: true }, )); // light @@ -60,96 +100,98 @@ fn initialize_camera(mut commands: Commands) { transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); + + info!("Initializing root"); + commands + .spawn(( + SpatialBundle { + visibility: Visibility::Hidden, + ..default() + }, + Display3d, + )) + .with_children(|parent| { + info!("Initializing 3D lights!"); + parent.spawn(( + Display3d, + PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }, + )); + + info!("Intializing 3D Board!"); + parent + .spawn((Display3d, Board3d, SceneBundle { ..default() })) + .with_children(|parent| { + board.unwrap().pieces().iter().for_each(|(index, piece)| { + let side = Board::side(index).expect("Spawn valid side"); + + parent.spawn(( + side, + Piece3d, + piece.clone(), + index.clone(), + SceneBundle { ..default() }, + )); + }); + }); + }); } -#[derive(Debug, Resource)] -struct ModelsFile { - handle: Handle, +fn fix_skybox(mut images: ResMut>, assets: Res) { + let image = images.get_mut(&assets.skybox).unwrap(); + info!("Loaded skybox image"); + // NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture, + // so they appear as one texture. The following code reconfigures the texture as necessary. + if image.texture_descriptor.array_layer_count() == 1 { + image.reinterpret_stacked_2d_as_array( + image.texture_descriptor.size.height / image.texture_descriptor.size.width, + ); + image.texture_view_descriptor = Some(TextureViewDescriptor { + dimension: Some(TextureViewDimension::Cube), + ..default() + }); + } } -/// Load 3d models -/// This is kind of pulling double duty. -/// Both loads the GLTF file _and_ populates the ModelMap once that is loaded. -fn load_models(server: Res, mut commands: Commands) { - commands.insert_resource(ModelsFile { - handle: server.load("models/Martian Chess.glb"), +fn set_piece_model( + mut events: Query<(&mut Handle, &Piece), (With, Changed)>, + assets_map: Option>, + gltfs: Res>, +) { + let mf = assets_map.expect("Models file"); + events.iter_mut().for_each(|(mut handle, piece)| { + let gltf = gltfs.get(&mf.models).expect("Load GLTF content"); + *handle = match piece { + game::Piece::Pawn => gltf.named_scenes.get("Pawn"), + game::Piece::Drone => gltf.named_scenes.get("Drone"), + game::Piece::Queen => gltf.named_scenes.get("Queen"), + } + .expect("Game board model") + .clone(); }); } -/// Initialize the 3d board -fn initialize_board( - mut commands: Commands, - model_file: Option>, +fn set_board_model( + mut events: Query<&mut Handle, With>, + assets_map: Option>, gltfs: Res>, - board: Option>, ) { - info!("Initializing board"); - if let Some(mf) = model_file { - let gltf = gltfs.get(&mf.handle).expect("Load GLTF content"); - - info!("Initializing root"); - commands - .spawn(( - SpatialBundle { - visibility: Visibility::Hidden, - ..default() - }, - Display3d, - )) - .with_children(|parent| { - info!("Initializing 3D lights!"); - parent.spawn(( - Display3d, - PointLightBundle { - point_light: PointLight { - intensity: 1500.0, - shadows_enabled: true, - ..default() - }, - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }, - )); - - info!("Intializeing 3D Board!"); - parent - .spawn(( - Display3d, - SceneBundle { - scene: gltf - .named_scenes - .get("Gameboard") - .expect("Game board model") - .clone(), - ..default() - }, - )) - .with_children(|parent| { - // TODO: Add this to a reactive system when board is added - board - .unwrap() - .pieces() - .into_iter() - .for_each(|(index, piece)| { - // TODO: Move this to a reactive system like index -> Transform - let scene = match piece { - game::Piece::Pawn => gltf.named_scenes.get("Pawn"), - game::Piece::Drone => gltf.named_scenes.get("Drone"), - game::Piece::Queen => gltf.named_scenes.get("Queen"), - } - .expect("Game board model") - .clone(); - - parent.spawn(( - Piece3d, - piece, - index, - SceneBundle { scene, ..default() }, - )); - }); - }); - }); - } + let mf = assets_map.expect("Models file"); + events.iter_mut().for_each(|mut handle| { + let gltf = gltfs.get(&mf.models).expect("Load GLTF content"); + *handle = gltf + .named_scenes + .get("Gameboard") + .expect("Game board model") + .clone(); + }) } /// Sets a piece location given it's board index diff --git a/src/main.rs b/src/main.rs index 1c0b4ac..750ecb9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,7 +83,7 @@ fn loading( .filter(|&id| matches!(id, HandleId::AssetPathId(_))) .collect::>(); - info!( + debug!( "Sprite len: {:?} | GLTF len: {:?}", s_ids.len(), g_ids.len()