From e0aee6375ece92f2613e45e470f83ec24609642c Mon Sep 17 00:00:00 2001
From: Stephen D <webmaster@scd31.com>
Date: Fri, 15 Oct 2021 22:55:20 -0300
Subject: [PATCH] Among us font with SUS

---
 Cargo.lock          |  93 +++++++++++++++++++++++--
 Cargo.toml          |   3 +-
 src/amongus.ttf     | Bin 0 -> 15576 bytes
 src/handlers/mod.rs |   3 +
 src/handlers/sus.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 252 insertions(+), 7 deletions(-)
 create mode 100644 src/amongus.ttf
 create mode 100644 src/handlers/sus.rs

diff --git a/Cargo.lock b/Cargo.lock
index ab6188d..ad41dd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,7 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+version = 3
+
 [[package]]
 name = "adler"
 version = "0.2.3"
@@ -12,6 +14,15 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 
+[[package]]
+name = "arrayvec"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
+dependencies = [
+ "nodrop",
+]
+
 [[package]]
 name = "async-trait"
 version = "0.1.41"
@@ -65,7 +76,7 @@ checksum = "1374191e2dd25f9ae02e3aa95041ed5d747fc77b3c102b49fe2dd9a8117a6244"
 dependencies = [
  "num-bigint",
  "num-integer",
- "num-traits",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -111,6 +122,7 @@ dependencies = [
  "phf",
  "png",
  "reqwest",
+ "rusttype",
  "serde",
  "serde_json",
  "serenity",
@@ -145,7 +157,7 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
 dependencies = [
  "libc",
  "num-integer",
- "num-traits",
+ "num-traits 0.2.14",
  "serde",
  "time",
  "winapi 0.3.9",
@@ -204,7 +216,7 @@ dependencies = [
  "diesel_derives",
  "num-bigint",
  "num-integer",
- "num-traits",
+ "num-traits 0.2.14",
  "pq-sys",
 ]
 
@@ -775,6 +787,12 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "nodrop"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
+
 [[package]]
 name = "num-bigint"
 version = "0.2.6"
@@ -783,7 +801,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
 dependencies = [
  "autocfg",
  "num-integer",
- "num-traits",
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -804,7 +822,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
 dependencies = [
  "autocfg",
- "num-traits",
+ "num-traits 0.2.14",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
+dependencies = [
+ "num-traits 0.2.14",
 ]
 
 [[package]]
@@ -871,6 +898,16 @@ dependencies = [
  "vcpkg",
 ]
 
+[[package]]
+name = "ordered-float"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
+dependencies = [
+ "num-traits 0.1.43",
+ "unreachable",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.1.0"
@@ -1231,6 +1268,17 @@ dependencies = [
  "webpki",
 ]
 
+[[package]]
+name = "rusttype"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ff03da02f6d340bbee5ec55eed03ff9abd6ea013b93bc7c35973cc28f65999"
+dependencies = [
+ "arrayvec",
+ "ordered-float",
+ "stb_truetype 0.2.8",
+]
+
 [[package]]
 name = "ryu"
 version = "1.0.5"
@@ -1405,6 +1453,24 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
+[[package]]
+name = "stb_truetype"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d"
+dependencies = [
+ "stb_truetype 0.3.1",
+]
+
+[[package]]
+name = "stb_truetype"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51"
+dependencies = [
+ "byteorder",
+]
+
 [[package]]
 name = "syn"
 version = "0.15.44"
@@ -1663,6 +1729,15 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
 
+[[package]]
+name = "unreachable"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+dependencies = [
+ "void",
+]
+
 [[package]]
 name = "untrusted"
 version = "0.7.1"
@@ -1699,6 +1774,12 @@ version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
 
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
 [[package]]
 name = "want"
 version = "0.3.0"
@@ -1887,6 +1968,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ff711e02a0840644b63e9906fd12bc15e7346f08531467b3962b3ed712bdd6ba"
 dependencies = [
  "num-derive",
- "num-traits",
+ "num-traits 0.2.14",
  "phf",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index c738368..3d6dc6b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,5 @@ diesel = { version = "1.4", features = ["postgres", "numeric"] }
 dotenv = "0.15.0"
 bigdecimal = "0.1.2"
 reqwest = { version = "0.10", features = ["json"] }
-serde_json = "1.0"
\ No newline at end of file
+serde_json = "1.0"
+rusttype = "0.4.3"
diff --git a/src/amongus.ttf b/src/amongus.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..359054c46a43ce71ef78e3d43397d20d14a49946
GIT binary patch
literal 15576
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

literal 0
HcmV?d00001

diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs
index 730a63e..f02fdb0 100644
--- a/src/handlers/mod.rs
+++ b/src/handlers/mod.rs
@@ -1,9 +1,11 @@
 mod joke;
 mod react;
+mod sus;
 mod xbasic;
 
 use crate::handlers::joke::*;
 use crate::handlers::react::*;
+use crate::handlers::sus::*;
 use crate::handlers::xbasic::*;
 
 use serenity::async_trait;
@@ -46,6 +48,7 @@ impl Default for Dispatcher {
 				Box::new(XbasicHandler::default()),
 				Box::new(JokeHandler::default()),
 				Box::new(ReactHandler::default()),
+				Box::new(SusHandler::default()),
 			],
 		}
 	}
diff --git a/src/handlers/sus.rs b/src/handlers/sus.rs
new file mode 100644
index 0000000..82856b0
--- /dev/null
+++ b/src/handlers/sus.rs
@@ -0,0 +1,160 @@
+use crate::framebuffer::FrameBuffer;
+use crate::handlers::LineHandler;
+use rusttype::LayoutIter;
+use rusttype::{point, FontCollection, Scale};
+use serenity::async_trait;
+use serenity::http::AttachmentType;
+use serenity::model::channel::Message;
+use serenity::prelude::*;
+use std::borrow::Cow;
+
+const COLOUR: (u8, u8, u8) = (255, 0, 0);
+const SCALE: Scale = Scale { x: 48.0, y: 48.0 };
+const PADDING_X: u32 = 0;
+const PADDING_Y: u32 = 0;
+const MAX_WIDTH: i32 = 800;
+const Y_GAP: i32 = 5;
+
+// Wrap text when width exceeds MAX_WIDTH
+struct WrappingLayoutIter<'a> {
+	iter: LayoutIter<'a, 'a>,
+	offset_x: i32,
+	offset_y: i32,
+	cur_x: i32,
+	cur_y: i32,
+}
+
+impl<'a> WrappingLayoutIter<'a> {
+	fn new(iter: LayoutIter<'a, 'a>, offset_x: i32, offset_y: i32) -> Self {
+		Self {
+			iter,
+			offset_x,
+			offset_y,
+			cur_x: 0,
+			cur_y: 0,
+		}
+	}
+}
+
+impl<'a> Iterator for WrappingLayoutIter<'a> {
+	type Item = Vec<(i32, i32, f32)>;
+
+	fn next(&mut self) -> Option<Self::Item> {
+		let (glyph, bounding_box) = loop {
+			let glyph = self.iter.next()?;
+			if let Some(bb) = glyph.pixel_bounding_box() {
+				break (glyph, bb);
+			}
+		};
+
+		if bounding_box.max.x + self.cur_x > MAX_WIDTH {
+			self.cur_x = -bounding_box.min.x;
+			self.cur_y += bounding_box.max.y - bounding_box.min.y + Y_GAP;
+		}
+
+		let mut buf = Vec::new();
+
+		glyph.draw(|x, y, a| {
+			let x = x as i32 + bounding_box.min.x + self.offset_x + self.cur_x;
+			let y = y as i32 + bounding_box.min.y + self.offset_y + self.cur_y;
+
+			buf.push((x, y, a));
+		});
+
+		Some(buf)
+	}
+}
+
+#[derive(Default)]
+pub struct SusHandler;
+
+impl SusHandler {
+	async fn render_font(&self, ctx: &Context, msg: &Message, s: &str) {
+		let font_data = include_bytes!("../amongus.ttf");
+		let collection = FontCollection::from_bytes(font_data as &[u8]);
+		let font = collection.into_font().unwrap();
+
+		let start = point(0.0, 0.0);
+
+		// Find image dimensions
+		let mut min_x = 0;
+		let mut max_x = 0;
+		let mut max_y = 0;
+		let mut min_y = 0;
+		for arr in WrappingLayoutIter::new(font.layout(s, SCALE, start), 0, 0) {
+			for (x, y, _) in arr {
+				if x < min_x {
+					min_x = x;
+				}
+
+				if x > max_x {
+					max_x = x;
+				}
+
+				if y < min_y {
+					min_y = y;
+				}
+
+				if y > max_y {
+					max_y = y;
+				}
+			}
+		}
+
+		let offset_x = -min_x;
+		let offset_y = -min_y;
+		max_x += offset_x;
+		max_y += offset_y;
+
+		let mut framebuffer =
+			FrameBuffer::new(max_x as u32 + PADDING_X * 2, max_y as u32 + PADDING_Y * 2);
+
+		for arr in WrappingLayoutIter::new(
+			font.layout(s, SCALE, start),
+			offset_x + PADDING_X as i32,
+			offset_y + PADDING_Y as i32,
+		) {
+			for (x, y, a) in arr {
+				framebuffer.set_pixel(
+					x as u32,
+					y as u32,
+					COLOUR.0,
+					COLOUR.1,
+					COLOUR.2,
+					(a * 255.0) as u8,
+				);
+			}
+		}
+
+		let buf = framebuffer.as_png_vec();
+
+		msg.channel_id
+			.send_message(&ctx, |e| {
+				e.add_file(AttachmentType::Bytes {
+					data: Cow::Borrowed(&buf),
+					filename: "output.png".to_string(),
+				});
+
+				e
+			})
+			.await
+			.unwrap();
+	}
+}
+
+#[async_trait]
+impl LineHandler for SusHandler {
+	async fn line(&self, ctx: &Context, msg: &Message, line: &str) {
+		if line.starts_with("!SUS") {
+			let s = line.split(' ').collect::<Vec<_>>()[1..]
+				.join(" ")
+				.to_uppercase();
+
+			if s.is_empty() {
+				return;
+			}
+
+			self.render_font(ctx, msg, &s).await;
+		}
+	}
+}
-- 
GitLab