From 58126e466417ddeb7e135f851e2a0d3c05ad8510 Mon Sep 17 00:00:00 2001 From: Rich Churcher Date: Tue, 21 Jan 2025 11:49:36 +1300 Subject: [PATCH] Rescale to 720p/2k, minimap rendering nonsense --- assets/shaders/mouse_shader.wgsl | 29 ++++++--- assets/textures/blank.png | Bin 0 -> 17866 bytes assets/textures/level.png | Bin 10501 -> 18615 bytes assets/textures/yup.png | Bin 395 -> 242 bytes src/assets.rs | 2 + src/game.rs | 3 +- src/game/minimap.rs | 85 ++++++++++++++++++++++++++ src/lib.rs | 4 +- src/screens/ingame/playing.rs | 102 ++++++++++--------------------- 9 files changed, 142 insertions(+), 83 deletions(-) create mode 100644 assets/textures/blank.png create mode 100644 src/game/minimap.rs diff --git a/assets/shaders/mouse_shader.wgsl b/assets/shaders/mouse_shader.wgsl index 24deaf7..70055a8 100644 --- a/assets/shaders/mouse_shader.wgsl +++ b/assets/shaders/mouse_shader.wgsl @@ -1,20 +1,31 @@ #import bevy_sprite::mesh2d_vertex_output::VertexOutput @group(2) @binding(0) var cursor_position: vec2; -@group(2) @binding(1) var terrain_texture: texture_2d; -@group(2) @binding(2) var terrain_texture_sampler: sampler; -@group(2) @binding(3) var mask_texture: texture_2d; -@group(2) @binding(4) var mask_texture_sampler: sampler; +@group(2) @binding(1) var level_viewport: vec2; +@group(2) @binding(2) var terrain_texture: texture_2d; +@group(2) @binding(3) var terrain_texture_sampler: sampler; +@group(2) @binding(4) var mask_texture: texture_2d; +@group(2) @binding(5) var mask_texture_sampler: sampler; @fragment fn fragment(mesh: VertexOutput) -> @location(0) vec4 { var terrain_color = textureSample(terrain_texture, terrain_texture_sampler, mesh.uv); - let diff = mesh.position.xy - cursor_position; - if all(abs(diff) < vec2(36.0, 36.0)) { - // Convert the difference to UV coordinates for the mask (0 to 1 range) - // Add 0.5 to center the mask (moving from -36..36 to 0..1 range) - let mask_uv = (diff + vec2(36.0)) / 72.0; + // For centre of screen: + // level_viewport here is 640, 360 (centred) + // mesh.position.xy is 1280, 720 because it's the middle of a 2k screen + // cursor_position will be 640, 360 (centre of screen) + // adding level_viewport + mesh.position.xy == 1920, 1080 which makes little sense + // instead, our target value should be the centre of 2k which is 1280, 720 + // it also needs to work when viewport is 0, 0 or 1920, 720, the min and max possible for viewport + // let adjusted_position = mesh.position.xy + level_viewport; + // let diff = adjusted_position - cursor_position; + + let diff = mesh.uv - cursor_position; + + if all(abs(diff) < vec2(0.01, 0.01)) { + // TODO: should this be different to adjust for actual mesh position? + let mask_uv = (diff + vec2(1., 1.)) / 2.; var mask_color = textureSample(mask_texture, mask_texture_sampler, mask_uv); if terrain_color.a != 0. { diff --git a/assets/textures/blank.png b/assets/textures/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..9b37b5bf246158cb1077c04c9ac40e72489de8b2 GIT binary patch literal 17866 zcmeHPJxc>Y5PkXN42eom(O}?28?iB3YLUc9k|s#7(jq}D?QCp>GeyAeh*dzrUl6bm zK@hGGv66I=6j}>vVPmi`?iqJ4prwV8cg@Wnw;VUjn|U)kyZbA-bSMxB00?C>sXSnd zzGKZVZWToC#m%*yPbX2k8GitDWK)UNox{gwB4p{Xtk`6 zbT0Gdu3yT)`#juo6gORiQbs9gD0y%bUO6yyk1l0+$Ka9!{TiB-k?_Zrtj+NgR1|1Y z0ujUo=s*B^S`oAuFTlVGkRE_MN`yudPSOKm2BZh12X^X6dH~V`VF#oKqzAS?AU%-u zpmlrd3EL`3vgi~iKan3D2G6=L08H6 zU=R;d1Edb*OJtQjL!~n_)mPaI09r0Bw`VMu*2-j@$vBg7T{6#qSDd=6MNRwXw72$o zbnn@m=<2j9d*kZAN5f7-T`|+ub;k+R5>3PDLM0xE2jYQvP?3{Sl+=NI$=Sa_JP;4W z1M#2&BvVV~)2uqM)S@at^&F^{gp{quyur_@Zv)yfWIhU#>i=_{yn!~FA literal 0 HcmV?d00001 diff --git a/assets/textures/level.png b/assets/textures/level.png index 274621b34d8928d8d8a0a9231fcab21e9bb5d7d8..abb4a9c0d340a9b094f86a7671ec483fbaf1c46c 100644 GIT binary patch literal 18615 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 JmJRdd{{Un+jaC2v literal 10501 zcmeI2YgAKL7ROH@gvby=v=$J`L&_9aGzD&vfB}ZrfD2ox76U~f2;QJP%qsGT6nd@L zK;*UUX%a_-q@ z?|aT~pYz|zS}BS8D4b@o!2$q4+a3|R3jlKj05Y3OK}Q~r^n{=vq^w=x!Jui#;Sm7N zV0&oLCwbMndp#K@p4MhjheEl}f}H+U6fkU_UAb;!NtA~=US&B~lXTHvPS+ood!qq} zMi3wf5CjMU1Ob8oL4Y7Y5FiK;1PB5If&X&?nXxea6$0etJM@(-m6oh{H4wBw>9#T9 z8J`fuk@iJg+DvlU(N|`vKgq+`{R`vGtc`EH!>9PR;xd7~UJ=)xZfu*q* zRRnB}y>rz6KHx>AqtO|FZgly2XhKit8Ap)cUCW)p*ACpyx#z2^ep}Ki%zn7qZ}gG= zZ5;90a1@HO7w)+za(`s%yOc41|9Zg*o#q%Dc@rys4u&CX4! zWy=YS4NHID-`MZYNc(NpyRA6J{@3eAGUa!*uDAGYi`JsIv8m@I4YVcx{^{)QxPtFo z$6}KUqUU7ci@!ByFD;i=P9OFGFIJ}Tm{+)$Cj;*4UbOgqJgSrR@12#my@Gr6zD_^2rE&vT=)O1(ZM&t)|4&Z{PEhboR@`%W{!LAIs5hVpo)R-ttPlrOF0XP zc-WXercK`if%?2dOpi*|#2MjgR?<1+#>9+k=53J9!*!I2=Tq|(JiW23KQE4D+0AL! zC>UK`JB!rIcg!?u8V?J0LF=^^X#N>erfTxGIfP~Tq+vGf_zid46F0)a!{x==?w7LM zifgmp?-{LvTm41+l)SPVAwbP&H?Vb?S?jQ4QZ?*uvsNOuyXVd~1HAXQ8M1ZdG!yjw zyY-3fy?$_OvB&P#yOvrq;L+O`gu0Xdm@%aNvC9=J%c-gbuU?1A%`yoCApW}1+9Xjr z7S(nrmF{9lVo#)Iso#OA;mjI3Kst4!SEZ3nLFj&Ywh*W2PT3?Is$O;#J9VU8hD^Z| z=C*}t-KjJN8ld%;Qo2h{${qfIzJLN1bym9oWa8(##fyx?;L#cMUncZ3gx zwDt>4K%SCS@NN8Bk}W_+qMbr@gAM;aazO=uCCwOG2NX=*up#2bPC%iqJUiPpXReNA z`j=K!{?vF_qJj$>u8BmAv(B-@c6psT+Cd4|q6+e}s|W_Krh_=e2Zn$snCqu%4ou5mulg)uQeO=LM6$D+ zb3k-|#IcLi(d%~lSdL_Uz)op~=6apjO~8UO(&3GX)zPz_%<=~v=$Ubi+Y0hy+7lLJ z{YR9i^&0eh7M|n+)sX2JXLX$S*Zt)nYQApHd*ybF&S~$=Exwff9=c(0&RtKDisbUx0MX&9 zO&PES)9ZGgs7+|8J$dR!?U#B~)f&glxjy#K`Xy6M#k)irLyu7t}xm+}L zZyPs!h@`avKrI~UB%;90CM@mrxfXl9WSoT(KNA|HTezm z+vc!)1|ABRC{N@yUp(4!Q}9*~9Iv7BJ(AhSgt(e=l8b$i`1JWrrMe0;1nu6sm zu8GKELB~eLz8}K&*tp=rJyPD7A$~{u{S>!-gVRcjys|dP9J0cUt=D&>#=`EroSro; zB_9MK4SSaQp?3&x&c8O-zcexSfkTKCOiV+W5I~FvgE%2L z2ja@$7@P@lz&H@%fS(3Hhy%`n5C|GR7lR^HJmmk*0EGSpe zw_{zjaC61volgt(s@%?0Cnf!o&ks;n<}X{ZJ0$dO^tHQt8+fdQ|9su&^z!irE?(Ps qL4)dqiD7*?-(Go5t>C%#{a#yH^*@`{cGrRKX7F_Nb6Mw<&;$U!Rb&hR literal 395 zcmV;60d)R}P)Px$MM*?KR9J=Wm&p;sAPhxu#;v#n_g_Fta4VikPGn@Eb2U;MW5Kstc1cJ+ha)B~osw}A2)i9n^QVC{VX4)@~qcKjL=xt_5 zGO7maGB@Tl#)`890dW{=$VJ;Z7>g5^g9t=}IgAEtWkDMY1ECZ0cF!0oT?2I1&XQmy zFEc}t#n>wj<(4c`{|p^~M$1Jr8r|+95NawJDQhGj2t9duJdbmZg, + #[asset(path = "textures/blank.png")] + pub blank: Handle, } #[derive(AssetCollection, Resource)] diff --git a/src/game.rs b/src/game.rs index cb9adee..eedf4ad 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,3 +1,4 @@ +pub mod minimap; pub mod movement; pub mod yup; @@ -24,7 +25,7 @@ pub enum Game { pub fn plugin(app: &mut App) { app.init_state::(); app.enable_state_scoped_entities::(); - app.add_plugins((movement::plugin, yup::plugin)); + app.add_plugins((minimap::plugin, movement::plugin, yup::plugin)); app.add_systems(OnEnter(Game::Intro), init); } diff --git a/src/game/minimap.rs b/src/game/minimap.rs new file mode 100644 index 0000000..42fb053 --- /dev/null +++ b/src/game/minimap.rs @@ -0,0 +1,85 @@ +use bevy::{ + asset::RenderAssetUsages, + prelude::*, + render::{ + render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, + view::RenderLayers, + }, +}; + +use crate::screens::Screen; + +pub fn plugin(app: &mut App) { + app.init_resource::(); + app.add_systems(OnEnter(Screen::InGame), init); +} + +#[derive(Component)] +pub struct MinimapCamera; + +#[derive(Resource, Default)] +pub struct MinimapRenderTarget { + pub texture: Handle, +} + +fn get_minimap_transform(image_size: &Vec2, screen_size: &Vec2, scale_factor: f32) -> Transform { + let actual_size = image_size / 2. * scale_factor; + Transform::from_xyz( + 20. - (screen_size.x / 2.) + actual_size.x, + // TODO: fix + -150. + (screen_size.y / 2.) + actual_size.y, + 0., + ) + .with_scale(Vec3::splat(scale_factor)) +} + +fn init( + mut commands: Commands, + mut images: ResMut>, + mut minimap: ResMut, + window: Single<&Window>, +) { + // Render to image for minimap. + let mut minimap_image = Image::new_fill( + Extent3d { + width: 2560, + height: 1440, + ..default() + }, + TextureDimension::D2, + &[0, 0, 0, 0], + TextureFormat::Bgra8UnormSrgb, + RenderAssetUsages::default(), + ); + // TODO: feels like we need DST but not SRC here? Find out for sure. This even seems to work + // without COPY_DST. Ask Discord? + minimap_image.texture_descriptor.usage = + TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING | TextureUsages::RENDER_ATTACHMENT; + minimap.texture = images.add(minimap_image); + + commands.spawn(( + Name::new("Minimap Camera"), + MinimapCamera, + Camera2d, + Camera { + clear_color: Color::WHITE.into(), + // Render this first. + order: -1, + target: minimap.texture.clone().into(), + ..default() + }, + StateScoped(Screen::InGame), + )); + + commands.spawn(( + Name::new("Minimap"), + RenderLayers::layer(1), + Sprite { + image: minimap.texture.clone(), + ..Default::default() + }, + StateScoped(Screen::InGame), + // TODO: magic numbers + get_minimap_transform(&Vec2::new(2560., 1440.), &window.size(), 0.1), + )); +} diff --git a/src/lib.rs b/src/lib.rs index ba2874c..1530a47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use bevy::{ asset::AssetMetaCheck, audio::{AudioPlugin, Volume}, prelude::*, - render::view::RenderLayers, + render::{camera::Viewport, view::RenderLayers}, window::WindowResolution, }; @@ -42,7 +42,7 @@ impl Plugin for GamePlugin { fit_canvas_to_parent: true, prevent_default_event_handling: true, resizable: false, - resolution: WindowResolution::new(1920., 1080.) + resolution: WindowResolution::new(1280., 720.) .with_scale_factor_override(1.0), ..default() } diff --git a/src/screens/ingame/playing.rs b/src/screens/ingame/playing.rs index 098dff9..829554c 100644 --- a/src/screens/ingame/playing.rs +++ b/src/screens/ingame/playing.rs @@ -1,35 +1,26 @@ use bevy::{ - asset::RenderAssetUsages, prelude::*, - render::{ - render_resource::{ - AsBindGroup, Extent3d, ShaderRef, TextureDimension, TextureFormat, TextureUsages, - }, - view::RenderLayers, - }, + render::render_resource::{AsBindGroup, ShaderRef}, sprite::{Material2d, Material2dPlugin}, }; use tiny_bail::prelude::*; use crate::{ + MainCamera, assets::{Levels, Masks}, + game::minimap::MinimapRenderTarget, screens::Screen, }; const SHADER_ASSET_PATH: &str = "shaders/mouse_shader.wgsl"; pub fn plugin(app: &mut App) { + app.init_resource::(); app.add_systems(OnEnter(Screen::InGame), init); - app.init_resource::(); app.add_systems(Update, draw_alpha_gpu.run_if(in_state(Screen::InGame))); app.add_plugins(Material2dPlugin::::default()); } -#[derive(Resource, Default)] -pub struct MinimapRenderTarget { - pub texture: Handle, -} - #[derive(Component, Debug)] pub struct Level; @@ -39,22 +30,31 @@ pub struct Obstacle; #[derive(Component)] pub struct MovementSpeed(pub f32); -#[derive(Component)] -pub struct MinimapCamera; - #[derive(Asset, Default, TypePath, AsBindGroup, Debug, Clone)] pub struct LevelMaterial { #[uniform(0)] pub cursor_position: Vec2, + #[uniform(1)] + pub level_viewport: Vec2, // TODO: find out more about samplers! - #[texture(1)] - #[sampler(2)] + #[texture(2)] + #[sampler(3)] pub terrain_texture: Handle, - #[texture(3)] - #[sampler(4)] + #[texture(4)] + #[sampler(5)] pub mask_texture: Handle, } +#[derive(Resource, Deref, DerefMut)] +pub struct LevelViewport(Vec2); + +impl Default for LevelViewport { + fn default() -> Self { + // Start at the centre of the 2k mesh + Self(Vec2::new(640., 360.)) + } +} + impl Material2d for LevelMaterial { fn alpha_mode(&self) -> bevy::sprite::AlphaMode2d { bevy::sprite::AlphaMode2d::Blend @@ -67,11 +67,10 @@ impl Material2d for LevelMaterial { pub fn init( mut commands: Commands, - mut images: ResMut>, + level_viewport: Res, masks: Res, mut materials: ResMut>, mut meshes: ResMut>, - mut minimap: ResMut, textures: Res, window: Single<&Window>, ) { @@ -80,64 +79,20 @@ pub fn init( commands.spawn(( Name::new("Level"), Level, - Mesh2d(meshes.add(Rectangle::new(1920., 1080.))), + Mesh2d(meshes.add(Rectangle::new(2560., 1440.))), MeshMaterial2d(materials.add(LevelMaterial { cursor_position, + level_viewport: **level_viewport, mask_texture: masks.cursor.clone(), terrain_texture: textures.level.clone(), })), StateScoped(Screen::InGame), )); - - // Render to image for minimap. - // TODO: can we do the lemmings-like thing of displaying a viewport within the larger image? - let mut image = Image::new_fill( - Extent3d { - width: 1920, - height: 1080, - ..default() - }, - TextureDimension::D2, - &[0, 0, 0, 0], - TextureFormat::Bgra8UnormSrgb, - RenderAssetUsages::default(), - ); - // TODO: feels like we need DST but not SRC here? Find out for sure. This even seems to work - // without COPY_DST. Ask Discord? - image.texture_descriptor.usage = - TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING | TextureUsages::RENDER_ATTACHMENT; - minimap.texture = images.add(image); - - // Source camera - commands.spawn(( - Name::new("Minimap Camera"), - MinimapCamera, - Camera2d, - Camera { - // Render this first. - order: -1, - target: minimap.texture.clone().into(), - clear_color: Color::WHITE.into(), - ..default() - }, - StateScoped(Screen::InGame), - )); - - // Debug image - commands.spawn(( - Name::new("Debug Terrain RenderTarget"), - RenderLayers::layer(1), - Sprite { - image: minimap.texture.clone(), - ..Default::default() - }, - Transform::from_xyz(-850., 450., 0.).with_scale(Vec3::splat(0.1)), - StateScoped(Screen::InGame), - )); } fn draw_alpha_gpu( level: Query<&MeshMaterial2d, With>, + level_viewport: Res, mut materials: ResMut>, mouse_button: Res>, window: Single<&Window>, @@ -148,7 +103,12 @@ fn draw_alpha_gpu( let l = r!(level.get_single()); let level_material = r!(materials.get_mut(&l.0)); - if let Some(cursor_pos) = window.physical_cursor_position() { - level_material.cursor_position = cursor_pos; + if let Some(cursor_pos) = window.cursor_position() { + let uv = Vec2::new( + cursor_pos.x / window.width(), + cursor_pos.y / window.height(), + ); + level_material.cursor_position = uv; + level_material.level_viewport = **level_viewport; } }