1#![allow(dead_code)]
6
7use std::f32::consts::PI;
8use std::fs::File;
9use std::io::Read;
10
11pub type Int = isize;
12pub type Float = f32;
13
14static EARTH_TEXTURE: &str = include_str!("../textures/earth.txt");
15static EARTH_NIGHT_TEXTURE: &str = include_str!("../textures/earth_night.txt");
16
17pub struct Texture {
19 day: Vec<Vec<char>>,
20 night: Option<Vec<Vec<char>>>,
21 palette: Option<Vec<char>>,
22}
23
24impl Texture {
25 pub fn new(
26 day: Vec<Vec<char>>,
27 night: Option<Vec<Vec<char>>>,
28 palette: Option<Vec<char>>,
29 ) -> Self {
30 Texture {
31 day,
32 night,
33 palette,
34 }
35 }
36 pub fn get_size(&self) -> (usize, usize) {
37 (self.day[0].len() - 1, self.day.len() - 1)
38 }
39}
40
41pub struct Canvas {
43 pub matrix: Vec<Vec<char>>,
44 size: (usize, usize),
45 pub char_pix: (usize, usize),
47}
48
49impl Canvas {
50 pub fn new(x: u16, y: u16, cp: Option<(usize, usize)>) -> Self {
51 let x = x as usize;
52 let y = y as usize;
53
54 let matrix = vec![vec![' '; x]; y];
55
56 Self {
57 size: (x, y),
58 matrix,
59 char_pix: cp.unwrap_or((4, 8)),
60 }
61 }
62 pub fn get_size(&self) -> (usize, usize) {
63 self.size
64 }
65 pub fn clear(&mut self) {
66 for i in self.matrix.iter_mut().flatten() {
67 *i = ' ';
68 }
69 }
70 fn draw_point(&mut self, a: usize, b: usize, c: char) {
71 if a >= self.size.0 || b >= self.size.1 {
72 return;
73 }
74 self.matrix[b][a] = c;
75 }
76}
77
78pub struct Globe {
80 pub camera: Camera,
81 pub radius: Float,
82 pub angle: Float,
83 pub texture: Texture,
84 pub display_night: bool,
85}
86
87impl Globe {
88 pub fn render_on(&self, canvas: &mut Canvas) {
89 let light: [Float; 3] = [0., 999999., 0.];
91 let (size_x, size_y) = canvas.get_size();
93 for yi in 0..size_y {
94 let yif = yi as Int;
95 for xi in 0..size_x {
96 let xif = xi as Int;
97 let o: [Float; 3] = [self.camera.x, self.camera.y, self.camera.z];
99 let mut u: [Float; 3] = [
101 -((xif - (size_x / canvas.char_pix.0 / 2) as Int) as Float + 0.5)
102 / (size_x / canvas.char_pix.0 / 2) as Float,
103 ((yif - (size_y / canvas.char_pix.1 / 2) as Int) as Float + 0.5)
104 / (size_y / canvas.char_pix.1 / 2) as Float,
105 -1.,
106 ];
107 transform_vector(&mut u, self.camera.matrix);
108 u[0] -= self.camera.x;
109 u[1] -= self.camera.y;
110 u[2] -= self.camera.z;
111 normalize(&mut u);
112 let dot_uo = dot(&u, &o);
113 let discriminant: Float = dot_uo * dot_uo - dot(&o, &o) + self.radius * self.radius;
114
115 if discriminant < 0. {
117 continue;
118 }
119
120 let distance: Float = -discriminant.sqrt() - dot_uo;
121
122 let inter: [Float; 3] = [
124 o[0] + distance * u[0],
125 o[1] + distance * u[1],
126 o[2] + distance * u[2],
127 ];
128
129 let mut n: [Float; 3] = [
131 o[0] + distance * u[0],
132 o[1] + distance * u[1],
133 o[2] + distance * u[2],
134 ];
135 normalize(&mut n);
136
137 let mut l: [Float; 3] = [0.; 3];
139 vector(&mut l, &inter, &light);
140 normalize(&mut l);
141 let luminance: Float = clamp(5. * (dot(&n, &l)) + 0.5, 0., 1.);
142 let mut temp: [Float; 3] = [inter[0], inter[1], inter[2]];
143 rotate_x(&mut temp, -PI * 2. * 0. / 360.);
144
145 let phi: Float = -temp[2] / self.radius / 2. + 0.5;
147 let mut theta: Float = (temp[1] / temp[0]).atan() / PI + 0.5 + self.angle / 2. / PI;
148 theta -= theta.floor();
150 let (tex_x, tex_y) = self.texture.get_size();
151 let earth_x = (theta * tex_x as Float) as usize;
152 let earth_y = (phi * tex_y as Float) as usize;
153
154 if self.display_night
156 && self.texture.night.is_some()
157 && self.texture.palette.is_some()
158 {
159 let palette = self.texture.palette.as_ref().unwrap();
160 let day = find_index(self.texture.day[earth_y][earth_x], palette);
161 let night = find_index(
162 self.texture.night.as_ref().unwrap()[earth_y][earth_x],
163 palette,
164 );
165
166 let mut index =
167 ((1.0 - luminance) * night as Float + luminance * day as Float) as usize;
168 if index >= palette.len() {
169 index = 0;
170 }
171 canvas.draw_point(xi, yi, palette[index]);
172 }
173 else {
175 canvas.draw_point(xi, yi, self.texture.day[earth_y][earth_x]);
176 }
177 }
178 }
179 }
180}
181
182#[derive(Default)]
184pub struct GlobeConfig {
185 camera_cfg: Option<CameraConfig>,
186 radius: Option<Float>,
187 angle: Option<Float>,
188 template: Option<GlobeTemplate>,
189 texture: Option<Texture>,
190 display_night: bool,
191}
192
193impl GlobeConfig {
194 pub fn new() -> Self {
196 Self::default()
197 }
198
199 pub fn with_camera(mut self, config: CameraConfig) -> Self {
201 self.camera_cfg = Some(config);
202 self
203 }
204
205 pub fn with_radius(mut self, r: Float) -> Self {
207 self.radius = Some(r);
208 self
209 }
210
211 pub fn use_template(mut self, t: GlobeTemplate) -> Self {
213 self.template = Some(t);
214 self
215 }
216
217 pub fn with_texture(mut self, texture: &str, palette: Option<Vec<char>>) -> Self {
219 let mut day = Vec::new();
220 let lines = texture.lines();
221 for line in lines {
222 let row: Vec<char> = line.chars().rev().collect();
223 day.push(row);
224 }
225 if let Some(texture) = &mut self.texture {
226 texture.day = day;
227 } else {
228 self.texture = Some(Texture::new(day, None, palette));
229 }
230 self
231 }
232
233 pub fn with_night_texture(mut self, texture: &str, palette: Option<Vec<char>>) -> Self {
235 let mut night = Vec::new();
236 let lines = texture.lines();
237 for line in lines {
238 let row: Vec<char> = line.chars().rev().collect();
239 night.push(row);
240 }
241
242 if let Some(texture) = &mut self.texture {
243 texture.night = Some(night);
244 } else {
245 self.texture = Some(Texture::new(night.clone(), Some(night), palette));
246 }
247
248 self
249 }
250
251 pub fn with_texture_at(self, path: &str, palette: Option<Vec<char>>) -> Self {
253 let mut file = File::open(path).unwrap();
254 let mut out_string = String::new();
255 file.read_to_string(&mut out_string).unwrap();
256 self.with_texture(&out_string, palette)
257 }
258
259 pub fn display_night(mut self, b: bool) -> Self {
261 self.display_night = b;
262 self
263 }
264
265 pub fn build(mut self) -> Globe {
267 if let Some(template) = &self.template {
268 match template {
269 GlobeTemplate::Earth => {
270 let palette = vec![
271 ' ', '.', ':', ';', '\'', ',', 'w', 'i', 'o', 'g', 'O', 'L', 'X', 'H', 'W',
272 'Y', 'V', '@',
273 ];
274 self = self
275 .with_texture(EARTH_TEXTURE, Some(palette.clone()))
276 .with_night_texture(EARTH_NIGHT_TEXTURE, Some(palette))
277 }
278 }
279 }
280 let texture = self.texture.expect("texture not provided");
281 let camera = self
282 .camera_cfg
283 .unwrap_or_else(CameraConfig::default)
284 .build();
285 Globe {
286 camera,
287 radius: self.radius.unwrap_or(1.),
288 angle: self.angle.unwrap_or(0.),
289 texture,
290 display_night: self.display_night,
291 }
292 }
293}
294
295pub enum GlobeTemplate {
297 Earth,
298 }
301
302pub struct CameraConfig {
304 radius: Float,
305 alpha: Float,
306 beta: Float,
307}
308
309impl CameraConfig {
310 pub fn new(radius: Float, alpha: Float, beta: Float) -> Self {
318 Self {
319 radius,
320 alpha,
321 beta,
322 }
323 }
324
325 pub fn default() -> Self {
327 Self {
328 radius: 2.,
329 alpha: 0.,
330 beta: 0.,
331 }
332 }
333
334 pub fn build(&self) -> Camera {
336 let mut camera = Camera::default();
337 camera.update(self.radius, self.alpha, self.beta);
338 camera
339 }
340}
341
342#[derive(Default)]
343pub struct Camera {
344 x: Float,
345 y: Float,
346 z: Float,
347 matrix: [Float; 16],
348 inv: [Float; 16],
349}
350
351impl Camera {
352 pub fn update(&mut self, r: Float, alpha: Float, beta: Float) {
354 let sin_a = alpha.sin();
355 let cos_a = alpha.cos();
356 let sin_b = beta.sin();
357 let cos_b = beta.cos();
358
359 let x = r * cos_a * cos_b;
360 let y = r * sin_a * cos_b;
361 let z = r * sin_b;
362
363 let mut matrix = [0.; 16];
364
365 matrix[3] = 0.;
367 matrix[7] = 0.;
368 matrix[11] = 0.;
369 matrix[15] = 1.;
370 matrix[0] = -sin_a;
372 matrix[1] = cos_a;
373 matrix[2] = 0.;
374 matrix[4] = cos_a * sin_b;
376 matrix[5] = sin_a * sin_b;
377 matrix[6] = -cos_b;
378 matrix[8] = cos_a * cos_b;
380 matrix[9] = sin_a * cos_b;
381 matrix[10] = sin_b;
382
383 matrix[12] = x;
384 matrix[13] = y;
385 matrix[14] = z;
386
387 let mut inv = [0.; 16];
388 invert(&mut inv, matrix);
389
390 self.x = x;
391 self.y = y;
392 self.z = z;
393 self.matrix = matrix;
394 self.inv = inv;
395 }
396}
397
398fn find_index(target: char, palette: &[char]) -> Int {
400 for (i, &ch) in palette.iter().enumerate() {
401 if target == ch {
402 return i as Int;
403 }
404 }
405 -1
406}
407
408fn transform_vector(vec: &mut [Float; 3], m: [Float; 16]) {
409 let tx: Float = vec[0] * m[0] + vec[1] * m[4] + vec[2] * m[8] + m[12];
410 let ty: Float = vec[0] * m[1] + vec[1] * m[5] + vec[2] * m[9] + m[13];
411 let tz: Float = vec[0] * m[2] + vec[1] * m[6] + vec[2] * m[10] + m[14];
412 vec[0] = tx;
413 vec[1] = ty;
414 vec[2] = tz;
415}
416
417fn invert(inv: &mut [Float; 16], matrix: [Float; 16]) {
418 inv[0] = matrix[5] * matrix[10] * matrix[15]
419 - matrix[5] * matrix[11] * matrix[14]
420 - matrix[9] * matrix[6] * matrix[15]
421 + matrix[9] * matrix[7] * matrix[14]
422 + matrix[13] * matrix[6] * matrix[11]
423 - matrix[13] * matrix[7] * matrix[10];
424
425 inv[4] = -matrix[4] * matrix[10] * matrix[15]
426 + matrix[4] * matrix[11] * matrix[14]
427 + matrix[8] * matrix[6] * matrix[15]
428 - matrix[8] * matrix[7] * matrix[14]
429 - matrix[12] * matrix[6] * matrix[11]
430 + matrix[12] * matrix[7] * matrix[10];
431
432 inv[8] = matrix[4] * matrix[9] * matrix[15]
433 - matrix[4] * matrix[11] * matrix[13]
434 - matrix[8] * matrix[5] * matrix[15]
435 + matrix[8] * matrix[7] * matrix[13]
436 + matrix[12] * matrix[5] * matrix[11]
437 - matrix[12] * matrix[7] * matrix[9];
438
439 inv[12] = -matrix[4] * matrix[9] * matrix[14]
440 + matrix[4] * matrix[10] * matrix[13]
441 + matrix[8] * matrix[5] * matrix[14]
442 - matrix[8] * matrix[6] * matrix[13]
443 - matrix[12] * matrix[5] * matrix[10]
444 + matrix[12] * matrix[6] * matrix[9];
445
446 inv[1] = -matrix[1] * matrix[10] * matrix[15]
447 + matrix[1] * matrix[11] * matrix[14]
448 + matrix[9] * matrix[2] * matrix[15]
449 - matrix[9] * matrix[3] * matrix[14]
450 - matrix[13] * matrix[2] * matrix[11]
451 + matrix[13] * matrix[3] * matrix[10];
452
453 inv[5] = matrix[0] * matrix[10] * matrix[15]
454 - matrix[0] * matrix[11] * matrix[14]
455 - matrix[8] * matrix[2] * matrix[15]
456 + matrix[8] * matrix[3] * matrix[14]
457 + matrix[12] * matrix[2] * matrix[11]
458 - matrix[12] * matrix[3] * matrix[10];
459
460 inv[9] = -matrix[0] * matrix[9] * matrix[15]
461 + matrix[0] * matrix[11] * matrix[13]
462 + matrix[8] * matrix[1] * matrix[15]
463 - matrix[8] * matrix[3] * matrix[13]
464 - matrix[12] * matrix[1] * matrix[11]
465 + matrix[12] * matrix[3] * matrix[9];
466
467 inv[13] = matrix[0] * matrix[9] * matrix[14]
468 - matrix[0] * matrix[10] * matrix[13]
469 - matrix[8] * matrix[1] * matrix[14]
470 + matrix[8] * matrix[2] * matrix[13]
471 + matrix[12] * matrix[1] * matrix[10]
472 - matrix[12] * matrix[2] * matrix[9];
473
474 inv[2] = matrix[1] * matrix[6] * matrix[15]
475 - matrix[1] * matrix[7] * matrix[14]
476 - matrix[5] * matrix[2] * matrix[15]
477 + matrix[5] * matrix[3] * matrix[14]
478 + matrix[13] * matrix[2] * matrix[7]
479 - matrix[13] * matrix[3] * matrix[6];
480
481 inv[6] = -matrix[0] * matrix[6] * matrix[15]
482 + matrix[0] * matrix[7] * matrix[14]
483 + matrix[4] * matrix[2] * matrix[15]
484 - matrix[4] * matrix[3] * matrix[14]
485 - matrix[12] * matrix[2] * matrix[7]
486 + matrix[12] * matrix[3] * matrix[6];
487
488 inv[10] = matrix[0] * matrix[5] * matrix[15]
489 - matrix[0] * matrix[7] * matrix[13]
490 - matrix[4] * matrix[1] * matrix[15]
491 + matrix[4] * matrix[3] * matrix[13]
492 + matrix[12] * matrix[1] * matrix[7]
493 - matrix[12] * matrix[3] * matrix[5];
494
495 inv[14] = -matrix[0] * matrix[5] * matrix[14]
496 + matrix[0] * matrix[6] * matrix[13]
497 + matrix[4] * matrix[1] * matrix[14]
498 - matrix[4] * matrix[2] * matrix[13]
499 - matrix[12] * matrix[1] * matrix[6]
500 + matrix[12] * matrix[2] * matrix[5];
501
502 inv[3] = -matrix[1] * matrix[6] * matrix[11]
503 + matrix[1] * matrix[7] * matrix[10]
504 + matrix[5] * matrix[2] * matrix[11]
505 - matrix[5] * matrix[3] * matrix[10]
506 - matrix[9] * matrix[2] * matrix[7]
507 + matrix[9] * matrix[3] * matrix[6];
508
509 inv[7] = matrix[0] * matrix[6] * matrix[11]
510 - matrix[0] * matrix[7] * matrix[10]
511 - matrix[4] * matrix[2] * matrix[11]
512 + matrix[4] * matrix[3] * matrix[10]
513 + matrix[8] * matrix[2] * matrix[7]
514 - matrix[8] * matrix[3] * matrix[6];
515
516 inv[11] = -matrix[0] * matrix[5] * matrix[11]
517 + matrix[0] * matrix[7] * matrix[9]
518 + matrix[4] * matrix[1] * matrix[11]
519 - matrix[4] * matrix[3] * matrix[9]
520 - matrix[8] * matrix[1] * matrix[7]
521 + matrix[8] * matrix[3] * matrix[5];
522
523 inv[15] = matrix[0] * matrix[5] * matrix[10]
524 - matrix[0] * matrix[6] * matrix[9]
525 - matrix[4] * matrix[1] * matrix[10]
526 + matrix[4] * matrix[2] * matrix[9]
527 + matrix[8] * matrix[1] * matrix[6]
528 - matrix[8] * matrix[2] * matrix[5];
529
530 let mut det: Float =
531 matrix[0] * inv[0] + matrix[1] * inv[4] + matrix[2] * inv[8] + matrix[3] * inv[12];
532
533 det = 1.0 / det;
534
535 for inv_i in inv.iter_mut() {
536 *inv_i *= det;
537 }
538}
539
540fn cross(r: &mut [Float; 3], a: [Float; 3], b: [Float; 3]) {
541 r[0] = a[1] * b[2] - a[2] * b[1];
542 r[1] = a[2] * b[0] - a[0] * b[2];
543 r[2] = a[0] * b[1] - a[1] * b[0];
544}
545
546fn magnitude(r: &[Float; 3]) -> Float {
547 dot(r, r).sqrt()
548}
549
550fn normalize(r: &mut [Float; 3]) {
551 let len: Float = magnitude(r);
552 r[0] /= len;
553 r[1] /= len;
554 r[2] /= len;
555}
556
557fn dot(a: &[Float; 3], b: &[Float; 3]) -> Float {
558 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
559}
560
561fn vector(a: &mut [Float; 3], b: &[Float; 3], c: &[Float; 3]) {
562 a[0] = b[0] - c[0];
563 a[1] = b[1] - c[1];
564 a[2] = b[2] - c[2];
565}
566
567fn transform_vector2(vec: &mut [Float; 3], m: &[Float; 9]) {
568 vec[0] = m[0] * vec[0] + m[1] * vec[1] + m[2] * vec[2];
569 vec[1] = m[3] * vec[0] + m[4] * vec[1] + m[5] * vec[2];
570 vec[2] = m[6] * vec[0] + m[7] * vec[1] + m[8] * vec[2];
571}
572
573fn rotate_x(vec: &mut [Float; 3], theta: Float) {
574 let a = theta.sin();
575 let b = theta.cos();
576 let m: [Float; 9] = [1., 0., 0., 0., b, -a, 0., a, b];
577 transform_vector2(vec, &m);
578}
579
580fn rotate_y(vec: &mut [Float; 3], theta: Float) {
581 let a = theta.sin();
582 let b = theta.cos();
583 let m: [Float; 9] = [b, 0., a, 0., 1., 0., -a, 0., b];
584 transform_vector2(vec, &m);
585}
586
587fn rotate_z(vec: &mut [Float; 3], theta: Float) {
588 let a = theta.sin();
589 let b = theta.cos();
590 let m: [Float; 9] = [b, -a, 0., a, b, 0., 0., 0., 1.];
591 transform_vector2(vec, &m);
592}
593
594fn clamp(mut x: Float, min: Float, max: Float) -> Float {
595 if x < min {
596 x = min;
597 } else if x > max {
598 x = max;
599 }
600 x
601}