diff options
Diffstat (limited to 'examples/solar_system/src')
| -rw-r--r-- | examples/solar_system/src/main.rs | 227 | 
1 files changed, 97 insertions, 130 deletions
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index 4c239806..6a2de736 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -7,13 +7,14 @@  //!  //! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system  use iced::{ -    canvas, executor, Application, Canvas, Color, Command, Container, Element, -    Length, Point, Settings, Size, Subscription, Vector, +    canvas::{self, Cursor, Path, Stroke}, +    executor, time, window, Application, Canvas, Color, Command, Element, +    Length, Point, Rectangle, Settings, Size, Subscription, Vector,  };  use std::time::Instant; -pub fn main() { +pub fn main() -> iced::Result {      SolarSystem::run(Settings {          antialiasing: true,          ..Settings::default() @@ -22,7 +23,6 @@ pub fn main() {  struct SolarSystem {      state: State, -    solar_system: canvas::layer::Cache<State>,  }  #[derive(Debug, Clone, Copy)] @@ -33,12 +33,12 @@ enum Message {  impl Application for SolarSystem {      type Executor = executor::Default;      type Message = Message; +    type Flags = (); -    fn new() -> (Self, Command<Message>) { +    fn new(_flags: ()) -> (Self, Command<Message>) {          (              SolarSystem {                  state: State::new(), -                solar_system: canvas::layer::Cache::new(),              },              Command::none(),          ) @@ -52,7 +52,6 @@ impl Application for SolarSystem {          match message {              Message::Tick(instant) => {                  self.state.update(instant); -                self.solar_system.clear();              }          } @@ -65,24 +64,20 @@ impl Application for SolarSystem {      }      fn view(&mut self) -> Element<Message> { -        let canvas = Canvas::new() +        Canvas::new(&mut self.state)              .width(Length::Fill)              .height(Length::Fill) -            .push(self.solar_system.with(&self.state)); - -        Container::new(canvas) -            .width(Length::Fill) -            .height(Length::Fill) -            .center_x() -            .center_y()              .into()      }  }  #[derive(Debug)]  struct State { +    space_cache: canvas::Cache, +    system_cache: canvas::Cache, +    cursor_position: Point,      start: Instant, -    current: Instant, +    now: Instant,      stars: Vec<(Point, f32)>,  } @@ -95,153 +90,125 @@ impl State {      pub fn new() -> State {          let now = Instant::now(); -        let (width, height) = Settings::default().window.size; +        let (width, height) = window::Settings::default().size;          State { +            space_cache: Default::default(), +            system_cache: Default::default(), +            cursor_position: Point::ORIGIN,              start: now, -            current: now, -            stars: { -                use rand::Rng; - -                let mut rng = rand::thread_rng(); - -                (0..100) -                    .map(|_| { -                        ( -                            Point::new( -                                rng.gen_range(0.0, width as f32), -                                rng.gen_range(0.0, height as f32), -                            ), -                            rng.gen_range(0.5, 1.0), -                        ) -                    }) -                    .collect() -            }, +            now, +            stars: Self::generate_stars(width, height),          }      }      pub fn update(&mut self, now: Instant) { -        self.current = now; +        self.now = now; +        self.system_cache.clear(); +    } + +    fn generate_stars(width: u32, height: u32) -> Vec<(Point, f32)> { +        use rand::Rng; + +        let mut rng = rand::thread_rng(); + +        (0..100) +            .map(|_| { +                ( +                    Point::new( +                        rng.gen_range( +                            -(width as f32) / 2.0, +                            width as f32 / 2.0, +                        ), +                        rng.gen_range( +                            -(height as f32) / 2.0, +                            height as f32 / 2.0, +                        ), +                    ), +                    rng.gen_range(0.5, 1.0), +                ) +            }) +            .collect()      }  } -impl canvas::Drawable for State { -    fn draw(&self, frame: &mut canvas::Frame) { -        use canvas::{Fill, Path, Stroke}; +impl<Message> canvas::Program<Message> for State { +    fn draw( +        &self, +        bounds: Rectangle, +        _cursor: Cursor, +    ) -> Vec<canvas::Geometry> {          use std::f32::consts::PI; -        let center = frame.center(); +        let background = self.space_cache.draw(bounds.size(), |frame| { +            let space = Path::rectangle(Point::new(0.0, 0.0), frame.size()); -        let space = Path::new(|path| { -            path.rectangle(Point::new(0.0, 0.0), frame.size()) -        }); +            let stars = Path::new(|path| { +                for (p, size) in &self.stars { +                    path.rectangle(*p, Size::new(*size, *size)); +                } +            }); -        let stars = Path::new(|path| { -            for (p, size) in &self.stars { -                path.rectangle(*p, Size::new(*size, *size)); -            } +            frame.fill(&space, Color::BLACK); + +            frame.translate(frame.center() - Point::ORIGIN); +            frame.fill(&stars, Color::WHITE);          }); -        let sun = Path::new(|path| path.circle(center, Self::SUN_RADIUS)); -        let orbit = Path::new(|path| path.circle(center, Self::ORBIT_RADIUS)); - -        frame.fill(&space, Fill::Color(Color::BLACK)); -        frame.fill(&stars, Fill::Color(Color::WHITE)); -        frame.fill(&sun, Fill::Color(Color::from_rgb8(0xF9, 0xD7, 0x1C))); -        frame.stroke( -            &orbit, -            Stroke { -                width: 1.0, -                color: Color::from_rgba8(0, 153, 255, 0.1), -                ..Stroke::default() -            }, -        ); +        let system = self.system_cache.draw(bounds.size(), |frame| { +            let center = frame.center(); -        let elapsed = self.current - self.start; -        let elapsed_seconds = elapsed.as_secs() as f32; -        let elapsed_millis = elapsed.subsec_millis() as f32; +            let sun = Path::circle(center, Self::SUN_RADIUS); +            let orbit = Path::circle(center, Self::ORBIT_RADIUS); -        frame.with_save(|frame| { -            frame.translate(Vector::new(center.x, center.y)); -            frame.rotate( -                (2.0 * PI / 60.0) * elapsed_seconds -                    + (2.0 * PI / 60_000.0) * elapsed_millis, +            frame.fill(&sun, Color::from_rgb8(0xF9, 0xD7, 0x1C)); +            frame.stroke( +                &orbit, +                Stroke { +                    width: 1.0, +                    color: Color::from_rgba8(0, 153, 255, 0.1), +                    ..Stroke::default() +                },              ); -            frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); -            let earth = Path::new(|path| { -                path.circle(Point::ORIGIN, Self::EARTH_RADIUS) -            }); +            let elapsed = self.now - self.start; +            let rotation = (2.0 * PI / 60.0) * elapsed.as_secs() as f32 +                + (2.0 * PI / 60_000.0) * elapsed.subsec_millis() as f32; -            let shadow = Path::new(|path| { -                path.rectangle( +            frame.with_save(|frame| { +                frame.translate(Vector::new(center.x, center.y)); +                frame.rotate(rotation); +                frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); + +                let earth = Path::circle(Point::ORIGIN, Self::EARTH_RADIUS); +                let shadow = Path::rectangle(                      Point::new(0.0, -Self::EARTH_RADIUS),                      Size::new(                          Self::EARTH_RADIUS * 4.0,                          Self::EARTH_RADIUS * 2.0,                      ), -                ) -            }); +                ); -            frame.fill(&earth, Fill::Color(Color::from_rgb8(0x6B, 0x93, 0xD6))); +                frame.fill(&earth, Color::from_rgb8(0x6B, 0x93, 0xD6)); -            frame.with_save(|frame| { -                frame.rotate( -                    ((2.0 * PI) / 6.0) * elapsed_seconds -                        + ((2.0 * PI) / 6_000.0) * elapsed_millis, -                ); -                frame.translate(Vector::new(0.0, Self::MOON_DISTANCE)); +                frame.with_save(|frame| { +                    frame.rotate(rotation * 10.0); +                    frame.translate(Vector::new(0.0, Self::MOON_DISTANCE)); -                let moon = Path::new(|path| { -                    path.circle(Point::ORIGIN, Self::MOON_RADIUS) +                    let moon = Path::circle(Point::ORIGIN, Self::MOON_RADIUS); +                    frame.fill(&moon, Color::WHITE);                  }); -                frame.fill(&moon, Fill::Color(Color::WHITE)); +                frame.fill( +                    &shadow, +                    Color { +                        a: 0.7, +                        ..Color::BLACK +                    }, +                );              }); - -            frame.fill( -                &shadow, -                Fill::Color(Color { -                    a: 0.7, -                    ..Color::BLACK -                }), -            );          }); -    } -} - -mod time { -    use iced::futures; -    use std::time::Instant; -    pub fn every(duration: std::time::Duration) -> iced::Subscription<Instant> { -        iced::Subscription::from_recipe(Every(duration)) -    } - -    struct Every(std::time::Duration); - -    impl<H, I> iced_native::subscription::Recipe<H, I> for Every -    where -        H: std::hash::Hasher, -    { -        type Output = Instant; - -        fn hash(&self, state: &mut H) { -            use std::hash::Hash; - -            std::any::TypeId::of::<Self>().hash(state); -            self.0.hash(state); -        } - -        fn stream( -            self: Box<Self>, -            _input: futures::stream::BoxStream<'static, I>, -        ) -> futures::stream::BoxStream<'static, Self::Output> { -            use futures::stream::StreamExt; - -            async_std::stream::interval(self.0) -                .map(|_| Instant::now()) -                .boxed() -        } +        vec![background, system]      }  }  | 
