1use crate::Renderer;
2use glium::{
3 self,
4 glutin::{self, WindowEvent},
5};
6use gridsim::{GetNeighbors, Sim, SquareGrid, TakeMoveNeighbors};
7
8#[cfg(feature = "multinode")]
9use serde::{Deserialize, Serialize};
10#[cfg(feature = "multinode")]
11use std::io::{Read, Write};
12
13type Coloration<C> = Box<dyn Fn(&C) -> [f32; 3] + Sync>;
14type Filter<C> = Box<dyn Fn(&C) -> bool + Sync>;
15
16pub struct Loop<'a, S>
17where
18 S: Sim<'a>,
19{
20 scale: f32,
21 coloration: Coloration<S::Cell>,
22 filter: Filter<S::Cell>,
23}
24
25impl<'a, S> Loop<'a, S>
26where
27 S: Sim<'a>,
28{
29 pub fn new<C>(coloration: C) -> Self
31 where
32 C: Fn(&S::Cell) -> [f32; 3] + Sync + 'static,
33 {
34 Loop {
35 scale: 10.0,
36 coloration: Box::new(coloration),
37 filter: Box::new(|_| true),
38 }
39 }
40
41 pub fn new_bool() -> Self
42 where
43 S: Sim<'a, Cell = bool>,
44 {
45 Loop {
46 scale: 10.0,
47 coloration: Box::new(|_| [1.0, 1.0, 1.0]),
48 filter: Box::new(|&c| c),
49 }
50 }
51
52 pub fn scale(&mut self, scale: f32) -> &mut Self {
53 self.scale = scale;
54 self
55 }
56
57 pub fn filter<F>(&mut self, filter: F) -> &mut Self
58 where
59 F: Fn(&S::Cell) -> bool + Sync + 'static,
60 {
61 self.filter = Box::new(filter);
62 self
63 }
64
65 pub fn run(&self, mut grid: SquareGrid<'a, S>)
66 where
67 S: 'a,
68 S::Cell: Sync + Send,
69 S::Move: Sync + Send,
70 S::Diff: Sync + Send,
71 S::Neighbors: Sync + Send,
72 S::MoveNeighbors: Sync + Send,
73 SquareGrid<'a, S>: TakeMoveNeighbors<usize, S::MoveNeighbors>,
74 SquareGrid<'a, S>: GetNeighbors<'a, usize, S::Neighbors>,
75 {
76 let mut events_loop = glutin::EventsLoop::new();
77 let window = glutin::WindowBuilder::new().with_dimensions(glutin::dpi::LogicalSize::new(
78 f64::from(self.scale) * grid.get_width() as f64,
79 f64::from(self.scale) * grid.get_height() as f64,
80 ));
81 let context = glutin::ContextBuilder::new().with_vsync(true);
82 let display = glium::Display::new(window, context, &events_loop).unwrap();
83 let renderer = Renderer::new(&display);
84
85 loop {
86 use glium::Surface;
87 grid.cycle();
88
89 let mut target = display.draw();
90 target.clear_color(0.0, 0.0, 0.0, 1.0);
91 renderer
92 .render(
93 &display,
94 &mut target,
95 &grid,
96 Default::default(),
97 &*self.coloration,
98 &*self.filter,
99 )
100 .unwrap();
101 target.finish().unwrap();
102
103 let mut finish = false;
104
105 events_loop.poll_events(|event| {
107 if let glutin::Event::WindowEvent {
108 event: WindowEvent::CloseRequested,
109 ..
110 } = event
111 {
112 finish = true;
114 }
115 });
116
117 if finish {
118 return;
119 }
120 }
121 }
122
123 #[cfg(feature = "multinode")]
129 #[allow(clippy::too_many_arguments)]
130 pub unsafe fn run_multi<
131 I0: Read,
132 I1: Read,
133 I2: Read,
134 I3: Read,
135 I4: Read,
136 I5: Read,
137 I6: Read,
138 I7: Read,
139 O0: Write,
140 O1: Write,
141 O2: Write,
142 O3: Write,
143 O4: Write,
144 O5: Write,
145 O6: Write,
146 O7: Write,
147 >(
148 &self,
149 mut grid: SquareGrid<'a, S>,
150 mut in_right: I0,
151 mut in_up_right: I1,
152 mut in_up: I2,
153 mut in_up_left: I3,
154 mut in_left: I4,
155 mut in_down_left: I5,
156 mut in_down: I6,
157 mut in_down_right: I7,
158 mut out_right: O0,
159 mut out_up_right: O1,
160 mut out_up: O2,
161 mut out_up_left: O3,
162 mut out_left: O4,
163 mut out_down_left: O5,
164 mut out_down: O6,
165 mut out_down_right: O7,
166 ) where
167 S: 'a,
168 for<'dc> S::Cell: Sync + Send + Serialize + Deserialize<'dc>,
169 S::Move: Sync + Send,
170 S::Diff: Sync + Send,
171 S::Neighbors: Sync + Send,
172 S::MoveNeighbors: Sync + Send,
173 SquareGrid<'a, S>: TakeMoveNeighbors<usize, S::MoveNeighbors>,
174 SquareGrid<'a, S>: GetNeighbors<'a, usize, S::Neighbors>,
175 {
176 let mut events_loop = glutin::EventsLoop::new();
177 let window = glutin::WindowBuilder::new().with_dimensions(glutin::dpi::LogicalSize::new(
178 f64::from(self.scale) * grid.get_width() as f64,
179 f64::from(self.scale) * grid.get_height() as f64,
180 ));
181 let context = glutin::ContextBuilder::new().with_vsync(true);
182 let display = glium::Display::new(window, context, &events_loop).unwrap();
183 let renderer = Renderer::new(&display);
184
185 loop {
186 use glium::Surface;
187 if grid
188 .cycle_multi(
189 &mut in_right,
190 &mut in_up_right,
191 &mut in_up,
192 &mut in_up_left,
193 &mut in_left,
194 &mut in_down_left,
195 &mut in_down,
196 &mut in_down_right,
197 &mut out_right,
198 &mut out_up_right,
199 &mut out_up,
200 &mut out_up_left,
201 &mut out_left,
202 &mut out_down_left,
203 &mut out_down,
204 &mut out_down_right,
205 )
206 .is_err()
207 {
208 return;
209 }
210
211 let mut target = display.draw();
212 target.clear_color(0.0, 0.0, 0.0, 1.0);
213 renderer
214 .render(
215 &display,
216 &mut target,
217 &grid,
218 Default::default(),
219 &*self.coloration,
220 &*self.filter,
221 )
222 .unwrap();
223 target.finish().unwrap();
224
225 let mut finish = false;
226
227 events_loop.poll_events(|event| {
229 if let glutin::Event::WindowEvent {
230 event: WindowEvent::CloseRequested,
231 ..
232 } = event
233 {
234 finish = true;
236 }
237 });
238
239 if finish {
240 return;
241 }
242 }
243 }
244}