summaryrefslogtreecommitdiffstats
path: root/emotes.py
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2022-11-26 17:08:09 -0800
committeryum <yum.food.vr@gmail.com>2022-11-26 17:13:36 -0800
commit480463b0578407a8f5a6585eb7018933e6ec7186 (patch)
tree2a11d8298aaca6169581008f225f7fcbcc70bae8 /emotes.py
parent89a929fe76e4dbd56436288055366d9416c13e74 (diff)
Add emotes
Add emotes.py. It accepts a list of images and creates a texture with 64 total embedded images. The shader knows how to draw these into fixed 6-character-wide slots. Each slot must be aligned to a 6-character boundary. osc_ctrl has to pad with spaces to make this work. This whole patch is a little more complicated than it has any right to be, but my brain feels fuzzy and I don't know where to start fixing it, so I'm going to leave it shitty-but-functional for now. There's also some bug where writing a character into the 11th slot causes it to show up at the end of the board. I'll figure that out later, idk. I didn't include any of the emotes I use since I couldn't find any info on their licenses. I'm just banking on having a good workflow later on so people can add their own.
Diffstat (limited to 'emotes.py')
-rw-r--r--emotes.py123
1 files changed, 123 insertions, 0 deletions
diff --git a/emotes.py b/emotes.py
new file mode 100644
index 0000000..0fd41d8
--- /dev/null
+++ b/emotes.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+
+import argparse
+from math import floor
+import os
+# python3 -m pip install pillow
+from PIL import Image
+import sys
+
+# (row, col)
+TEX_SZ = (2048, 2048)
+
+IMG_SZ_PX = 256
+IMG_PER_ROW = int(TEX_SZ[0] / IMG_SZ_PX)
+IMG_PER_COL = int(TEX_SZ[1] / IMG_SZ_PX)
+
+# TODO(yum) this should live in a config file.
+# Note: the name of the emote must be no longer than 6 characters.
+IMG_TEX_DATA = []
+IMG_TEX_DATA.append(("Images/Emotes/xdd.png", "xdd"))
+IMG_TEX_DATA.append(("Images/Emotes/pog.png", "pog"))
+IMG_TEX_DATA.append(("Images/Emotes/lulw.png", "laugh"))
+IMG_TEX_DATA.append(("Images/Emotes/bighardo.png", "hard"))
+IMG_TEX_DATA.append(("Images/Emotes/peepoHappy.png", "happy"))
+IMG_TEX_DATA.append(("Images/Emotes/peepoSad.png", "sad"))
+IMG_TEX_DATA.append(("Images/Emotes/bedge.png", "bed"))
+IMG_TEX_DATA.append(("Images/Emotes/reallymad.png", "mad"))
+
+IMG_TEX_KEYWORD_TO_COORD = {}
+for i in range(0, len(IMG_TEX_DATA)):
+ IMG_TEX_KEYWORD_TO_COORD[IMG_TEX_DATA[i][1]] = i
+
+# We treat images like words. To keep things simple, they're the same height as
+# a word, and they're a fixed width.
+IMG_SZ_LETTER_ROWS = 1
+IMG_SZ_LETTER_COLS = 6
+
+def lookup(word: str):
+ word = word.lower()
+ word = ''.join(c for c in word.lower() if c.isalpha())
+ if word in IMG_TEX_KEYWORD_TO_COORD.keys():
+ return word, IMG_TEX_KEYWORD_TO_COORD[word]
+ return None, None
+
+def openTexture(tex_path: str):
+ if not os.path.exists(args.texture_path):
+ return Image.new("RGB", TEX_SZ)
+ tex = Image.open(args.texture_path)
+ if tex.size != TEX_SZ:
+ print("Texture at {} has mismatching size {}, creating new texture".format(
+ tex_path, tex.size), file=sys.stderr)
+ return Image.new("RGB", TEX_SZ)
+ return tex
+
+# Add an image to the texture at the coordinates (x, y). x and y should be in
+# the range [0, IMG_PER_COL) and [0, IMG_PER_ROW) respectively.
+def addImageToTexture(tex: Image, img_path: str, x: int, y:int):
+ # Transparent images will be composited on top of a black background.
+ img = Image.open(img_path).convert('RGBA')
+ img_bg = Image.new('RGBA', img.size, (0, 0, 0))
+ img = Image.alpha_composite(img_bg, img).convert('RGB')
+
+ max_px = IMG_SZ_PX
+
+ # Scale the image up so it uses as much space as is given to it.
+ # I originally planned to support multiple scales, but this proved to be
+ # too much work - getting line wrapping to work with this would be a pain.
+ # So for now, all images are the same height as words.
+ scale = 1
+ img_x, img_y = img.size
+ max_dim = max(img_x, img_y)
+ img_scale = (max_px / max_dim) * scale
+ new_sz = (int(floor(img.size[0] * img_scale)),
+ int(floor(img.size[1] * img_scale)))
+ print("Original size: {}".format(img.size))
+ print("Scaled size: {}".format(new_sz))
+ img = img.resize(new_sz)
+
+ # Center the image within its new coordinate space.
+ padded_img_sz = (IMG_SZ_PX * scale, IMG_SZ_PX * scale)
+ padded_img = Image.new("RGB", padded_img_sz)
+ centered_x = int(floor((padded_img_sz[0] - new_sz[0]) / 2))
+ centered_y = int(floor((padded_img_sz[1] - new_sz[1]) / 2))
+ padded_img.paste(img, box=(centered_x, centered_y))
+ img = padded_img
+
+ # Break the image into tiles and write them into the texture.
+ for slot in range(0, scale * scale):
+ tile_x = slot % scale
+ tile_y = int(floor(slot / scale))
+ tile_bbox = (tile_x * IMG_SZ_PX, tile_y * IMG_SZ_PX, (tile_x + 1) * IMG_SZ_PX, (tile_y + 1) * IMG_SZ_PX)
+ tile = img.crop(tile_bbox)
+ print("tile {},{} (bbox={})".format(tile_x, tile_y, tile_bbox))
+
+ slot_x = x + slot % IMG_PER_ROW
+ slot_y = y + int(floor(slot / IMG_PER_ROW))
+ slot_x_px = slot_x * IMG_SZ_PX
+ slot_y_px = slot_y * IMG_SZ_PX
+ print("Add img at {},{} (px {},{})".format(slot_x, slot_y, slot_x_px, slot_y_px))
+
+ tex.paste(tile, box=(slot_x_px, slot_y_px))
+
+def parseArgs():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--texture_path", type=str, help="Path to save the generated texture.")
+ args = parser.parse_args()
+
+ if not args.texture_path:
+ args.texture_path = "img_texture.png"
+
+ return args
+
+if __name__ == "__main__":
+ args = parseArgs()
+
+ tex = openTexture(args.texture_path)
+ for i in range(0, len(IMG_TEX_DATA)):
+ filename = IMG_TEX_DATA[i][0]
+ x = i % IMG_PER_ROW
+ y = int(floor(i / IMG_PER_ROW))
+ addImageToTexture(tex, filename, x, y)
+ tex.save(args.texture_path)
+