diff options
author | Matthew Michelotti <michelotti.matthew@gmail.com> | 2018-05-24 16:29:37 -0500 |
---|---|---|
committer | Matthew Michelotti <michelotti.matthew@gmail.com> | 2018-05-24 17:29:18 -0500 |
commit | 7091ab728345607cc028a1364ba1280df69cc58b (patch) | |
tree | 74f98444f024266f13a12819b2af186b73cf86a5 | |
parent | f905b3148397c1db1f283e1cf78f5ae5326147dd (diff) |
changed how render dims are computed, changed origin to bottom-left corner
-rw-r--r-- | example/src/main.rs | 28 | ||||
-rw-r--r-- | gate/src/app_context.rs | 5 | ||||
-rw-r--r-- | gate/src/app_info.rs | 38 | ||||
-rw-r--r-- | gate/src/renderer/render_buffer.rs | 67 | ||||
-rw-r--r-- | gate/src/renderer/renderer.rs | 15 | ||||
-rw-r--r-- | gate/src/renderer/vbo_packer.rs | 5 | ||||
-rw-r--r-- | gate_build/src/asset_packer.rs | 4 | ||||
-rw-r--r-- | gate_build/src/lib.rs | 1 |
8 files changed, 64 insertions, 99 deletions
diff --git a/example/src/main.rs b/example/src/main.rs index b4e0942..c06f1ce 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -21,7 +21,7 @@ mod asset_id { include!(concat!(env!("OUT_DIR"), "/asset_id.rs")); } use asset_id::{AssetId, SpriteId, MusicId, SoundId}; // Note: the assets that we placed in the src_assets directory can be referenced using the -// SpriteId, TileId, MusicId, and SoundId enums +// SpriteId, MusicId, and SoundId enums struct HeldDisc { value: u8, pos: (f64, f64) } @@ -40,7 +40,8 @@ fn disc_pos(pillar_index: usize, height_index: usize) -> (f64, f64) { (-27. + pillar_index as f64 * 27., 2.5 + height_index as f64 * 5.) } -fn pillar_for_cursor(cursor: (f64, f64)) -> Option<usize> { +fn pillar_for_cursor(cursor: (f64, f64), dims: (f64, f64)) -> Option<usize> { + let cursor = (cursor.0 - 0.5 * dims.0, cursor.1 - 0.5 * dims.1); (0..3).find(|&idx| { let cursor_x = cursor.0 + 13.5 - (13.5 * idx as f64); cursor_x > -6. && cursor_x < 6. && cursor.1 > -5.5 && cursor.1 < 9. @@ -65,7 +66,7 @@ impl App<AssetId> for TowerGame { KeyCode::Num1 => Some(0), KeyCode::Num2 => Some(1), KeyCode::Num3 => Some(2), - KeyCode::MouseLeft => pillar_for_cursor(ctx.cursor()), + KeyCode::MouseLeft => pillar_for_cursor(ctx.cursor(), ctx.dims()), _ => None, }; if let Some(index) = index { @@ -95,25 +96,12 @@ impl App<AssetId> for TowerGame { let mut renderer = renderer.sprite_mode(); for x in 0..((app_width / 16.).ceil() as usize) { for y in 0..((app_height / 16.).ceil() as usize) { - let affine = Affine::translate( - 8. + x as f64 * 16. - 0.5 * app_width, - 8. + y as f64 * 16. - 0.5 * app_height, - ); + let affine = Affine::translate(8. + x as f64 * 16., 8. + y as f64 * 16.); let tile = if (x + y) % 2 == 0 { SpriteId::BgTileR0C0 } else { SpriteId::BgTileR0C1 }; renderer.draw(&affine, tile); } } - /*{ // drawing tiles - let mut renderer = renderer.tiled_mode(0.5 * app_width, 0.5 * app_height); - for x in 0..((app_width / 16.).ceil() as usize) { - for y in 0..((app_height / 16.).ceil() as usize) { - let affine = Affine::translate(8. + x as f64 * 16., 8. + y as f64 * 16.); - let tile = if (x + y) % 2 == 0 { TileId::BgTileR0C0 } else { TileId::BgTileR0C1 }; - renderer.draw(&affine, tile); - } - } - }*/ - let base = Affine::scale(0.5).pre_translate(0., -10.); + let base = Affine::translate(0.5 * app_width, 0.5 * app_height - 5.).pre_scale(0.5); renderer.draw(&base, SpriteId::Pillars); for pillar_index in 0..self.pillars.len() { let pillar = &self.pillars[pillar_index]; @@ -129,6 +117,8 @@ impl App<AssetId> for TowerGame { } fn main() { - let info = AppInfo::with_app_height(48.).title("Tower"); + let info = AppInfo::with_max_dims(86., 48.) + .min_dims(64., 44.) + .title("Tower"); gate::run(info, TowerGame { pillars: vec![vec![4, 3, 2, 1, 0], vec![], vec![]], held: None }); } diff --git a/gate/src/app_context.rs b/gate/src/app_context.rs index 40c09ce..1dfe3e1 100644 --- a/gate/src/app_context.rs +++ b/gate/src/app_context.rs @@ -47,10 +47,9 @@ impl<A: AppAssetId> AppContext<A> { } fn bound_cursor(&mut self) { - let (half_width, half_height) = (self.dims.0 * 0.5, self.dims.1 * 0.5); self.cursor = ( - self.cursor.0.max(-half_width).min(half_width), - self.cursor.1.max(-half_height).min(half_height), + self.cursor.0.max(0.).min(self.dims.0), + self.cursor.1.max(0.).min(self.dims.1), ); } diff --git a/gate/src/app_info.rs b/gate/src/app_info.rs index 8f3dac6..e1c48bc 100644 --- a/gate/src/app_info.rs +++ b/gate/src/app_info.rs @@ -25,39 +25,33 @@ /// ```rust /// use gate::AppInfo; /// -/// let info = AppInfo::with_app_height(100.) +/// let info = AppInfo::with_max_dims(160., 90.) +/// .min_dims(120., 86.) /// .title("My Game") /// .target_fps(30.) /// .print_workload_info() /// .print_gl_info(); /// ``` pub struct AppInfo { - pub(crate) app_height: f64, pub(crate) window_pixels: (u32, u32), - pub(crate) min_aspect_ratio: f64, - pub(crate) max_aspect_ratio: f64, + pub(crate) min_dims: (f64, f64), + pub(crate) max_dims: (f64, f64), pub(crate) title: &'static str, pub(crate) target_fps: f64, pub(crate) print_workload_info: bool, pub(crate) print_gl_info: bool, } -impl AppInfo { - /// Returns a new AppInfo, initialized with the required value `app_height`. - /// - /// The `app_height` is the height of the screen in conceptual "app pixels", - /// which defines the units used by the renderers. - /// Even if the window is resized and the aspect ratio changed, - /// the app height will always remain the same. - /// The choice of this is important for the `TiledRenderer` in particular. - pub fn with_app_height(app_height: f64) -> AppInfo { - assert!(app_height >= 1e-30 && app_height <= 3000., "unrealistic app height {}", app_height); +// FIXME update rustdoc comments relating to app dims... +impl AppInfo { + pub fn with_max_dims(max_width: f64, max_height: f64) -> AppInfo { + assert!(max_width >= 1e-30 && max_width <= 3000., "unrealistic max_width: {}", max_width); + assert!(max_height >= 1e-30 && max_height <= 3000., "unrealistic max_height: {}", max_height); AppInfo { - app_height, window_pixels: (800, 600), - min_aspect_ratio: 4. / 3., - max_aspect_ratio: 16. / 9., + min_dims: (0., 0.), + max_dims: (max_width, max_height), title: "untitled app", target_fps: 60., print_workload_info: false, @@ -65,13 +59,9 @@ impl AppInfo { } } - /// Specifies the minimum and maximum aspect ratio for the game, enforced by - /// letterboxing/pillarboxing if necessary (default is `4/3` to `16/9`). - pub fn aspect_ratio_range(mut self, min_ratio: f64, max_ratio: f64) -> Self { - assert!(0.2 < min_ratio && min_ratio < max_ratio && max_ratio < 5.0, "invalid aspect ratios"); - // TODO ensure there is a large enough gap between min_ratio and max_ratio, so that pixel rounding isn't an issue - self.min_aspect_ratio = min_ratio; - self.max_aspect_ratio = max_ratio; + pub fn min_dims(mut self, min_width: f64, min_height: f64) -> Self { + assert!(self.min_dims.0 <= self.max_dims.0 && self.min_dims.1 <= self.max_dims.1); + self.min_dims = (min_width, min_height); self } diff --git a/gate/src/renderer/render_buffer.rs b/gate/src/renderer/render_buffer.rs index 2b4e042..916863a 100644 --- a/gate/src/renderer/render_buffer.rs +++ b/gate/src/renderer/render_buffer.rs @@ -23,58 +23,43 @@ use super::geom::Affine; pub(super) enum Mode { Sprite } pub(super) struct RenderDims { - pub min_aspect_ratio: f64, - pub max_aspect_ratio: f64, - pub app_dims: (f64, f64), - pub full_screen_dims: (u32, u32), - pub tiled_fbo_dims: (u32, u32), - pub used_screen_dims: (u32, u32), - pub app_pixel_scalar: f64, + pub min_dims: (f64, f64), + pub max_dims: (f64, f64), + pub native_dims: (u32, u32), + pub pixel_scalar: f64, + pub native_pre_pad: (u32, u32), + pub used_native_dims: (u32, u32), + pub dims: (f64, f64), } impl RenderDims { - fn new(min_aspect_ratio: f64, max_aspect_ratio: f64, app_height: f64, full_screen_dims: (u32, u32)) -> RenderDims { - let ratio = full_screen_dims.0 as f64 / full_screen_dims.1 as f64; - let used_screen_dims = if ratio < min_aspect_ratio { - let mut h = (full_screen_dims.0 as f64 / min_aspect_ratio).floor() as u32; - if (full_screen_dims.1 - h) % 2 != 0 { h -= 1; } - (full_screen_dims.0, h) - } else if ratio > max_aspect_ratio { - let mut w = (full_screen_dims.1 as f64 * max_aspect_ratio).floor() as u32; - if (full_screen_dims.0 - w) % 2 != 0 { w -= 1; } - (w, full_screen_dims.1) - } else { - full_screen_dims - }; - let ratio = used_screen_dims.0 as f64 / used_screen_dims.1 as f64; - let app_dims = (app_height * ratio, app_height); - let app_pixel_scalar = if used_screen_dims.1 == full_screen_dims.1 { - full_screen_dims.1 as f64 / app_dims.1 - } else { - full_screen_dims.0 as f64 / app_dims.0 - }; - RenderDims { - min_aspect_ratio, max_aspect_ratio, app_dims, full_screen_dims, used_screen_dims, app_pixel_scalar, - tiled_fbo_dims: (to_fbo_dim(app_height * max_aspect_ratio), to_fbo_dim(app_height)), - } + fn new(min_dims: (f64, f64), max_dims: (f64, f64), native_dims: (u32, u32)) -> RenderDims { + let scalar_from_min = (native_dims.0 as f64 / min_dims.0).min(native_dims.1 as f64 / min_dims.1); + let scalar_from_max = (native_dims.0 as f64 / max_dims.0).max(native_dims.1 as f64 / max_dims.1); + let pixel_scalar = scalar_from_min.min(scalar_from_max).max(1.0); + let used_native_dims = ( + native_dims.0.min((max_dims.0 * pixel_scalar).floor() as u32), + native_dims.1.min((max_dims.1 * pixel_scalar).floor() as u32), + ); + let native_pad = (native_dims.0 - used_native_dims.0, native_dims.1 - used_native_dims.1); + let native_pre_pad = (native_pad.0 / 2, native_pad.1 / 2); + let dims = (used_native_dims.0 as f64 / pixel_scalar, used_native_dims.1 as f64 / pixel_scalar); + RenderDims { min_dims, max_dims, native_dims, pixel_scalar, native_pre_pad, used_native_dims, dims } } - pub fn set_full_screen_dims(&mut self, screen_dims: (u32, u32)) { - *self = RenderDims::new(self.min_aspect_ratio, self.max_aspect_ratio, self.app_dims.1, screen_dims); + pub fn set_native_dims(&mut self, native_dims: (u32, u32)) { + *self = RenderDims::new(self.min_dims, self.max_dims, native_dims); } pub fn to_app_pos(&self, raw_x: i32, raw_y: i32) -> (f64, f64) { + let raw_y = self.native_dims.1 as i32 - raw_y; ( - (raw_x as f64 - 0.5 * self.full_screen_dims.0 as f64) / self.app_pixel_scalar, - -(raw_y as f64 - 0.5 * self.full_screen_dims.1 as f64) / self.app_pixel_scalar, + (raw_x - self.native_pre_pad.0 as i32) as f64 / self.pixel_scalar, + (raw_y - self.native_pre_pad.1 as i32) as f64 / self.pixel_scalar, ) } } -fn to_fbo_dim(app_dim: f64) -> u32 { - (app_dim - 1e-7).ceil() as u32 + 1 -} - pub struct RenderBuffer { pub(super) sprite_atlas: Atlas, pub(super) mode: Mode, @@ -83,12 +68,12 @@ pub struct RenderBuffer { } impl RenderBuffer { - pub fn new(info: &AppInfo, screen_dims: (u32, u32), sprite_atlas: Atlas) -> RenderBuffer { + pub fn new(info: &AppInfo, native_dims: (u32, u32), sprite_atlas: Atlas) -> RenderBuffer { RenderBuffer { sprite_atlas, mode: Mode::Sprite, vbo_data: Vec::new(), - dims: RenderDims::new(info.min_aspect_ratio, info.max_aspect_ratio, info.app_height, screen_dims), + dims: RenderDims::new(info.min_dims, info.max_dims, native_dims), } } diff --git a/gate/src/renderer/renderer.rs b/gate/src/renderer/renderer.rs index 4e58f51..e2ff84f 100644 --- a/gate/src/renderer/renderer.rs +++ b/gate/src/renderer/renderer.rs @@ -55,7 +55,7 @@ impl<A: AppAssetId> Renderer<A> { SpriteRenderer { r: self } } - pub(crate) fn app_dims(&self) -> (f64, f64) { self.b.dims.app_dims } + pub(crate) fn app_dims(&self) -> (f64, f64) { self.b.dims.dims } pub(crate) fn to_app_pos(&self, raw_x: i32, raw_y: i32) -> (f64, f64) { self.b.dims.to_app_pos(raw_x, raw_y) @@ -66,18 +66,19 @@ impl<A: AppAssetId> Renderer<A> { } pub(crate) fn set_screen_dims(&mut self, dims: (u32, u32)) { - if dims != self.b.dims.full_screen_dims { - self.b.dims.set_full_screen_dims(dims); + if dims != self.b.dims.native_dims { + self.b.dims.set_native_dims(dims); self.set_scissor(); } } fn set_scissor(&mut self) { + let dims = &self.b.dims; self.c.set_scissor( - (self.b.dims.full_screen_dims.0 - self.b.dims.used_screen_dims.0) / 2, - (self.b.dims.full_screen_dims.1 - self.b.dims.used_screen_dims.1) / 2, - self.b.dims.used_screen_dims.0, - self.b.dims.used_screen_dims.1, + dims.native_pre_pad.0, + dims.native_pre_pad.1, + dims.used_native_dims.0, + dims.used_native_dims.1, ); } } diff --git a/gate/src/renderer/vbo_packer.rs b/gate/src/renderer/vbo_packer.rs index 1ef7e68..d052abe 100644 --- a/gate/src/renderer/vbo_packer.rs +++ b/gate/src/renderer/vbo_packer.rs @@ -19,7 +19,7 @@ pub fn append_sprite(r: &mut RenderBuffer, affine: &Affine, sprite_id: u16, flas assert!(r.mode == Mode::Sprite); let img_coords = r.sprite_atlas.images[&sprite_id]; - let affine = affine.post_scale(r.dims.app_pixel_scalar); + let affine = affine.post_scale(r.dims.pixel_scalar); let flash_ratio = (flash_ratio as f32).max(0.0).min(1.0); let pad = ( @@ -37,7 +37,8 @@ pub fn append_sprite(r: &mut RenderBuffer, affine: &Affine, sprite_id: u16, flas let dst_lb = (dst_lt.0, dst_rb.1); let dst_rt = (dst_rb.0, dst_lt.1); - let affine = affine.post_scale_axes(2.0 / r.dims.full_screen_dims.0 as f64, 2.0 / r.dims.full_screen_dims.1 as f64); + let affine = affine.post_translate(-0.5 * r.dims.used_native_dims.0 as f64, -0.5 * r.dims.used_native_dims.1 as f64) + .post_scale_axes(2.0 / r.dims.native_dims.0 as f64, 2.0 / r.dims.native_dims.1 as f64); let aff_lt = affine.apply_f32(dst_lt); let aff_rb = affine.apply_f32(dst_rb); let aff_lb = affine.apply_f32(dst_lb); diff --git a/gate_build/src/asset_packer.rs b/gate_build/src/asset_packer.rs index f604fb0..679f42c 100644 --- a/gate_build/src/asset_packer.rs +++ b/gate_build/src/asset_packer.rs @@ -152,14 +152,14 @@ impl AssetPacker { /// Generates Rust enums to use as handles for all of the packed assets. /// /// The generated code will consist of four enums: - /// `SpriteId`, `TileId`, `MusicId`, and `SoundId`. + /// `SpriteId`, `MusicId`, and `SoundId`. /// These types are collected together in the type `AssetId`, /// which implements `gate::asset_id::AppAssetId`. /// Constructing a `gate::App` instance with this as the Asset ID type /// will allow you to use the generated handles to refer to assets. /// /// This method should be called after packing all of the assets. - /// The `sprites` and `tiles` methods must be called before this, + /// The `sprites` method must be called before this, /// but `music` and `sounds` may be omitted if there is no audio. /// /// The generated Rust code is written to `out`. diff --git a/gate_build/src/lib.rs b/gate_build/src/lib.rs index 87f0931..d324db6 100644 --- a/gate_build/src/lib.rs +++ b/gate_build/src/lib.rs @@ -38,7 +38,6 @@ //! let mut packer = AssetPacker::new(Path::new("assets")); //! packer.cargo_rerun_if_changed(); //! packer.sprites(Path::new("sprites")); -//! packer.tiles(Path::new("tiles")); //! packer.music(Path::new("music")); //! packer.sounds(Path::new("sounds")); //! packer.gen_asset_id_code(&gen_code_path); |