Hacked some more on this.

This commit is contained in:
Rasmus Kaj 2023-11-30 22:48:17 +01:00
parent 4f8f02e146
commit c05d696b5c
2 changed files with 197 additions and 4 deletions

13
README.md Normal file
View file

@ -0,0 +1,13 @@
# ttylia - Julia fractals on tty
This is intended to write the output to a DIGITAL VT220 terminal.
```
sudo chown $USER /dev/ttyUSB0
stty -F /dev/ttyUSB0 raw 19200
cargo run > /dev/ttyUSB0
```
Note: 19200 bits per second gives about 2 frames per second (a frame
is 40x24 chars, a char is 8 data bits + start and stop bit, so 10
bits).

View file

@ -1,9 +1,17 @@
use num_complex::Complex32;
use std::{io::{self, Write}, thread::sleep, time::{Duration, Instant}};
const CHARS: &[u8; 33] = b"@. .,:;-~+*i=xom\\//11II77OO77MMMM";
const CHARS: &[u8; 13] = b"\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xA9\xA9\xA9\xA9";
fn main() {
const CSI: u8 = b'\x9b'; // Start of control sequence, equivalent to "\x1B["
fn csi(code: &[u8]) -> Vec<u8> {
let mut res = vec![CSI]; // or vec![0x1B, b'['] for 7-bit compat.
res.extend(code);
res
}
fn main() -> Result<(), io::Error> {
const WIDTH: u16 = 40;
const HEIGHT: u16 = 24;
const SY: f32 = 3.2 / (HEIGHT as f32);
@ -17,10 +25,22 @@ fn main() {
let mut rotor = Complex32 { re: 1., im: frame_time.as_secs_f32() * 0.2 };
let mut frame = 0;
let mut out = io::stdout().lock();
out.write_all(b"\x1B[2J").unwrap();
out.write_all(&csi(b"2J"))?;
out.write_all(&csi(b"?25l"))?;
out.write_all(b"\x1B)@\x1B~")?; // Enable custom character set
define_pixels(&mut out);
//out.write_all(b"\r\n\x1B#6 Hello \xA0\xA1\xA2\xA3\xA4\xA5\xA6 World\r\n").unwrap();
//return;
loop {
let frame_start = Instant::now();
c *= rotor;
/*eprintln!("{:.4} / {:+.4} {:+.4} / {:+.4}",
c.l1_norm(),
(c.l1_norm() - 1.),
(rotor.l1_norm() - 1.),
(c.l1_norm() - 1.) * (rotor.l1_norm() - 1.));*/
if c.norm_sqr() > 2. {
rotor *= (1. / rotor.norm_sqr()).sqrt();
}
@ -61,9 +81,169 @@ fn main() {
}
}
fn define_pixels(out: &mut impl Write) {
let chars = [
chardef([
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b1111_1110,
0b0000_0000,
]),
chardef([
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
]),
chardef([ // 1 pixel
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0001_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
]),
chardef([ // 4 pixels
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0010_1000,
0b0000_0000,
0b0010_1000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
0b0000_0000,
]),
chardef([ // 5 pixels
0b0000_0000,
0b0000_0000,
0b0100_0100,
0b0000_0000,
0b0001_0000,
0b0000_0000,
0b0100_0100,
0b0000_0000,
0b0000_0000,
0b0000_0000,
]),
chardef([ // 6 pixels
0b0000_0000,
0b0100_1000,
0b0000_0000,
0b0000_0000,
0b0100_1000,
0b0000_0000,
0b0000_0000,
0b0100_1000,
0b0000_0000,
0b0000_0000,
]),
chardef([ // 9 pixels
0b0000_0010,
0b0001_0000,
0b1000_0000,
0b0000_0010,
0b0001_0000,
0b1000_0000,
0b0000_0010,
0b0001_0000,
0b1000_0000,
0b0000_0000,
]),
chardef([ // half
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0000_0000,
]),
chardef([
0b1010_1010,
0b0111_0100,
0b1010_1010,
0b0101_1100,
0b1110_1010,
0b0101_0100,
0b1010_1010,
0b0101_1100,
0b1010_1010,
0b0000_0000,
]),
chardef([
0b1110_1110,
0b0111_0110,
0b1011_1010,
0b0101_0100,
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0101_0100,
0b1010_1010,
0b0000_0000,
]),
];
//eprintln!("Defining {} chars", chars.len());
//eprintln!("Def: {chars:?}");
out.write_all(b"\x1BP1;1;1{@").unwrap();
if let Some((first, rest)) = chars.split_first() {
out.write_all(first).unwrap();
for ch in rest {
out.write_all(b";").unwrap();
out.write_all(ch).unwrap();
}
}
out.write_all(b"\x1B\\").unwrap();
}
fn chardef(bits: [u8; 10]) -> [u8;17] {
let mut result = [0;17];
for y in 0..6 {
for x in 0..8 {
if bits[y] & (0b10000000 >> x) > 0 {
result[x] |= 1 << y;
}
}
}
for y in 0..4 {
for x in 0..8 {
if bits[y+6] & (0b10000000 >> x) > 0 {
result[9 + x] |= 1 << y;
}
}
}
for c in &mut result {
*c += b'?';
}
result[8] = b'/';
//eprintln!("chardef2: {}", String::from_utf8_lossy(&result));
result
}
fn pixel(i: u8) -> u8 {
CHARS[usize::from(i)]
// u32::from_be_bytes([0xff, i * 6, i + i / 2, i.saturating_mul(8)])
}
fn julia(z: Complex32, c: Complex32, max_i: u8) -> u8 {