From 1d55bacd9b1671eab8afd8400e2dcbcec50802f0 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Sat, 16 Nov 2019 21:54:17 -0800 Subject: [PATCH] Add helper type for fixed-point layer sorts --- src/editor/map_renderer.rs | 2 +- src/tools/minimap.rs | 47 +++++++++++++++++++++++---- src/tools/render_passes/mod.rs | 26 +++++++-------- src/tools/render_passes/structures.rs | 2 +- 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/editor/map_renderer.rs b/src/editor/map_renderer.rs index 72f7a10c..92efdd2d 100644 --- a/src/editor/map_renderer.rs +++ b/src/editor/map_renderer.rs @@ -335,7 +335,7 @@ impl RenderPop { ofs_x: sprite.ofs_x, ofs_y: sprite.ofs_y, plane: sprite.plane, - layer: sprite.layer, + layer: sprite.layer.encode(), }) } diff --git a/src/tools/minimap.rs b/src/tools/minimap.rs index 673e818e..a9171ff4 100644 --- a/src/tools/minimap.rs +++ b/src/tools/minimap.rs @@ -158,7 +158,7 @@ pub fn generate(ctx: Context, icon_cache: &IconCache) -> Result { }; if !aboveground.is_empty() { add_overlay!(aboveground); - atom.sprite.layer = -5_000; + atom.sprite.layer = Layer::from(-5); } } else if subtype(p, "/obj/machinery/power/apc/") { use dmi::*; @@ -460,6 +460,39 @@ impl<'a> GetVar<'a> for TypeRef<'a> { // ---------------------------------------------------------------------------- // Renderer-agnostic sprite structure +/// A guaranteed sortable representation of a `layer` float. +#[derive(Default, Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct Layer { + whole: i16, + frac: u16, +} + +impl Layer { + /// Encode this layer as an `i32` for FFI representation. + pub fn encode(self) -> i32 { + ((self.whole as i32) << 16) | (self.frac as i32) + } +} + +impl From for Layer { + fn from(whole: i16) -> Layer { + Layer { whole, frac: 0 } + } +} + +impl From for Layer { + fn from(whole: i32) -> Layer { + use std::convert::TryFrom; + Layer { whole: i16::try_from(whole).expect("layer out of range"), frac: 0 } + } +} + +impl From for Layer { + fn from(f: f32) -> Layer { + Layer { whole: f as i16, frac: ((f.fract() + 1.).fract() * 65536.) as u16 } + } +} + /// A Sprite is a fragment of an atom's appearance. /// /// Every atom has a default sprite, which may be disabled, and a list of @@ -481,7 +514,7 @@ pub struct Sprite<'s> { // sorting pub plane: i32, - pub layer: i32, + pub layer: Layer, } impl<'s> Sprite<'s> { @@ -518,7 +551,7 @@ impl<'s> Default for Sprite<'s> { ofs_x: 0, ofs_y: 0, plane: 0, - layer: 0, + layer: Layer::default(), } } } @@ -547,13 +580,13 @@ fn plane_of<'s, T: GetVar<'s> + ?Sized>(objtree: &'s ObjectTree, atom: &T) -> i3 } } -fn layer_of<'s, T: GetVar<'s> + ?Sized>(objtree: &'s ObjectTree, atom: &T) -> i32 { +fn layer_of<'s, T: GetVar<'s> + ?Sized>(objtree: &'s ObjectTree, atom: &T) -> Layer { match atom.get_var("layer", objtree) { - &Constant::Int(i) => (i % 1000) * 1000, - &Constant::Float(f) => ((f % 1000.) * 1000.) as i32, + &Constant::Int(i) => Layer::from(i), + &Constant::Float(f) => Layer::from(f), other => { eprintln!("not a layer: {:?} on {:?}", other, atom.get_path()); - 2_000 + Layer::from(2) } } } diff --git a/src/tools/render_passes/mod.rs b/src/tools/render_passes/mod.rs index 90244a44..6e0a39f1 100644 --- a/src/tools/render_passes/mod.rs +++ b/src/tools/render_passes/mod.rs @@ -1,6 +1,6 @@ use dm::objtree::*; use dm::constants::Constant; -use minimap::{Atom, GetVar, Sprite}; +use minimap::{Atom, GetVar, Sprite, Layer}; pub mod transit_tube; pub mod random; @@ -287,30 +287,30 @@ impl RenderPass for FancyLayers { } } -fn fancy_layer_for_path(p: &str) -> Option { +fn fancy_layer_for_path(p: &str) -> Option { use dm::objtree::subpath as subtype; Some(if subtype(p, "/turf/open/floor/plating/") || subtype(p, "/turf/open/space/") { - -10_000 // under everything + Layer::from(-10) // under everything } else if subtype(p, "/turf/closed/mineral/") { - -3_000 // above hidden stuff and plating but below walls + Layer::from(-3) // above hidden stuff and plating but below walls } else if subtype(p, "/turf/open/floor/") || subtype(p, "/turf/closed/") { - -2_000 // above hidden pipes and wires + Layer::from(-2) // above hidden pipes and wires } else if subtype(p, "/turf/") { - -10_000 // under everything + Layer::from(-10) // under everything } else if subtype(p, "/obj/effect/turf_decal/") { - -1_000 // above turfs + Layer::from(-1) // above turfs } else if subtype(p, "/obj/structure/disposalpipe/") { - -6_000 + Layer::from(-6) } else if subtype(p, "/obj/machinery/atmospherics/pipe/") && !p.contains("visible") { - -5_000 + Layer::from(-5) } else if subtype(p, "/obj/structure/cable/") { - -4_000 + Layer::from(-4) } else if subtype(p, "/obj/machinery/power/terminal/") { - -3_500 + Layer::from(-3.5) } else if subtype(p, "/obj/structure/lattice/") { - -8_000 + Layer::from(-8) } else if subtype(p, "/obj/machinery/navbeacon/") { - -3_000 + Layer::from(-3) } else { return None }) diff --git a/src/tools/render_passes/structures.rs b/src/tools/render_passes/structures.rs index b9d938a3..f97229c9 100644 --- a/src/tools/render_passes/structures.rs +++ b/src/tools/render_passes/structures.rs @@ -66,7 +66,7 @@ impl RenderPass for GravityGen { sprite.icon_state = icon_state; sprite.plane = 0; // TODO: figure out plane handling for real if count <= 3 { - sprite.layer = 4_250; // WALL_OBJ_LAYER + sprite.layer = Layer::from(4.25); // WALL_OBJ_LAYER } if count == 5 { // energy overlay goes above the middle part