Advertisement
here2share

water simulation

Apr 2nd, 2021
907
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.73 KB | None | 0 0
  1. use std::{
  2.     f32,
  3.     io
  4. };
  5. use minifb::{
  6.     Key,
  7.     WindowOptions,
  8.     Window,
  9. };
  10. use vek::*;
  11.  
  12. const W: usize = 64;
  13. const H: usize = 64;
  14.  
  15. // store bottom-left corner + side length
  16. // since its most convenient
  17. #[derive(Copy, Clone)]
  18. struct Square {
  19.     p: Vec2<f32>,
  20.     a: f32
  21. }
  22. impl Square {
  23.     pub fn new(p0: Vec2<f32>, a0: f32) -> Self {
  24.         Square {p: p0, a: a0}
  25.     }
  26.  
  27.     pub fn shift(&mut self, offset: Vec2<f32>) {
  28.         self.p += offset
  29.     }
  30.  
  31.     pub fn grow(&mut self, amount: f32) {
  32.         self.a += amount;
  33.         self.p += Vec2::new(-0.5 * amount, -0.5 * amount);
  34.     }
  35.  
  36.     // copied from
  37.     // https://stackoverflow.com/questions/9324339
  38.     // since it was way better than what i would have come up with
  39.     pub fn intersect_area(&self, other: &Self) -> f32 {
  40.         let x1 = self.p.x.max(other.p.x);
  41.         let y1 = self.p.y.max(other.p.y);
  42.         let x2 = (self.p.x + self.a).min(other.p.x + other.a);
  43.         let y2 = (self.p.y + self.a).min(other.p.y + other.a);
  44.         (x2 - x1).max(0.0) * (y2 - y1).max(0.0)
  45.     }
  46. }
  47.  
  48. #[derive(Copy, Clone)]
  49. struct Cell {
  50.     pop: f32,
  51.     vel: Vec2<f32>,
  52.     // Watch out when using negative spread; if the group is also
  53.     // moving then it will cause weird behaviour namely if the
  54.     // absolute magnitude of the spread is greater than the largest
  55.     // of the two velocity components then the group will be rooted
  56.     // to the spot.
  57.     spread: f32,
  58.     // In the range 0 to 1 normally, 0 = no flow (if you set it to
  59.     // zero then nothing will ever enter and everything currently
  60.     // there will leave at the end of the tick unless the adjacent
  61.     // cells all have 0 conductivity). 1 = free flow, < 0 is sort of
  62.     // UDB and will make things move the opposite way to the way they
  63.     // normally would (not recommended for use apart from in special
  64.     // circumstances). Everything is relative so you can freely use
  65.     // anything above 1, but 1 should be the baseline for standard
  66.     // cells.
  67.     conductivity: f32, //TODO think of a shorter name for this lol
  68.  
  69. }
  70. impl Cell {
  71.     pub fn empty() -> Self {
  72.         Cell {
  73.             pop: 0.0,
  74.             vel: Vec2::zero(),
  75.             spread: 0.0,
  76.             conductivity: 1.0,
  77.         }
  78.     }
  79.  
  80.     pub fn set(&mut self, population: f32, velocity: Vec2<f32>, spread_factor: f32) {
  81.         self.pop = population;
  82.         self.vel = velocity;
  83.         self.spread = spread_factor
  84.     }
  85.  
  86.     pub fn clean(&mut self) {
  87.         self.pop = 0.0;
  88.     }
  89.  
  90.     // I switched out the `Option<Vec2<f32>>` since we dont need
  91.     // separate handling for the same cell; now `None` is just
  92.     // replaced by the zero vector. We also need access to delta
  93.     // here.
  94.     #[inline(always)]
  95.     pub fn flow_factor(&self, vec: Vec2<f32>, other: &Self, delta: f32) -> f32 {
  96.         let pop_box = &mut Square::new(Vec2::zero(), 1.0);
  97.         pop_box.grow(self.spread * delta);
  98.         pop_box.shift(self.vel * delta);
  99.         other.conductivity * pop_box.intersect_area(&Square::new(vec, 1.0))
  100.     }
  101.  
  102.     // I'm guessing we want to inline a function like this
  103.     #[inline(always)]
  104.     fn update_vel(&mut self, new_vel: Vec2<f32>, pop_flow: f32) {
  105.         if self.pop + pop_flow == 0.0 {
  106.             self.vel = Vec2::zero();
  107.             return
  108.         }
  109.         self.vel = (self.vel * self.pop + new_vel * pop_flow) / (self.pop + pop_flow)
  110.     }
  111.  
  112.     #[inline(always)]
  113.     fn update_spread(&mut self, new_spread: f32, pop_flow: f32) {
  114.         if self.pop + pop_flow == 0.0 {
  115.             self.spread = 0.0;
  116.             return
  117.         }
  118.         self.spread = (self.spread * self.pop + new_spread * pop_flow) / (self.pop + pop_flow)
  119.     }
  120.  
  121.     pub fn tick(&self, (this, left, right, up, down): (&mut Self, &mut Self, &mut Self, &mut Self, &mut Self), delta: f32) {
  122.         /* save some effort quite often
  123.         if self.pop == 0.0 {
  124.             return
  125.         }*/
  126.         let flow_factors = [
  127.             self.flow_factor(Vec2::zero(), this, delta),
  128.             self.flow_factor(Vec2::left(), left, delta),
  129.             self.flow_factor(Vec2::right(), right, delta),
  130.             self.flow_factor(Vec2::up(), up, delta),
  131.             self.flow_factor(Vec2::down(), down, delta),
  132.         ];
  133.         let flow_sum: f32 = (&flow_factors).iter().sum::<f32>();
  134.  
  135.         // prevent division by zero; if all flows are zero then
  136.         // all adjacent conductivities must be zero so nothing
  137.         // should move anyway (unless some are negative in which
  138.         // case in theory the net flow should be between the adjacent
  139.         // cells with no flow into/out of here but meh its
  140.         // exceedingly rare anyway)
  141.         if flow_sum == 0.0 {
  142.             return
  143.         }
  144.         let flow_vals = [
  145.             self.pop * flow_factors[1] / flow_sum,
  146.             self.pop * flow_factors[2] / flow_sum,
  147.             self.pop * flow_factors[3] / flow_sum,
  148.             self.pop * flow_factors[4] / flow_sum,
  149.         ];
  150.         let val_sum: f32 = (&flow_vals).iter().sum::<f32>();
  151.  
  152.         left.update_vel(self.vel, flow_vals[0]);
  153.         right.update_vel(self.vel, flow_vals[1]);
  154.         up.update_vel(self.vel, flow_vals[2]);
  155.         down.update_vel(self.vel, flow_vals[3]);
  156.         left.update_spread(self.spread, flow_vals[0]);
  157.         right.update_spread(self.spread, flow_vals[1]);
  158.         up.update_spread(self.spread, flow_vals[2]);
  159.         down.update_spread(self.spread, flow_vals[3]);
  160.         this.pop -= val_sum;
  161.         left.pop += flow_vals[0];
  162.         right.pop += flow_vals[1];
  163.         up.pop += flow_vals[2];
  164.         down.pop += flow_vals[3];
  165.  
  166.         this.vel.x += (left.pop - self.pop).powf(3.0) * 0.000000001;
  167.         this.vel.x += (self.pop - right.pop).powf(3.0) * 0.000000001;
  168.         this.vel.y -= (up.pop - self.pop).powf(3.0) * 0.000000001;
  169.         this.vel.y -= (self.pop - down.pop).powf(3.0) * 0.000000001;
  170.     }
  171.  
  172.     pub fn get_colour(&self) -> u32 {
  173.         ((self.pop as u32).min(255) << 16) + (((1.0 - self.conductivity) * 255.0) as u32).min(255)
  174.     }
  175. }
  176.  
  177. struct World {
  178.     cells: Box<[[Cell; H]; W]>,
  179. }
  180.  
  181. impl World {
  182.     pub fn test(option: i32) -> Self {
  183.         let mut this = Self {
  184.             cells: Box::new([[Cell::empty(); H]; W]),
  185.         };
  186.  
  187.         for i in 0..W {
  188.             for j in 0..H {
  189.                 if
  190.                     (20 + i as i32 - W as i32 / 2).wrapping_pow(2) +
  191.                     (j as i32 - H as i32 / 2).wrapping_pow(2) < 100
  192.                 {
  193.                     this.cells[i][j].set(250.0, Vec2::new(0.2, 0.1), 0.2);
  194.                 }
  195.                 if
  196.                     (-20 + i as i32 - W as i32 / 2).wrapping_pow(2) +
  197.                     (j as i32 - H as i32 / 2).wrapping_pow(2) < 100
  198.                 {
  199.                     this.cells[i][j].set(250.0, Vec2::new(-0.2, 0.1), 0.2);
  200.                 }
  201.             }
  202.         }
  203.  
  204.         match option {
  205.             2 => for i in 24..W - 24 {
  206.                 for j in 24..H - 24 {
  207.                     this.cells[i][j].conductivity = (j as f32) / (H as f32)
  208.                 }
  209.             },
  210.             _ => {
  211.                 for i in 24..W - 24 {
  212.                     this.cells[i][H / 3].conductivity = 0.0;
  213.                 }
  214.                 for i in 0..10 {
  215.                     this.cells[20 + i][H / 6].conductivity = 0.0;
  216.                     this.cells[W - 20 - i][H / 6].conductivity = 0.0;
  217.                 }
  218.                 for i in 0..W {
  219.                     this.cells[i][0].conductivity = 0.0;
  220.                     this.cells[i][0].pop = 400.0;
  221.                     this.cells[i][H - 1].conductivity = 0.0;
  222.                     this.cells[i][H - 1].pop = 400.0;
  223.                 }
  224.                 for j in 0..H {
  225.                     this.cells[0][j].conductivity = 0.0;
  226.                     this.cells[0][j].pop = 400.0;
  227.                     this.cells[W - 1][j].conductivity = 0.0;
  228.                     this.cells[W - 1][j].pop = 400.0;
  229.                 }
  230.             },
  231.         };
  232.  
  233.         this
  234.     }
  235.  
  236.     pub fn tick(&mut self, delta: f32) {
  237.         let mut new_cells = self.cells.clone();
  238.         for i in 1..W - 1 {
  239.             for j in 1..H - 1 {
  240.                 let mut this = new_cells[i][j];
  241.                 let mut left = new_cells[i - 1][j];
  242.                 let mut right = new_cells[i + 1][j];
  243.                 let mut up = new_cells[i][j - 1];
  244.                 let mut down = new_cells[i][j + 1];
  245.                 self.cells[i][j].tick((
  246.                     &mut this,
  247.                     &mut left,
  248.                     &mut right,
  249.                     &mut up,
  250.                     &mut down,
  251.                 ), delta);
  252.  
  253.                 new_cells[i][j] = this;
  254.                 new_cells[i - 1][j] = left;
  255.                 new_cells[i + 1][j] = right;
  256.                 new_cells[i][j - 1] = up;
  257.                 new_cells[i][j + 1] = down;
  258.             }
  259.         }
  260.  
  261.         self.cells = new_cells;
  262.     }
  263.  
  264.     pub fn render_to(&self, buf: &mut [u32]) {
  265.         for i in 0..W {
  266.             for j in 0..H {
  267.                 buf[j * W + i] = self.cells[i][j].get_colour();
  268.             }
  269.         }
  270.     }
  271. }
  272.  
  273. fn main() {
  274.     println!("Test mode:");
  275.     let fun = |_| {
  276.         println!("Defaulting to 1.");
  277.         1
  278.     };
  279.     let mut n_str_1 = String::new();
  280.     io::stdin().read_line(&mut n_str_1).expect("Err 1");
  281.     let n: i32 = n_str_1.trim().parse().unwrap_or_else(fun);
  282.     let mut buf = vec![0; W * H];
  283.     let mut opts = WindowOptions::default();
  284.     opts.scale = minifb::Scale::X8;
  285.     let mut win = Window::new("Worldsim", W, H, opts).unwrap();
  286.  
  287.     let mut world = World::test(n);
  288.  
  289.     while win.is_open() {
  290.         world.tick(0.01);
  291.         world.render_to(&mut buf);
  292.  
  293.         win.update_with_buffer(&buf).unwrap();
  294.     }
  295. }
  296.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement