Skip to content

Commit

Permalink
Rescale to 720p/2k, minimap rendering nonsense
Browse files Browse the repository at this point in the history
  • Loading branch information
bas-ie committed Jan 20, 2025
1 parent 9061684 commit 58126e4
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 83 deletions.
29 changes: 20 additions & 9 deletions assets/shaders/mouse_shader.wgsl
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(0) var<uniform> cursor_position: vec2<f32>;
@group(2) @binding(1) var terrain_texture: texture_2d<f32>;
@group(2) @binding(2) var terrain_texture_sampler: sampler;
@group(2) @binding(3) var mask_texture: texture_2d<f32>;
@group(2) @binding(4) var mask_texture_sampler: sampler;
@group(2) @binding(1) var<uniform> level_viewport: vec2<f32>;
@group(2) @binding(2) var terrain_texture: texture_2d<f32>;
@group(2) @binding(3) var terrain_texture_sampler: sampler;
@group(2) @binding(4) var mask_texture: texture_2d<f32>;
@group(2) @binding(5) var mask_texture_sampler: sampler;

@fragment
fn fragment(mesh: VertexOutput) -> @location(0) vec4<f32> {
var terrain_color = textureSample(terrain_texture, terrain_texture_sampler, mesh.uv);

let diff = mesh.position.xy - cursor_position;
if all(abs(diff) < vec2<f32>(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<f32>(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<f32>(0.01, 0.01)) {
// TODO: should this be different to adjust for actual mesh position?
let mask_uv = (diff + vec2<f32>(1., 1.)) / 2.;

var mask_color = textureSample(mask_texture, mask_texture_sampler, mask_uv);
if terrain_color.a != 0. {
Expand Down
Binary file added assets/textures/blank.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/textures/level.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/textures/yup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub fn plugin(app: &mut App) {
pub struct Levels {
#[asset(path = "textures/level.png")]
pub level: Handle<Image>,
#[asset(path = "textures/blank.png")]
pub blank: Handle<Image>,
}

#[derive(AssetCollection, Resource)]
Expand Down
3 changes: 2 additions & 1 deletion src/game.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod minimap;
pub mod movement;
pub mod yup;

Expand All @@ -24,7 +25,7 @@ pub enum Game {
pub fn plugin(app: &mut App) {
app.init_state::<Game>();
app.enable_state_scoped_entities::<Game>();
app.add_plugins((movement::plugin, yup::plugin));
app.add_plugins((minimap::plugin, movement::plugin, yup::plugin));
app.add_systems(OnEnter(Game::Intro), init);
}

Expand Down
85 changes: 85 additions & 0 deletions src/game/minimap.rs
Original file line number Diff line number Diff line change
@@ -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::<MinimapRenderTarget>();
app.add_systems(OnEnter(Screen::InGame), init);
}

#[derive(Component)]
pub struct MinimapCamera;

#[derive(Resource, Default)]
pub struct MinimapRenderTarget {
pub texture: Handle<Image>,
}

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<Assets<Image>>,
mut minimap: ResMut<MinimapRenderTarget>,
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),
));
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bevy::{
asset::AssetMetaCheck,
audio::{AudioPlugin, Volume},
prelude::*,
render::view::RenderLayers,
render::{camera::Viewport, view::RenderLayers},
window::WindowResolution,
};

Expand Down Expand Up @@ -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()
}
Expand Down
102 changes: 31 additions & 71 deletions src/screens/ingame/playing.rs
Original file line number Diff line number Diff line change
@@ -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::<LevelViewport>();
app.add_systems(OnEnter(Screen::InGame), init);
app.init_resource::<MinimapRenderTarget>();
app.add_systems(Update, draw_alpha_gpu.run_if(in_state(Screen::InGame)));
app.add_plugins(Material2dPlugin::<LevelMaterial>::default());
}

#[derive(Resource, Default)]
pub struct MinimapRenderTarget {
pub texture: Handle<Image>,
}

#[derive(Component, Debug)]
pub struct Level;

Expand All @@ -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<Image>,
#[texture(3)]
#[sampler(4)]
#[texture(4)]
#[sampler(5)]
pub mask_texture: Handle<Image>,
}

#[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
Expand All @@ -67,11 +67,10 @@ impl Material2d for LevelMaterial {

pub fn init(
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
level_viewport: Res<LevelViewport>,
masks: Res<Masks>,
mut materials: ResMut<Assets<LevelMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut minimap: ResMut<MinimapRenderTarget>,
textures: Res<Levels>,
window: Single<&Window>,
) {
Expand All @@ -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<LevelMaterial>, With<Level>>,
level_viewport: Res<LevelViewport>,
mut materials: ResMut<Assets<LevelMaterial>>,
mouse_button: Res<ButtonInput<MouseButton>>,
window: Single<&Window>,
Expand All @@ -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;
}
}

0 comments on commit 58126e4

Please sign in to comment.