Skip to main content

roar/runtime/
frame.rs

1use crate::{
2    frame_map,
3    result::{RoarError, RoarResult},
4};
5use noise::{Fbm, MultiFractal, Perlin, RidgedMulti, Value};
6use std::{collections::VecDeque, sync::Arc};
7
8use crate::bc::Op;
9
10use super::{value::RuntimeValue, FRAME_SIZE};
11pub struct ExecutionFrame {
12    code_pos: usize,
13    code: Arc<[Op]>,
14    stack: VecDeque<RuntimeValue>,
15    input_pos: usize,
16    input_section: Arc<[RuntimeValue]>,
17    buf_pos: usize,
18    input_buffer: Arc<[RuntimeValue]>,
19    memory: Vec<RuntimeValue>,
20    ctx: ExecutionContext,
21}
22
23impl ExecutionFrame {
24    pub(super) fn new(
25        code: Arc<[Op]>,
26        input_section: Arc<[RuntimeValue]>,
27        input_buffer: Arc<[RuntimeValue]>,
28        ctx: ExecutionContext,
29    ) -> Self {
30        Self {
31            code_pos: 0,
32            code,
33            stack: VecDeque::new(),
34            input_pos: 0,
35            input_section,
36            buf_pos: 0,
37            input_buffer,
38            memory: Vec::with_capacity(256),
39            ctx,
40        }
41    }
42
43    fn pull_op(&mut self) -> RoarResult<Op> {
44        if self.code_pos < self.code.len() {
45            self.code_pos += 1;
46            Ok(self.code[self.code_pos - 1])
47        } else {
48            Err(RoarError::RuntimeNoOpsLeft)
49        }
50    }
51    fn pull_const(&mut self) -> RoarResult<RuntimeValue> {
52        if self.input_pos < self.input_section.len() {
53            self.input_pos += 1;
54            Ok(self.input_section[self.input_pos - 1])
55        } else {
56            Err(RoarError::RuntimeNoConstsLeft)
57        }
58    }
59    fn pull_var(&mut self) -> RoarResult<RuntimeValue> {
60        if self.buf_pos < self.input_buffer.len() {
61            self.buf_pos += 1;
62            Ok(self.input_buffer[self.buf_pos - 1])
63        } else {
64            Err(RoarError::RuntimeNoVarsLeft)
65        }
66    }
67    fn pull_stack(&mut self) -> RoarResult<RuntimeValue> {
68        if let Some(pulled) = self.stack.pop_front() {
69            Ok(pulled)
70        } else {
71            Err(RoarError::RuntimeStackEmpty)
72        }
73    }
74    fn push_stack(&mut self, value: RuntimeValue) {
75        self.stack.push_front(value);
76    }
77    fn step(&mut self) -> RoarResult<()> {
78        match self.pull_op()? {
79            Op::Load => {
80                        let value = self.pull_var()?;
81                        self.push_stack(value);
82                    }
83            Op::LoadConst => {
84                        let value = self.pull_const()?;
85                        self.push_stack(value);
86                    }
87            Op::Set => {
88                        let id = self.pull_stack()?.as_i64()?;
89                        let val = self.pull_stack()?;
90                        self.memory.insert(id[0] as usize, val);
91                    }
92            Op::Get => {
93                        let id = self.pull_stack()?.as_i64()?;
94                        if let Some(val) = self.memory.get(id[0] as usize) {
95                            self.push_stack(*val);
96                        } else {
97                            return Err(RoarError::IndexNotInMemory);
98                        }
99                    }
100            Op::Swap => {
101                        self.stack.swap(0, 1);
102                    }
103            Op::Perlin => {
104                        let seed = self.pull_stack()?.as_i64()?.unanymous_val()?;
105                        let noise = Perlin::new(seed as u32);
106                        let noise_map = frame_map!(self.ctx, noise);
107                        self.push_stack(RuntimeValue::f64_new(noise_map));
108                    }
109            Op::Fbm => {
110                        let persistence = self.pull_stack()?.as_f64()?.unanymous_val()?;
111                        let lacunarity = self.pull_stack()?.as_f64()?.unanymous_val()?;
112                        let freq = self.pull_stack()?.as_f64()?.unanymous_val()?;
113                        let octaves = self.pull_stack()?.as_i64()?.unanymous_val()?;
114                        let seed = self.pull_stack()?.as_i64()?.unanymous_val()?;
115                        let noise = Fbm::<Perlin>::new(seed as u32)
116                            .set_persistence(persistence)
117                            .set_lacunarity(lacunarity)
118                            .set_frequency(freq)
119                            .set_octaves(octaves as usize);
120                        let noise_map = frame_map!(self.ctx, noise);
121                        self.push_stack(RuntimeValue::f64_new(noise_map));
122                    }
123            Op::RidgedMulti => {
124                        let persistence = self.pull_stack()?.as_f64()?.unanymous_val()?;
125                        let lacunarity = self.pull_stack()?.as_f64()?.unanymous_val()?;
126                        let freq = self.pull_stack()?.as_f64()?.unanymous_val()?;
127                        let octaves = self.pull_stack()?.as_i64()?.unanymous_val()?;
128                        let seed = self.pull_stack()?.as_i64()?.unanymous_val()?;
129                        let noise = RidgedMulti::<Perlin>::new(seed as u32)
130                            .set_persistence(persistence)
131                            .set_lacunarity(lacunarity)
132                            .set_frequency(freq)
133                            .set_octaves(octaves as usize);
134                        let noise_map = frame_map!(self.ctx, noise);
135                        self.push_stack(RuntimeValue::f64_new(noise_map));
136                    }
137            Op::Value => {
138                        let seed = self.pull_stack()?.as_i64()?.unanymous_val()?;
139                        let noise = Value::new(seed as u32);
140                        let noise_map = frame_map!(self.ctx, noise);
141                        self.push_stack(RuntimeValue::f64_new(noise_map));
142                    }
143            Op::Add => {
144                        let rhs = self.pull_stack()?;
145                        let out = match rhs {
146                            RuntimeValue::F64(rhs) => RuntimeValue::F64(rhs + self.pull_stack()?.as_f64()?),
147                            RuntimeValue::I64(rhs) => RuntimeValue::I64(rhs + self.pull_stack()?.as_i64()?),
148                        };
149                        self.push_stack(out);
150                    }
151            Op::Sub => {
152                        let rhs = self.pull_stack()?;
153                        let out = match rhs {
154                            RuntimeValue::F64(rhs) => RuntimeValue::F64(rhs - self.pull_stack()?.as_f64()?),
155                            RuntimeValue::I64(rhs) => RuntimeValue::I64(rhs - self.pull_stack()?.as_i64()?),
156                        };
157                        self.push_stack(out);
158                    }
159            Op::Mul => {
160                        let rhs = self.pull_stack()?;
161                        let out = match rhs {
162                            RuntimeValue::F64(rhs) => RuntimeValue::F64(rhs * self.pull_stack()?.as_f64()?),
163                            RuntimeValue::I64(rhs) => RuntimeValue::I64(rhs * self.pull_stack()?.as_i64()?),
164                        };
165                        self.push_stack(out);
166                    }
167            Op::Div => {
168                        let rhs = self.pull_stack()?;
169                        let out = match rhs {
170                            RuntimeValue::F64(rhs) => RuntimeValue::F64(rhs / self.pull_stack()?.as_f64()?),
171                            RuntimeValue::I64(rhs) => RuntimeValue::I64(rhs / self.pull_stack()?.as_i64()?),
172                        };
173                        self.push_stack(out);
174                    }
175            Op::Neg => {
176                        let out = match self.pull_stack()? {
177                            RuntimeValue::I64(runtime_i64_value) => RuntimeValue::I64(-runtime_i64_value),
178                            RuntimeValue::F64(runtime_f64_value) => RuntimeValue::F64(-runtime_f64_value),
179                        };
180                        self.push_stack(out);
181                    }
182            Op::Max => {
183                        let other = self.pull_stack()?;
184                        let out = match other {
185                            RuntimeValue::F64(other) => {
186                                RuntimeValue::F64(other.max(self.pull_stack()?.as_f64()?))
187                            }
188                            RuntimeValue::I64(other) => {
189                                RuntimeValue::I64(other.max(self.pull_stack()?.as_i64()?))
190                            }
191                        };
192                        self.push_stack(out);
193                    }
194            Op::Min => {
195                        let other = self.pull_stack()?;
196                        let out = match other {
197                            RuntimeValue::F64(other) => {
198                                RuntimeValue::F64(other.min(self.pull_stack()?.as_f64()?))
199                            }
200                            RuntimeValue::I64(other) => {
201                                RuntimeValue::I64(other.min(self.pull_stack()?.as_i64()?))
202                            }
203                        };
204                        self.push_stack(out);
205                    }
206            Op::Pwr => {
207                        let pow = self.pull_stack()?;
208                        let out = match self.pull_stack()? {
209                            RuntimeValue::I64(runtime_i64_value) => {
210                                RuntimeValue::I64(runtime_i64_value.pow(pow.as_i64()?))
211                            }
212                            RuntimeValue::F64(runtime_f64_value) => match pow {
213                                RuntimeValue::I64(pow_i64) => {
214                                    RuntimeValue::F64(runtime_f64_value.powi(pow_i64))
215                                }
216                                RuntimeValue::F64(pow_f64) => {
217                                    RuntimeValue::F64(runtime_f64_value.powf(pow_f64))
218                                }
219                            },
220                        };
221                        self.push_stack(out);
222                    }
223            Op::LeftShift => {
224                        let rhs = self.pull_stack()?.as_i64()?;
225                        let lhs = self.pull_stack()?.as_i64()?;
226                        self.push_stack(RuntimeValue::I64(lhs << rhs));
227                    }
228            Op::RightShift => {
229                        let rhs = self.pull_stack()?.as_i64()?;
230                        let lhs = self.pull_stack()?.as_i64()?;
231                        self.push_stack(RuntimeValue::I64(lhs >> rhs));
232                    }
233            Op::GetCtx1 => self.push_stack(RuntimeValue::f64_splat(self.ctx.x)),
234            Op::GetCtx2 => self.push_stack(RuntimeValue::f64_splat(self.ctx.y)),
235            Op::SetCtx4 => self.ctx.scale_x = self.pull_stack()?.as_f64()?.unanymous_val()?,
236            Op::SetCtx5 => self.ctx.scale_y = self.pull_stack()?.as_f64()?.unanymous_val()?,
237            Op::PutOnCurve => {
238                let end_y = self.pull_stack()?.as_f64()?;
239                let end_x = self.pull_stack()?.as_f64()?;
240                let start_y = self.pull_stack()?.as_f64()?;
241                let start_x = self.pull_stack()?.as_f64()?;
242                let mem_idx = self.pull_stack()?.as_i64()?.unanymous_val()? as usize;
243                let value = self.pull_stack()?.as_f64()?;
244                if self.memory.get(mem_idx).is_none() {
245                    self.memory.insert(mem_idx, RuntimeValue::f64_splat(0.0));
246                }
247                let mem = &mut self.memory[mem_idx];
248                match mem {
249                    RuntimeValue::I64(_) => return Err(RoarError::UnmatchedTypeUnwrap),
250                    RuntimeValue::F64(mem) => {
251                        for i in 0..FRAME_SIZE {
252                            let v = value[i];
253                            let end_y = end_y[i];
254                            let end_x = end_x[i];
255                            let start_y = start_y[i];
256                            let start_x = start_x[i];
257                            if start_x <= v && v <= end_x {
258                                let t = (v - start_x) / (end_x - start_x);
259                                mem[i] = (1.0 - t) * start_y + t * end_y;
260                            }
261                        }
262                    },
263                }
264                self.push_stack(RuntimeValue::F64(value));
265            },
266        }
267        Ok(())
268    }
269    pub fn run(&mut self) -> RoarResult<RuntimeValue> {
270        while self.code_pos < self.code.len() {
271            self.step()?;
272        }
273        if let Some(out) = self.stack.pop_front() {
274            Ok(out)
275        } else {
276            Err(RoarError::RuntimeFinishedWithoutReturnValue)
277        }
278    }
279}
280#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
281pub struct ExecutionContext {
282    pub(super) x: f64,
283    pub(super) y: f64,
284    pub(super) scale_x: f64,
285    pub(super) scale_y: f64,
286}
287
288#[macro_export]
289macro_rules! frame_map {
290    ($ctx:expr, $noise: expr) => {{
291        use super::{FRAME_SIZE, FRAME_WIDTH};
292        use noise::NoiseFn;
293        let map = noise::utils::PlaneMapBuilder::new_fn(move |[x, y]| $noise.get([x, y]))
294            .set_size(FRAME_WIDTH, FRAME_WIDTH)
295            .set_x_bounds(
296                $ctx.x * 16.0 * $ctx.scale_x,
297                ($ctx.x + 1.0) * 16.0 * $ctx.scale_x,
298            )
299            .set_y_bounds(
300                $ctx.y * 16.0 * $ctx.scale_y,
301                ($ctx.y + 1.0) * 16.0 * $ctx.scale_y,
302            )
303            .build();
304        let mut arr = [0.0; FRAME_SIZE];
305        let mut i = 0;
306        for v in map.iter() {
307            arr[i] = *v;
308            i += 1;
309        }
310        arr
311    }};
312}