1#![allow(dead_code)]
10
11use handwired_rs::{
12 Circuit, Relation, SourceTable, TensorProgram, Wire, emit_and, emit_compare, emit_not, emit_select, event, input,
13 state_bit,
14};
15
16pub const TRACK_WIDTH: f64 = 52.0;
17pub const TRACK_HEIGHT: f64 = 32.0;
18
19#[derive(Copy, Clone, Debug, PartialEq)]
20pub enum PointerKind {
21 Down,
22 Up,
23 Cancel,
24}
25
26#[derive(Copy, Clone, Debug, PartialEq)]
28pub struct PointerEvent {
29 pub kind: PointerKind,
30 pub x: f32,
31 pub y: f32,
32}
33
34#[derive(Copy, Clone, Debug, PartialEq)]
35pub struct Output {
36 pub track_left: f32,
37 pub track_top: f32,
38 pub on: f32,
39 pub armed: f32,
40}
41
42struct Pointer {
43 active: Wire,
44 x: Wire,
45 y: Wire,
46}
47
48pub struct Toggle {
49 table: SourceTable,
50 circuit: Circuit,
51 program: TensorProgram,
52 source: Vec<f32>,
53 viewport: (Wire, Wire),
54 down: Pointer,
55 up: Pointer,
56 cancel: Wire,
57 outputs: [Wire; 4],
58}
59
60impl Default for Toggle {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66impl Toggle {
67 pub fn new() -> Toggle {
68 let mut table = SourceTable::new();
70 let coordinate = || input(-16_384.0, 16_384.0).grid(1.0 / 64.0);
71 let viewport_width = table.declare("viewport.width", input(0.0, 16_384.0).grid(1.0).initial(1280.0));
72 let viewport_height = table.declare("viewport.height", input(0.0, 16_384.0).grid(1.0).initial(800.0));
73 let mut pointer = |name: &str| Pointer {
74 active: table.declare(format!("{name}.active"), event()),
75 x: table.declare(format!("{name}.x"), coordinate()),
76 y: table.declare(format!("{name}.y"), coordinate()),
77 };
78 let down = pointer("down");
79 let up = pointer("up");
80 let cancel = table.declare("cancel", event());
81 let on_cell = table.declare("on", state_bit());
82 let armed_cell = table.declare("armed", state_bit());
83 let mut circuit = table.create_circuit();
84 let c = &mut circuit;
85
86 let track_left = c.affine(viewport_width * 0.5 - TRACK_WIDTH / 2.0);
88 let track_top = c.affine(viewport_height * 0.5 - TRACK_HEIGHT / 2.0);
89 let track_right = c.affine(track_left + TRACK_WIDTH);
90 let track_bottom = c.affine(track_top + TRACK_HEIGHT);
91 let inside_track = |c: &mut Circuit, point: &Pointer| {
93 let bits = [
94 emit_compare(c, point.x, Relation::AtLeast, track_left),
95 emit_compare(c, point.x, Relation::Less, track_right),
96 emit_compare(c, point.y, Relation::AtLeast, track_top),
97 emit_compare(c, point.y, Relation::Less, track_bottom),
98 ];
99 emit_and(c, &bits)
100 };
101
102 let down_inside = inside_track(c, &down);
105 let armed_after_down = emit_select(c, down.active, armed_cell, down_inside);
106 let up_inside = inside_track(c, &up);
108 let flips = emit_and(c, &[up.active, armed_after_down, up_inside]);
109 let flipped = emit_not(c, on_cell);
110 let on = emit_select(c, flips, on_cell, flipped);
111 let no_up = emit_not(c, up.active);
113 let no_cancel = emit_not(c, cancel);
114 let armed = emit_and(c, &[armed_after_down, no_up, no_cancel]);
115
116 table.next(on_cell, on);
118 table.next(armed_cell, armed);
119 table.finish();
120 let outputs = [track_left, track_top, on, armed];
121 let mut roots = outputs.to_vec();
122 roots.extend(table.next_wires());
123 let program = circuit.compile(Some(&roots));
124 let source = table.initial();
125 Toggle {
126 table,
127 circuit,
128 program,
129 source,
130 viewport: (viewport_width, viewport_height),
131 down,
132 up,
133 cancel,
134 outputs,
135 }
136 }
137
138 pub fn circuit(&self) -> &Circuit {
139 &self.circuit
140 }
141
142 pub fn program(&self) -> &TensorProgram {
143 &self.program
144 }
145
146 pub fn step(&mut self, width: f32, height: f32, events: &[PointerEvent]) -> Result<Output, String> {
149 let mut values = self.source.clone();
150 values[self.viewport.0.index()] = width;
151 values[self.viewport.1.index()] = height;
152 for event in events {
153 let pointer = match event.kind {
154 PointerKind::Down => &self.down,
155 PointerKind::Up => &self.up,
156 PointerKind::Cancel => {
157 values[self.cancel.index()] = 1.0;
158 continue;
159 }
160 };
161 values[pointer.active.index()] = 1.0;
162 values[pointer.x.index()] = event.x;
163 values[pointer.y.index()] = event.y;
164 }
165 self.table.validate(&values)?;
166 let result = self.circuit.evaluate_tensor(&values, &self.program).map_err(|error| error.to_string())?;
167 self.source = self.table.advance(&values, &result);
168 let [track_left, track_top, on, armed] = self.outputs.map(|wire| result[wire.index()]);
169 Ok(Output { track_left, track_top, on, armed })
170 }
171}
172
173#[derive(Default)]
175pub struct ToggleReference {
176 on: bool,
177 armed: bool,
178}
179
180impl ToggleReference {
181 pub fn step(&mut self, width: f64, height: f64, events: &[PointerEvent]) -> Output {
182 let track_left = width / 2.0 - TRACK_WIDTH / 2.0;
183 let track_top = height / 2.0 - TRACK_HEIGHT / 2.0;
184 let inside = |event: &PointerEvent| {
185 let (x, y) = (event.x as f64, event.y as f64);
186 x >= track_left && x < track_left + TRACK_WIDTH && y >= track_top && y < track_top + TRACK_HEIGHT
187 };
188 let last = |kind| events.iter().rev().find(|event| event.kind == kind);
189 if let Some(down) = last(PointerKind::Down) {
190 self.armed = inside(down);
191 }
192 let up = last(PointerKind::Up);
193 if let Some(up) = up
194 && self.armed
195 && inside(up)
196 {
197 self.on = !self.on;
198 }
199 if up.is_some() || last(PointerKind::Cancel).is_some() {
200 self.armed = false;
201 }
202 let bit = |value: bool| if value { 1.0 } else { 0.0 };
203 Output { track_left: track_left as f32, track_top: track_top as f32, on: bit(self.on), armed: bit(self.armed) }
204 }
205}
206
207fn main() {
208 let mut toggle = Toggle::new();
209 let program = toggle.program();
210 println!(
211 "toggle: {} source cells, {} built operations, {} live in {} layers, {} stored weights",
212 toggle.circuit().source_size(),
213 toggle.circuit().operations().len(),
214 program.live_operation_count(),
215 program.layers.len(),
216 program.stored_weight_count(),
217 );
218 let press = |kind, x, y| [PointerEvent { kind, x, y }];
219 let frames: [(&str, Vec<PointerEvent>); 4] = [
220 ("press on the track", press(PointerKind::Down, 640.0, 400.0).to_vec()),
221 ("release on the track", press(PointerKind::Up, 640.0, 400.0).to_vec()),
222 ("press 1/64 px left of the track", press(PointerKind::Down, 613.984_4, 400.0).to_vec()),
223 ("release on the track", press(PointerKind::Up, 640.0, 400.0).to_vec()),
224 ];
225 for (label, events) in frames {
226 let output = toggle.step(1280.0, 800.0, &events).unwrap();
227 println!("{label:32} -> on {} armed {}", output.on, output.armed);
228 }
229}