pax_global_header00006660000000000000000000000064152014060410014503gustar00rootroot0000000000000052 comment=219fe7d3a7168a2fd79bd19a6561e77b8dc0e289 arcadefont-1.0/000077500000000000000000000000001520140604100134515ustar00rootroot00000000000000arcadefont-1.0/.Rbuildignore000066400000000000000000000000651520140604100161000ustar00rootroot00000000000000^.*\.Rproj$ ^\.Rproj\.user$ ^README\.Rmd$ ^data-raw$ arcadefont-1.0/.gitignore000066400000000000000000000001261520140604100154400ustar00rootroot00000000000000.DS_Store .Rhistory *.Rproj .Rproj.user *.swp *.txt inst/doc doc Meta pkgdown working arcadefont-1.0/DESCRIPTION000066400000000000000000000004751520140604100151650ustar00rootroot00000000000000Package: arcadefont Type: Package Title: Raw Vector Data for Arcade Vector Font Version: 0.1.0 Author: mikefc Maintainer: mikefc Description: Raw vector data for an arcade vector font. License: MIT + file LICENSE Encoding: UTF-8 LazyData: true Depends: R (>= 2.10) RoxygenNote: 7.1.0 arcadefont-1.0/LICENSE000066400000000000000000000020651520140604100144610ustar00rootroot00000000000000Copyright (c) 2020 mikefc@coolbutuseless.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. arcadefont-1.0/NAMESPACE000066400000000000000000000001051520140604100146640ustar00rootroot00000000000000# Generated by roxygen2: do not edit by hand export(create_text_df) arcadefont-1.0/NEWS.md000066400000000000000000000000461520140604100145470ustar00rootroot00000000000000# arcadefont 0.1.0 * Initial release arcadefont-1.0/R/000077500000000000000000000000001520140604100136525ustar00rootroot00000000000000arcadefont-1.0/R/arcade.R000066400000000000000000000003371520140604100152170ustar00rootroot00000000000000 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Data.frame of Arcade vector font information #' #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "arcade_df" arcadefont-1.0/R/string.R000066400000000000000000000073771520140604100153210ustar00rootroot00000000000000 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Create data.frame of glyph information for the given line of text. #' #' @param text text string #' @param dx character spacing in original units #' #' @return data.frame with coordinates for all the glyphs with characters offset #' appropriately. \code{char_idx} is the index of the character within #' the given text string #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ create_text_df_single_row <- function(text, dx = 2) { stopifnot(length(text) == 1) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # split text into characters #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ text <- toupper(text) text <- strsplit(text, '')[[1]] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Replace any unknown chars with a blank space #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bad_idx <- !(text %in% arcadefont::arcade_df$letter) text[bad_idx] <- ' ' #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Merge the text info with the data.frame for each character from `arcade_df` #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string_df <- data.frame( letter = text, char_idx = seq_along(text), stringsAsFactors = FALSE ) string_df <- merge(string_df, arcadefont::arcade_df, sort = FALSE, all.x = TRUE) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Offset characters in the x direction so they don't overlap #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string_df <- with(string_df, string_df[order(char_idx, stroke, idx),]) string_df$x <- string_df$x + (string_df$char_idx - 1) * (8 + dx) string_df } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Create data.frame of glyph information for the given text. #' #' Text input can contain multiple lines separated by carriage returns #' #' @param text single character string #' @param dx,dy character spacing in original units #' #' @return data.frame with coordinates for all the glyphs with characters offset #' appropriately. \code{char_idx} is the index of the character within #' the given text string #' #' @export #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ create_text_df <- function(text, dx = 2, dy = 2) { stopifnot(length(text) == 1) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Split the text at "\n" boundaries #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ texts <- strsplit(text, "\n")[[1]] nchars <- cumsum(nchar(texts)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create a string for each line #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dfs <- lapply(texts, create_text_df_single_row, dx = dx) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Update line numbering and character indices #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ for (i in seq_along(dfs)) { if (nrow(dfs[[i]]) == 0) next dfs[[i]]$line <- i if (i > 1) { dfs[[i]]$char_idx <- dfs[[i]]$char_idx + nchars[i-1] } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # combined all data.frames for each line, offset the y for each line #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ res <- do.call(rbind, dfs) res$y <- res$y - (res$line - 1) * (8 + dy) res } arcadefont-1.0/README.Rmd000066400000000000000000000130571520140604100150600ustar00rootroot00000000000000--- output: github_document --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" ) library(dplyr) library(ggplot2) library(arcadefont) ``` # arcadefont ![](http://img.shields.io/badge/cool-useless-green.svg) `arcadefont` provides raw vector data for an 80s arcade vector font - similar to that seen in [Battlezone](https://en.wikipedia.org/wiki/Battlezone_(1980_video_game)) or [Star Wars](https://en.wikipedia.org/wiki/Star_Wars_(1983_video_game)). It is a fixed-width, caps-only font. This package was released on "May the 4th" 2020 - i.e. "Star Wars Day". This is similar to the [hershey vector font package](https://github.com/coolbutuseless/hershey) in that it provides point and stroke information, but how this is actually rendered is up to you. In the examples below `ggplot` is used to render the strokes for each glyphs as `geom_path` objects. ## What's in the box? * `arcade_df` - a data.frame of coordinates and stroke information for all the provided glyphs. * `create_text_df()` - a function to create stroke information for all the characters in a given string, and offset them appropriately (vertically and horizontally) so that they are ready to render. ## Installation You can install from [GitHub](https://github.com/coolbutuseless/arcadefont) with: ``` r # install.packages("remotes") remotes::install_github("coolbutuseless/arcadefont") ``` ## Vector data source - `arcade_df` The following output shows the data for the letter `A` contained in the `arcade_df` data.frame. * letter - character represented in this data, in this case "A" * stroke - grouping variable for the points belonging to the same stroke. The letter 'A' is made of 2 strokes: 1. the frame of the A shape 2. the crossbar. * x,y - coordinates of points which make up a stroke. Coordinates are integer locations on a 9x9 grid. * idx - ordering index of points within each stroke ```{r} arcadefont::arcade_df %>% filter(letter == 'A') %>% knitr::kable() ``` ## Font Sample Sheet A rendering of all the glyphs represented in `arcade_df`. ```{r onesheet, warning = FALSE, message = FALSE} library(ggplot2) library(arcadefont) ggplot(arcadefont::arcade_df, aes(x, y)) + geom_path(aes(group=stroke)) + coord_fixed() + theme_void() + facet_wrap(~letter) + theme( strip.background = element_blank(), strip.text.x = element_blank() ) ``` ## Create data for sequences of characters A simple way to create all the strokes for lines of text is to use `create_text_df()`. This function will offset the characters along a row of text, and arrange the characters over multiple lines. ```{r simple, fig.height=2} text <- "Hello #RStats!\n@coolbutuseless" text_df <- arcadefont::create_text_df(text, dx = 2, dy = 3) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Plot it! #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ggplot(text_df, aes(x, y)) + geom_path(aes(group=interaction(char_idx, stroke))) + coord_fixed() + theme_void() ``` ## Recreation of instructions screen for "Star Wars - The Arcade Game" Star Wars is a 3D vector graphics arcade game released in 1983. See more on [wikipedia](https://en.wikipedia.org/wiki/Star_Wars_(1983_video_game)) and [playthrough video](https://www.youtube.com/watch?v=EA_kDTwZodQ). When running in 'attract mode' the arcade machine displayed information such as the high score table and instructions for playing. Here I've recreated the instructions screen - colours too! ```{r starwars} library(dplyr) library(ggplot2) library(arcadefont) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Full text of the instructions screen #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ text <- " score 0 wave 00 game over 1 coin 1 play flight instructions to red five 1. your x-wing is equipped with an invisible deflector shield that will protect you for 8 collisions. 2. deflector strength is lost when a fireball impacts your shield or when you strike a laser tower or trench catwalk. 3. aim your lasers with cursor to explode empire tie fighters, laser tower tops and trench turrets. 4. shoot fireballs before they impact your shield. 5. the rebel force is depending on you to stop the empire by blowing up the death star." #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create the text in the arcade font and set some colours #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ text_df <- arcadefont::create_text_df(text, dx = 2, dy = 3) text_df <- text_df %>% mutate( colour = case_when( line == 2 & letter == '0' ~ 'green', line == 2 ~ 'red', line == 3 & letter == '0' ~ 'green', line == 3 ~ 'cyan', line == 4 ~ 'yellow', TRUE ~ 'red' ) ) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Plot it! #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ggplot(text_df, aes(x, y)) + geom_path(aes(group=interaction(char_idx, stroke), colour = I(colour))) + coord_fixed() + theme_void() + theme(panel.background = element_rect(fill = 'black')) ``` arcadefont-1.0/README.md000066400000000000000000000134301520140604100147310ustar00rootroot00000000000000 # arcadefont ![](http://img.shields.io/badge/cool-useless-green.svg) `arcadefont` provides raw vector data for an 80s arcade vector font - similar to that seen in [Battlezone](https://en.wikipedia.org/wiki/Battlezone_\(1980_video_game\)) or [Star Wars](https://en.wikipedia.org/wiki/Star_Wars_\(1983_video_game\)). It is a fixed-width, caps-only font. This package was released on “May the 4th” 2020 - i.e. “Star Wars Day”. This is similar to the [hershey vector font package](https://github.com/coolbutuseless/hershey) in that it provides point and stroke information, but how this is actually rendered is up to you. In the examples below `ggplot` is used to render the strokes for each glyphs as `geom_path` objects. ## What’s in the box? - `arcade_df` - a data.frame of coordinates and stroke information for all the provided glyphs. - `create_text_df()` - a function to create stroke information for all the characters in a given string, and offset them appropriately (vertically and horizontally) so that they are ready to render. ## Installation You can install from [GitHub](https://github.com/coolbutuseless/arcadefont) with: ``` r # install.packages("remotes") remotes::install_github("coolbutuseless/arcadefont") ``` ## Vector data source - `arcade_df` The following output shows the data for the letter `A` contained in the `arcade_df` data.frame. - letter - character represented in this data, in this case “A” - stroke - grouping variable for the points belonging to the same stroke. The letter ‘A’ is made of 2 strokes: 1. the frame of the A shape 2. the crossbar. - x,y - coordinates of points which make up a stroke. Coordinates are integer locations on a 9x9 grid. - idx - ordering index of points within each stroke ``` r arcadefont::arcade_df %>% filter(letter == 'A') %>% knitr::kable() ``` | letter | stroke | x | y | idx | | :----- | :----- | -: | -: | --: | | A | 1 | 0 | 0 | 1 | | A | 1 | 0 | 6 | 2 | | A | 1 | 4 | 8 | 3 | | A | 1 | 8 | 6 | 4 | | A | 1 | 8 | 0 | 5 | | A | 2 | 0 | 3 | 1 | | A | 2 | 8 | 3 | 2 | ## Font Sample Sheet A rendering of all the glyphs represented in `arcade_df`. ``` r library(ggplot2) library(arcadefont) ggplot(arcadefont::arcade_df, aes(x, y)) + geom_path(aes(group=stroke)) + coord_fixed() + theme_void() + facet_wrap(~letter) + theme( strip.background = element_blank(), strip.text.x = element_blank() ) ``` ## Create data for sequences of characters A simple way to create all the strokes for lines of text is to use `create_text_df()`. This function will offset the characters along a row of text, and arrange the characters over multiple lines. ``` r text <- "Hello #RStats!\n@coolbutuseless" text_df <- arcadefont::create_text_df(text, dx = 2, dy = 3) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Plot it! #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ggplot(text_df, aes(x, y)) + geom_path(aes(group=interaction(char_idx, stroke))) + coord_fixed() + theme_void() ``` ## Recreation of instructions screen for “Star Wars - The Arcade Game” Star Wars is a 3D vector graphics arcade game released in 1983. See more on [wikipedia](https://en.wikipedia.org/wiki/Star_Wars_\(1983_video_game\)) and [playthrough video](https://www.youtube.com/watch?v=EA_kDTwZodQ). When running in ‘attract mode’ the arcade machine displayed information such as the high score table and instructions for playing. Here I’ve recreated the instructions screen - colours too\! ``` r library(dplyr) library(ggplot2) library(arcadefont) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Full text of the instructions screen #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ text <- " score 0 wave 00 game over 1 coin 1 play flight instructions to red five 1. your x-wing is equipped with an invisible deflector shield that will protect you for 8 collisions. 2. deflector strength is lost when a fireball impacts your shield or when you strike a laser tower or trench catwalk. 3. aim your lasers with cursor to explode empire tie fighters, laser tower tops and trench turrets. 4. shoot fireballs before they impact your shield. 5. the rebel force is depending on you to stop the empire by blowing up the death star." #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create the text in the arcade font and set some colours #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ text_df <- arcadefont::create_text_df(text, dx = 2, dy = 3) text_df <- text_df %>% mutate( colour = case_when( line == 2 & letter == '0' ~ 'green', line == 2 ~ 'red', line == 3 & letter == '0' ~ 'green', line == 3 ~ 'cyan', line == 4 ~ 'yellow', TRUE ~ 'red' ) ) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Plot it! #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ggplot(text_df, aes(x, y)) + geom_path(aes(group=interaction(char_idx, stroke), colour = I(colour))) + coord_fixed() + theme_void() + theme(panel.background = element_rect(fill = 'black')) ``` arcadefont-1.0/data-raw/000077500000000000000000000000001520140604100151515ustar00rootroot00000000000000arcadefont-1.0/data-raw/Makefile000066400000000000000000000010611520140604100166070ustar00rootroot00000000000000PYTHON := python3 FONTFORGE := fontforge CONVERTER := convert_to_otf.py SFD_FILE := ArcadeFont.sfd OTF_FILE := ArcadeFont.otf # Default target .PHONY: all all: otf # Generate both SFD and OTF files .PHONY: otf otf: $(OTF_FILE) # Generate only SFD file .PHONY: sfd sfd: $(SFD_FILE) $(OTF_FILE): $(CONVERTER) $(PYTHON) $(CONVERTER) $(SFD_FILE): $(CONVERTER) $(PYTHON) -c "from convert_to_otf import generate_sfd_only; generate_sfd_only()" .PHONY: sfd-to-otf sfd-to-otf: $(SFD_FILE) $(FONTFORGE) -lang=ff -c 'Open("$(SFD_FILE)"); Generate("$(OTF_FILE)")' arcadefont-1.0/data-raw/convert_to_otf.py000066400000000000000000000250371520140604100205640ustar00rootroot00000000000000#!/usr/bin/env python3 """ Convert arcade font from R point data to OTF format via FontForge. Creates proper rectangular strokes for each line segment. """ import re import sys import math from pathlib import Path # Diacritical marks DIACRITICS = { 'dot_above': '39 49 48 38 39', 'diaeresis': '29 39 38 28 29 : 59 69 68 58 59', 'acute': '39 59', 'grave': '59 39', 'circumflex': '29 49 69', 'tilde': '29 39 49 59 69', 'ring': '39 49 48 38 39', 'cedilla': '40 30 20', 'ogonek': '70 60 50', 'caron': '69 49 29', 'stroke': '14 74', } # Extended Latin characters EXTENDED_LATIN = { 'Ä': ('A', 'diaeresis', -1), 'ä': ('a', 'diaeresis', -1), 'Ö': ('O', 'diaeresis', -1), 'ö': ('o', 'diaeresis', -1), 'Ü': ('U', 'diaeresis', -1), 'ü': ('u', 'diaeresis', -1), 'ß': ('B', None, 0), 'Å': ('A', 'ring', -1), 'å': ('a', 'ring', -1), 'Æ': ('A', None, 0), 'æ': ('a', None, 0), 'Ø': ('O', 'stroke', 0), 'ø': ('o', 'stroke', 0), 'À': ('A', 'grave', -1), 'à': ('a', 'grave', -1), 'Á': ('A', 'acute', -1), 'á': ('a', 'acute', -1), 'Â': ('A', 'circumflex', -1), 'â': ('a', 'circumflex', -1), 'É': ('E', 'acute', -1), 'é': ('e', 'acute', -1), 'È': ('E', 'grave', -1), 'è': ('e', 'grave', -1), 'Ê': ('E', 'circumflex', -1), 'ê': ('e', 'circumflex', -1), 'Ë': ('E', 'diaeresis', -1), 'ë': ('e', 'diaeresis', -1), 'Ï': ('I', 'diaeresis', -1), 'ï': ('i', 'diaeresis', -1), 'Î': ('I', 'circumflex', -1), 'î': ('i', 'circumflex', -1), 'Ô': ('O', 'circumflex', -1), 'ô': ('o', 'circumflex', -1), 'Ù': ('U', 'grave', -1), 'ù': ('u', 'grave', -1), 'Û': ('U', 'circumflex', -1), 'û': ('u', 'circumflex', -1), 'Ç': ('C', 'cedilla', 1), 'ç': ('c', 'cedilla', 1), 'Ñ': ('N', 'tilde', -1), 'ñ': ('n', 'tilde', -1), 'Ą': ('A', 'ogonek', 1), 'ą': ('a', 'ogonek', 1), 'Ć': ('C', 'acute', -1), 'ć': ('c', 'acute', -1), 'Ę': ('E', 'ogonek', 1), 'ę': ('e', 'ogonek', 1), 'Ł': ('L', 'stroke', 0), 'ł': ('l', 'stroke', 0), 'Ń': ('N', 'acute', -1), 'ń': ('n', 'acute', -1), 'Ó': ('O', 'acute', -1), 'ó': ('o', 'acute', -1), 'Ś': ('S', 'acute', -1), 'ś': ('s', 'acute', -1), 'Ź': ('Z', 'acute', -1), 'ź': ('z', 'acute', -1), 'Ż': ('Z', 'dot_above', -1), 'ż': ('z', 'dot_above', -1), 'Č': ('C', 'caron', -1), 'č': ('c', 'caron', -1), 'Ď': ('D', 'caron', -1), 'ď': ('d', 'caron', -1), 'Ě': ('E', 'caron', -1), 'ě': ('e', 'caron', -1), 'Ň': ('N', 'caron', -1), 'ň': ('n', 'caron', -1), 'Ř': ('R', 'caron', -1), 'ř': ('r', 'caron', -1), 'Š': ('S', 'caron', -1), 'š': ('s', 'caron', -1), 'Ť': ('T', 'caron', -1), 'ť': ('t', 'caron', -1), 'Ů': ('U', 'ring', -1), 'ů': ('u', 'ring', -1), 'Ž': ('Z', 'caron', -1), 'ž': ('z', 'caron', -1), } def parse_r_font_file(r_file_path): """ Parse the R file to extract the arcode_font_point_sets list. Returns a dictionary mapping characters to their point set strings. """ try: with open(r_file_path, 'r', encoding='utf-8') as f: content = f.read() # Find the arcode_font_point_sets list definition # Pattern matches: CHAR = "point_set" or CHAR = 'point_set' or `CHAR` = "point_set" pattern = r'`?([^`=\s]+)`?\s*=\s*["\']([^"\']+)["\']' font_data = {} for match in re.finditer(pattern, content): char = match.group(1) point_set = match.group(2) # Handle backtick-quoted characters (like `0`, ` `, etc.) if len(char) == 1: font_data[char] = point_set # Add lowercase versions for uppercase letters uppercase_letters = [c for c in font_data.keys() if c.isupper() and c.isalpha()] for letter in uppercase_letters: font_data[letter.lower()] = font_data[letter] return font_data except FileNotFoundError: print(f"ERROR: R file not found: {r_file_path}") sys.exit(1) except Exception as e: print(f"ERROR parsing R file: {e}") import traceback traceback.print_exc() sys.exit(1) def parse_points(points_string): points_string = re.sub(r'\s+', '', points_string) coords = [int(c) for c in points_string] return [(coords[i], coords[i+1]) for i in range(0, len(coords), 2)] def parse_strokes(point_set): stroke_strings = point_set.split(':') return [parse_points(s.strip()) for s in stroke_strings] def scale_coords(x, y, scale=100, y_offset=0): """Scale coordinates WITHOUT flipping Y-axis.""" scaled_x = x * scale # Don't flip - use Y as-is from R data scaled_y = y * scale + (y_offset * scale) return scaled_x, scaled_y def create_line_rectangle(x1, y1, x2, y2, width): dx = x2 - x1 dy = y2 - y1 length = math.sqrt(dx*dx + dy*dy) if length < 0.001: return [] dx /= length dy /= length perp_x = -dy perp_y = dx half_w = width / 2.0 p1 = (x1 + perp_x * half_w, y1 + perp_y * half_w) p2 = (x2 + perp_x * half_w, y2 + perp_y * half_w) p3 = (x2 - perp_x * half_w, y2 - perp_y * half_w) p4 = (x1 - perp_x * half_w, y1 - perp_y * half_w) return [p1, p2, p3, p4] def draw_strokes(pen, strokes, stroke_width, y_offset=0): for stroke in strokes: if len(stroke) < 2: continue scaled_stroke = [scale_coords(x, y, y_offset=y_offset) for x, y in stroke] for i in range(len(scaled_stroke) - 1): x1, y1 = scaled_stroke[i] x2, y2 = scaled_stroke[i + 1] rect = create_line_rectangle(x1, y1, x2, y2, stroke_width) if len(rect) == 4: pen.moveTo(rect[0]) pen.lineTo(rect[1]) pen.lineTo(rect[2]) pen.lineTo(rect[3]) pen.closePath() def create_composite_glyph(pen, base_char, diacritic, y_offset, stroke_width, font_data): if base_char in font_data: base_strokes = parse_strokes(font_data[base_char]) draw_strokes(pen, base_strokes, stroke_width) if diacritic and diacritic in DIACRITICS: diacritic_strokes = parse_strokes(DIACRITICS[diacritic]) draw_strokes(pen, diacritic_strokes, stroke_width, y_offset) def build_font_object(font_data, stroke_width=40): """Build and return a FontForge font object with all glyphs.""" try: import fontforge except ImportError: print("ERROR: FontForge Python module not found.") return None print(f"Building font object...") font = fontforge.font() font.fontname = "ArcadeFont" font.fullname = "Arcade Font Extended" font.familyname = "Arcade" font.weight = "Regular" font.copyright = "Generated from R arcade font data" font.version = "001.000" font.ascent = 800 font.descent = 200 font.em = 1000 glyph_count = 0 for char, point_set in font_data.items(): unicode_val = ord(char) glyph = font.createChar(unicode_val) glyph.width = 900 strokes = parse_strokes(point_set) pen = glyph.glyphPen() draw_strokes(pen, strokes, stroke_width) pen = None glyph.removeOverlap() glyph.simplify() glyph_count += 1 for char, (base, diacritic, offset) in EXTENDED_LATIN.items(): unicode_val = ord(char) glyph = font.createChar(unicode_val) glyph.width = 900 pen = glyph.glyphPen() create_composite_glyph(pen, base, diacritic, offset, stroke_width, font_data) pen = None glyph.removeOverlap() glyph.simplify() glyph_count += 1 print(f" Created {glyph_count} glyphs (Base: {len(font_data)}, Extended Latin: {len(EXTENDED_LATIN)})") return font def create_sfd_file(output_path, font_data, stroke_width=40): """Create a FontForge SFD (source) file.""" try: font = build_font_object(font_data, stroke_width) if font is None: return False print(f"Saving SFD file: {output_path}") font.save(str(output_path)) print(f"Successfully created SFD file: {output_path}") return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def create_font_with_fontforge(output_path, font_data, stroke_width=40): """Create an OTF font file.""" try: font = build_font_object(font_data, stroke_width) if font is None: return False print(f"Generating OTF file: {output_path}") font.generate(str(output_path)) print(f"Successfully created OTF font: {output_path}") return True except Exception as e: print(f"ERROR: {e}") import traceback traceback.print_exc() return False def generate_sfd_only(): """Standalone function to generate only the SFD file.""" script_dir = Path(__file__).parent r_file_path = script_dir / "create-arcade-font.R" sfd_path = script_dir / "ArcadeFont.sfd" print("Generating SFD file only...") print(f"Reading font data from: {r_file_path}") font_data = parse_r_font_file(r_file_path) print(f"Loaded {len(font_data)} base glyphs from R file") success = create_sfd_file(sfd_path, font_data, 40) if not success: sys.exit(1) def main(): script_dir = Path(__file__).parent # Parse command line arguments if len(sys.argv) > 1: r_file_path = Path(sys.argv[1]) else: r_file_path = script_dir / "create-arcade-font.R" # Ensure R file path is absolute if not r_file_path.is_absolute(): r_file_path = script_dir / r_file_path otf_path = script_dir / "ArcadeFont.otf" print("=" * 60) print("Arcade Font Converter: Extended Edition") print("(Y-axis: NO flip - using R coordinates as-is)") print("=" * 60) print(f"Reading font data from: {r_file_path}") # Parse the R file to get font data font_data = parse_r_font_file(r_file_path) print(f"Loaded {len(font_data)} base glyphs from R file") success = create_font_with_fontforge(otf_path, font_data, 40) print("\n" + "=" * 60) if success: print("+ Font created with extended Latin characters") print(f" File: {otf_path}") else: print("✗ Conversion failed!") print("=" * 60) if __name__ == "__main__": main() arcadefont-1.0/data-raw/create-arcade-font.R000066400000000000000000000110641520140604100207220ustar00rootroot00000000000000 suppressPackageStartupMessages({ library(dplyr) library(purrr) }) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Each pair of digits describes a point i.e. "00" is the point (0, 0) # Points are separated by a space for readability # Strokes within a glyph are separaed by ":" # Font is defined on an 9x9 grid with x and y coords in the range [0,8] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arcode_font_point_sets <- list( A = "00 06 48 86 80 : 03 83", B = "00 08 58 76 54 04 : 64 82 60 00", C = "88 08 00 80", D = "00 08 58 85 83 50 00", E = "88 08 00 80 : 04 64", F = "88 08 00 : 04 64", G = '88 08 00 80 83 43', H = '00 08 : 80 88 : 04 84', I = '00 80 : 08 88 : 40 48', J = '88 80 40 03', K = '00 08 : 88 04 80', L = '08 00 80', M = '00 08 45 88 80', N = '00 08 80 88', O = '00 80 88 08 00', P = '00 08 88 84 04', Q = '00 08 88 83 40 00 : 43 80', R = '00 08 88 84 04 80', S = '00 80 84 04 08 88', T = '08 88 : 40 48', U = '08 00 80 88', V = '08 40 88', W = '08 00 43 80 88', X = '00 88 : 08 80', Y = '08 45 88 : 45 40', Z = '08 88 00 80', `0` = '00 80 88 08 00', `1` = '00 80 : 40 48 26', `2` = '08 88 84 04 00 80', `3` = '08 88 80 00 : 04 84', `4` = '08 04 84 : 88 80', `5` = '00 80 84 04 08 88', `6` = '08 00 80 84 04', `7` = '08 88 80', `8` = '00 08 88 80 00 : 04 84', `9` = '80 88 08 04 84', `.` = '00 01 11 10 00', `,` = '01 02 12 11 01 : 11 00', `-` = '14 74', ` ` = '00', `=` = '13 73 : 15 75', `!` = '00 01 11 10 00 : 03 08 18 13 03', `?` = '06 08 88 84 44 40', `:` = '02 03 13 12 02 : 05 06 16 15 05', `;` = '02 03 13 12 02 : 05 06 16 15 05 : 1 2 0 0', `#` = '03 83 : 05 85 : 30 38 : 50 58', `'` = '07 08 18 17 07 : 17 05', `"` = '07 08 18 17 07 : 17 05 : 27 28 38 37 27 : 37 25', `[` = '28 08 00 20', `]` = '08 28 20 00', `(` = '28 04 20', `)` = '08 24 00', `{` = '28 04 20', `}` = '08 24 00', `$` = '01 81 84 04 07 87 : 40 48', `+` = '41 47 : 14 74', `/` = '00 88', `*` = '41 47 : 14 74 : 22 66 : 26 62', `%` = '00 88 : 18 28 27 17 18 : 70 71 61 60 70', `^` = '26 48 66', `|` = '40 48', `_` = '00 80', `<` = '87 04 81', `>` = '07 84 01', `&` = '80 47 58 67 21 30 60 82', `@` = '71 60 20 02 06 28 68 86 84 62 22 24 36 66 62' ) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # @param points_string e.g. "00 34 12 56" # @return data.frame of x,y coordinates #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ points_to_df <- function(points_string) { points <- gsub("\\s+", '', points_string) points <- strsplit(points, '')[[1]] points <- as.integer(points) res <- as.data.frame(t(matrix(points, nrow = 2))) names(res) <- c('x', 'y') res$idx <- seq(nrow(res)) res } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # @param point_set colon-separated string containing 1 or more point strings # e.g. "12 34 : 45 56" # @return data.frame with x, y and stroke number #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ point_set_to_df <- function(point_set) { points_strings <- strsplit(point_set, ":")[[1]] dfs <- lapply(points_strings, points_to_df) dplyr::bind_rows(dfs, .id = 'stroke') } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # @param point_sets named list of points sets. One point set for each glyph # @return data.frame with x, y, stroke and letter #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ point_sets_to_df <- function(point_sets) { dfs <- lapply(point_sets, point_set_to_df) dplyr::bind_rows(dfs, .id = 'letter') } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create point set for the arcade font and save in package as external data #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arcade_df <- point_sets_to_df(arcode_font_point_sets) arcade_df <- as_tibble(arcade_df) usethis::use_data(arcade_df, internal = FALSE, overwrite = TRUE) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Test Plot of all chars #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ suppressPackageStartupMessages({ library(dplyr) library(ggplot2) }) ggplot(arcade_df, aes(x, y)) + # geom_point() + geom_path(aes(group=stroke)) + coord_fixed() + theme_void() + facet_wrap(~letter) arcadefont-1.0/data/000077500000000000000000000000001520140604100143625ustar00rootroot00000000000000arcadefont-1.0/data/arcade_df.rda000066400000000000000000000015671520140604100167530ustar00rootroot00000000000000BZh91AY&SYyh/@"JD20FC@bCM4h4hڂ!OP$D4ёFM44ɦFPM40U"dшhb24h44M !1i @@ o%su㦰5M[:e7g,7.ZMÖV,Q T+* +:sE+#i;GiELfһya+rfìBAqjBIA6[9: C:EV0XpC e&#glEF^D]Np3c;:N:sYg-34o)NUyf.Mh!&M b Q! !!@؍@0sLy4 Дٟ8$ ]`@_$'!I 4BQ6Mb))6x:l`1vC9 'Nh`&AXd kY+T D$Y d F X1dA'(@  DTe F^)qDEI¦.qtDtԎ, ]Bk&QT(3ޯOޫPr$ |@ EXvr\J$XVe)!0am 6I!b!Y"V$ R@1,%d dɊZFAV Ds3eQQƊQٚܵb6BHx@ i Hp@;H9#.:9&, Yy4J:ŌGH1CirqH ~2arcadefont-1.0/man/000077500000000000000000000000001520140604100142245ustar00rootroot00000000000000arcadefont-1.0/man/arcade_df.Rd000066400000000000000000000006311520140604100164030ustar00rootroot00000000000000% Generated by roxygen2: do not edit by hand % Please edit documentation in R/arcade.R \docType{data} \name{arcade_df} \alias{arcade_df} \title{Data.frame of Arcade vector font information} \format{ An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 366 rows and 5 columns. } \usage{ arcade_df } \description{ Data.frame of Arcade vector font information } \keyword{datasets} arcadefont-1.0/man/create_text_df.Rd000066400000000000000000000011521520140604100174720ustar00rootroot00000000000000% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.R \name{create_text_df} \alias{create_text_df} \title{Create data.frame of glyph information for the given text.} \usage{ create_text_df(text, dx = 2, dy = 2) } \arguments{ \item{text}{single character string} \item{dx, dy}{character spacing in original units} } \value{ data.frame with coordinates for all the glyphs with characters offset appropriately. \code{char_idx} is the index of the character within the given text string } \description{ Text input can contain multiple lines separated by carriage returns } arcadefont-1.0/man/create_text_df_single_row.Rd000066400000000000000000000011721520140604100217240ustar00rootroot00000000000000% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.R \name{create_text_df_single_row} \alias{create_text_df_single_row} \title{Create data.frame of glyph information for the given line of text.} \usage{ create_text_df_single_row(text, dx = 2) } \arguments{ \item{text}{text string} \item{dx}{character spacing in original units} } \value{ data.frame with coordinates for all the glyphs with characters offset appropriately. \code{char_idx} is the index of the character within the given text string } \description{ Create data.frame of glyph information for the given line of text. }