From a0f3a7e9192a3764a1fff756be06202c06713da9 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 1 Sep 2018 11:02:51 -0400 Subject: [PATCH] more work on font generator --- package-lock.json | 281 +++++++++--------- package.json | 1 + presets/vcs/examples/scoreboard.a | 3 +- .../fontgen/uifont.js => src/tools/uifont.ts | 244 ++++++++++----- tools/fontgen/index.html | 30 +- 5 files changed, 348 insertions(+), 211 deletions(-) rename tools/fontgen/uifont.js => src/tools/uifont.ts (57%) diff --git a/package-lock.json b/package-lock.json index 433670fa..c3c3f508 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha512-UGvzSQFkv0Oh2vjj30AfZructi7XvY0aRa1Y/vrgFq+tfrTMxtqQ9+s5liCYLJnrISc9LinEtOY5N8Ibrhj2Tg==", "dev": true, "requires": { - "@types/jquery": "2.0.49" + "@types/jquery": "*" } }, "@types/jquery": { @@ -19,6 +19,15 @@ "integrity": "sha512-/9xLnYmohN/vD2gDnLS4cym8TUmrJu7DvZa/LELKzZjdPsvWVJiedsdu2SXNtb/DA7FGimqL2g0IoyhbNKLl8g==", "dev": true }, + "@types/w2ui": { + "version": "1.4.32", + "resolved": "https://registry.npmjs.org/@types/w2ui/-/w2ui-1.4.32.tgz", + "integrity": "sha512-K/VxxtmGRhMHMyiPL4rl+Drk74n21lXw+dlLD2ovaAN/QbiDpFxXdRKvBeDoU+XphKShHoAQC/WiIKl60ZZ2qA==", + "dev": true, + "requires": { + "@types/jquery": "*" + } + }, "abab": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", @@ -37,7 +46,7 @@ "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", "dev": true, "requires": { - "acorn": "5.7.1" + "acorn": "^5.0.0" } }, "ajv": { @@ -46,10 +55,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ansi-regex": { @@ -76,7 +85,7 @@ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "assert-plus": { @@ -128,7 +137,7 @@ "dev": true, "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "bluebird": { @@ -143,7 +152,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -171,11 +180,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "clipboard": { @@ -184,9 +193,9 @@ "integrity": "sha512-7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==", "dev": true, "requires": { - "good-listener": "1.2.2", - "select": "1.1.2", - "tiny-emitter": "2.0.2" + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" } }, "co": { @@ -201,7 +210,7 @@ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -210,7 +219,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "concat-map": { @@ -237,7 +246,7 @@ "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", "dev": true, "requires": { - "cssom": "0.3.4" + "cssom": "0.3.x" } }, "dashdash": { @@ -246,7 +255,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "data-urls": { @@ -255,9 +264,9 @@ "integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==", "dev": true, "requires": { - "abab": "2.0.0", - "whatwg-mimetype": "2.1.0", - "whatwg-url": "7.0.0" + "abab": "^2.0.0", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^7.0.0" } }, "deep-is": { @@ -284,7 +293,7 @@ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "dev": true, "requires": { - "webidl-conversions": "4.0.2" + "webidl-conversions": "^4.0.2" } }, "ecc-jsbn": { @@ -294,8 +303,8 @@ "dev": true, "optional": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "escape-string-regexp": { @@ -310,11 +319,11 @@ "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "dev": true, "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" } }, "esprima": { @@ -386,9 +395,9 @@ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "dev": true, "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.19" + "mime-types": "^2.1.12" } }, "fs.realpath": { @@ -403,7 +412,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "good-listener": { @@ -412,7 +421,7 @@ "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", "dev": true, "requires": { - "delegate": "3.2.0" + "delegate": "^3.1.2" } }, "graceful-readlink": { @@ -433,8 +442,8 @@ "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "dev": true, "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, "has-ansi": { @@ -443,7 +452,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "he": { @@ -464,7 +473,7 @@ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "dev": true, "requires": { - "whatwg-encoding": "1.0.4" + "whatwg-encoding": "^1.0.1" } }, "http-signature": { @@ -473,9 +482,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { @@ -484,7 +493,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "inflight": { @@ -493,8 +502,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -528,31 +537,31 @@ "integrity": "sha512-42RgZYXWwyClG0pN6Au7TExAQqRvzbtJhlcIvu58cJj4yr1bIbqZkgxHqn1btxKu80axZXPZLvldeTzg2auKow==", "dev": true, "requires": { - "abab": "2.0.0", - "acorn": "5.7.1", - "acorn-globals": "4.1.0", - "array-equal": "1.0.0", - "cssom": "0.3.4", - "cssstyle": "1.1.1", - "data-urls": "1.0.1", - "domexception": "1.0.1", - "escodegen": "1.11.0", - "html-encoding-sniffer": "1.0.2", - "nwsapi": "2.0.8", + "abab": "^2.0.0", + "acorn": "^5.7.1", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.1", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.0.8", "parse5": "5.1.0", - "pn": "1.1.0", - "request": "2.88.0", - "request-promise-native": "1.0.5", - "sax": "1.2.4", - "symbol-tree": "3.2.2", - "tough-cookie": "2.4.3", - "w3c-hr-time": "1.0.1", - "webidl-conversions": "4.0.2", - "whatwg-encoding": "1.0.4", - "whatwg-mimetype": "2.1.0", - "whatwg-url": "7.0.0", - "ws": "6.0.0", - "xml-name-validator": "3.0.0" + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.4.3", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.4", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^7.0.0", + "ws": "^6.0.0", + "xml-name-validator": "^3.0.0" } }, "json-schema": { @@ -591,8 +600,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lodash": { @@ -613,10 +622,10 @@ "integrity": "sha1-S9MHpk4FbGTWBSqRt+rlwmqopRY=", "dev": true, "requires": { - "chalk": "1.1.3", + "chalk": "^1.1.3", "commander": "2.9.0", - "filepath": "1.1.0", - "pkginfo": "0.4.1" + "filepath": "~1.1.0", + "pkginfo": "~0.4.0" } }, "mime-db": { @@ -631,7 +640,7 @@ "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "dev": true, "requires": { - "mime-db": "1.35.0" + "mime-db": "~1.35.0" } }, "minimatch": { @@ -640,7 +649,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -710,12 +719,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "growl": { @@ -736,7 +745,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -765,7 +774,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "optionator": { @@ -774,12 +783,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "parse5": { @@ -842,26 +851,26 @@ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.1.0", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.19", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.4.3", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, "request-promise-core": { @@ -870,7 +879,7 @@ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.13.1" } }, "request-promise-native": { @@ -880,8 +889,8 @@ "dev": true, "requires": { "request-promise-core": "1.1.1", - "stealthy-require": "1.1.1", - "tough-cookie": "2.4.3" + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" } }, "safe-buffer": { @@ -921,15 +930,15 @@ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "dev": true, "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "stealthy-require": { @@ -944,7 +953,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -971,8 +980,8 @@ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -989,7 +998,7 @@ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "tunnel-agent": { @@ -998,7 +1007,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -1014,7 +1023,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "typescript": { @@ -1035,9 +1044,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "w3c-hr-time": { @@ -1046,7 +1055,7 @@ "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", "dev": true, "requires": { - "browser-process-hrtime": "0.1.2" + "browser-process-hrtime": "^0.1.2" } }, "wavedrom-cli": { @@ -1082,9 +1091,9 @@ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "dev": true, "requires": { - "lodash.sortby": "4.7.0", - "tr46": "1.0.1", - "webidl-conversions": "4.0.2" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } }, "wordwrap": { @@ -1105,7 +1114,7 @@ "integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==", "dev": true, "requires": { - "async-limiter": "1.0.0" + "async-limiter": "~1.0.0" } }, "xml-name-validator": { diff --git a/package.json b/package.json index 093829c6..15825746 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "devDependencies": { "@types/bootstrap": "^3.x", "@types/jquery": "^2.x", + "@types/w2ui": "^1.4.32", "atob": "^2.1.2", "btoa": "^1.2.1", "clipboard": "^2.0.1", diff --git a/presets/vcs/examples/scoreboard.a b/presets/vcs/examples/scoreboard.a index e4f1e53c..aa73dcd6 100644 --- a/presets/vcs/examples/scoreboard.a +++ b/presets/vcs/examples/scoreboard.a @@ -68,8 +68,7 @@ ScanLoop1a lda #0 sta WSYNC sta PF1 -; Turn playfield reflection off, since our brick field -; will be drawn asymetrically (and turn score mode off) +; Turn playfield reflection off (and turn score mode off) lda #%00010100 ; no reflection + ball priority + 2 pixel ball sta CTRLPF diff --git a/tools/fontgen/uifont.js b/src/tools/uifont.ts similarity index 57% rename from tools/fontgen/uifont.js rename to src/tools/uifont.ts index 08494e1e..5466b892 100644 --- a/tools/fontgen/uifont.js +++ b/src/tools/uifont.ts @@ -1,8 +1,13 @@ +import { hex } from "../util"; + var font; -var params = { +declare var FONTLIST : string; + +var FONT_DEFAULT_PARAMS = { bpp:1, + np:1, wbytes:1, width:8, height:8, @@ -12,21 +17,88 @@ var params = { xflip:false, yflip:false, msbfirst:false, + output:'c_nested', }; +var params; + var errors; var previewCanvas = $("#previewCanvas"); var codeTextarea = $("#codeTextarea"); var paramsForm = $("#paramsForm"); -function refreshPreset(item) { - console.log(item); - w2ui.toolbar.set('bpp', {value:'1'}); - w2ui.toolbar.set('width', {value:'8'}); - w2ui.toolbar.set('height', {value:'8'}); - w2ui.toolbar.set('lochar', {value:'32'}); - w2ui.toolbar.set('hichar', {value:'95'}); +var FONT_PRESETS = { + _8x8: { }, + apple2: { width:7 }, + vcs: { output:'dasm', msbfirst:true }, + mw8080bw: { rotate:true, flip:true, msbfirst:true }, + nes: { np:2, msbfirst:true }, +}; + +function loadPreset(preset_id) { + params = $.extend({}, FONT_DEFAULT_PARAMS, FONT_PRESETS[preset_id]); + refreshToolbar(); +} + +function updateToolbarValue(event, id:string) { + event.item = w2ui.toolbar.get(id); + event.item.value = event.target.value; + refreshToolbar(event); +} + +function refreshToolbar(event?) { + // update params from toolbar item? + console.log(event); + if (event && event.item) { + switch (event.item.id) { + case 'width': + case 'height': + case 'lochar': + case 'hichar': + params[event.item.id] = parseInt(event.item.value); + break; + case 'rotate': + case 'xflip': + case 'yflip': + case 'msbfirst': + params[event.item.id] = event.item.checked; + break; + case 'bpp': + if (event.subItem) + params[event.item.id] = parseInt(event.subItem.text); + break; + case 'preset': + if (event.subItem) + loadPreset(event.subItem.id); + break; + case 'charsel': + if (event.subItem) + loadCharSel(event.subItem.id); + break; + } + } + // set derived params + params.wbytes = Math.floor((params.width*params.bpp+7)/8); + // set toolbar items + Object.keys(params).forEach(function(key) { + var val = params[key]; + var item = w2ui.toolbar.get(key); + switch (item && item.type) { + case 'check': item.checked = val; break; + case 'html': item.value = val; break; + case 'menu-radio': item.selected = val; break; + } + }); + w2ui.toolbar.refresh(); + updateEncoding(); + previewFont(); +} + +function loadCharSel(id) { + var toks = id.split('-'); + params.lochar = parseInt(toks[0]); + params.hichar = parseInt(toks[1]); } function parseBDF(text) { @@ -80,12 +152,20 @@ function loadFont(rec) { font.rec = rec; font.path = path; console.log(font); + updateEncoding(); previewFont(); - codeTextarea.text(encodeFont()); }); } +function updateEncoding() { + if (font) { + codeTextarea.text(encodeFont()); + } +} + function renderGlyph(glyph, putPixel) { + if (glyph.ord < params.lochar || glyph.ord > params.hichar) + return {w:8,h:8}; var w = glyph.bbx[0]; var h = glyph.bbx[1]; var dx = glyph.bbx[2]; @@ -95,11 +175,14 @@ function renderGlyph(glyph, putPixel) { if (glyph.bytes[glyph.bytes.length-y-1] & (0x800000 >> x)) { var xx = x+dx; var yy = y+dy; + /* font.pixbounds[0] = Math.min(font.pixbounds[0], xx); font.pixbounds[1] = Math.min(font.pixbounds[1], yy); font.pixbounds[2] = Math.max(font.pixbounds[2], xx); font.pixbounds[3] = Math.max(font.pixbounds[3], yy); - putPixel(xx, yy); + */ + if (xx >= 0 && yy >= 0 && xx < params.width && yy < params.height) + putPixel(xx, yy); } } } @@ -107,7 +190,7 @@ function renderGlyph(glyph, putPixel) { } function drawChar(x0, y0, chord) { - var ctx = previewCanvas[0].getContext('2d'); + var ctx = (previewCanvas[0] as any).getContext('2d'); ctx.fillStyle = "black"; var glyph = font.chars[chord]; if (glyph) { @@ -134,7 +217,8 @@ var TEST_SENTENCES = [ ]; function previewFont() { - var ctx = previewCanvas[0].getContext('2d'); + if (!font) return; + var ctx = (previewCanvas[0] as any).getContext('2d'); ctx.fillStyle = "white"; ctx.fillRect( 0, 0, 1024, 1024 ); var x = 8; @@ -151,11 +235,11 @@ function encodeGlyph(glyph, bytes) { renderGlyph(glyph, function(x,y) { //x -= font.pixbounds[0]; //y -= font.pixbounds[1]; + if (params.yflip) { y = params.height-1-y; } + if (params.xflip ^ params.rotate) { x = params.width-1-x; } if (params.rotate) { var y2 = x; var x2 = y; x = x2; y = y2; } - if (params.yflip) { y = params.height-1-y; } - if (params.xflip) { x = params.width-1-x; } var xoutrange = (x < 0 || x >= params.width); var youtrange = (y < 0 || y >= params.height); if (xoutrange || youtrange) { @@ -173,23 +257,36 @@ function encodeGlyph(glyph, bytes) { } function encodeFont() { - var s = '/* ' + JSON.stringify(params) + JSON.stringify(font.bounds) + JSON.stringify(font.pixbounds) + ' */\n'; - s += "#define LOCHAR " + params.lochar + "\n"; - s += "#define HICHAR " + params.hichar + "\n"; - s += "#define FONT_HEIGHT " + params.height + "\n"; - s += "const char FONT[HICHAR-LOCHAR+1][FONT_HEIGHT] = {\n"; + var s = ''; + if (params.output.startsWith('c_')) { + //s += '/* ' + JSON.stringify(params) + JSON.stringify(font.bounds) + JSON.stringify(font.pixbounds) + ' */\n'; + s += "#define LOCHAR " + params.lochar + "\n"; + s += "#define HICHAR " + params.hichar + "\n"; + s += "#define FONT_BWIDTH " + (params.wbytes*params.np) + "\n"; + s += "#define FONT_HEIGHT " + params.height + "\n"; + s += "const char FONT[HICHAR-LOCHAR+1][FONT_HEIGHT*FONT_BWIDTH] = {\n"; + } else { + s += "LOCHAR\t\t= " + params.lochar + "\n"; + s += "HICHAR\t\t= " + params.hichar + "\n"; + s += "FONT_HEIGHT\t= " + params.height + "\n"; + s += "FontData:\n"; + } errors = []; for (var chord=params.lochar; chord<=params.hichar; chord++) { var glyph = font.chars[chord]; - var bytes = new Uint8Array(params.wbytes*params.height); + var bytes = new Uint8Array(params.wbytes*params.height*params.np); if (glyph) { encodeGlyph(glyph, bytes); - s += "{ "; + if (params.output=='c_nested') s += "{ "; + else if (params.output=='dasm') s += "\thex\t"; for (var i=0; i'; return html; }; @@ -240,39 +337,48 @@ function toolbarHTMLItem(id, title, maxchars) { $().w2toolbar({ name: 'toolbar', + onClick: function(event) { + // TODO? + setTimeout(function() { refreshToolbar(event); }, 1); + }, + tooltip: 'bottom', items: [ { type: 'menu-radio', id: 'preset', caption: 'Presets', img: 'icon-folder', - text: function(item) { refreshPreset(item); return item.caption; }, + tooltip: 'Preset encoding options for specific platforms', + //text: function(item) { refreshPreset(item); return item.caption; }, items: [ - { text: 'Generic 8x8', id: '8x8' }, - { text: 'Atari 2600', id: 'vcs' }, - { text: 'Midway 8080', id: 'mw8080bw' }, - { text: 'NES', id: 'nes' } - ]}, - { type: 'check', id: 'rotate', caption: 'Rotate' }, - { type: 'check', id: 'yflip', caption: 'Flip' }, - { type: 'menu-radio', id: 'bpp', caption: 'BPP', img: 'fas fa-star', items: [ - { text: '1' }, - { text: '2' }, - { text: '4' }, - { text: '8' } - ]}, + { text: 'Generic C 8x8', id: '_8x8' }, + { text: 'Atari 2600', id: 'vcs' }, + { text: 'Midway 8080', id: 'mw8080bw' }, + { text: 'NES', id: 'nes' }, + { text: 'Apple ][', id: 'apple2' }, + ]}, + { type: 'check', id: 'rotate', caption: 'Rotate', img: 'fas fa-sync', tooltip: 'Rotate 90 degrees (swap X/Y)' }, + { type: 'check', id: 'xflip', caption: 'Mirror', img: 'fas fa-arrows-alt-h', tooltip: 'Flip X axis' }, + { type: 'check', id: 'yflip', caption: 'Flip', img: 'fas fa-arrows-alt-v', tooltip: 'Flip Y axis' }, + { type: 'check', id: 'msbfirst', caption: 'MSB First', img: 'fas fa-arrow-alt-circle-right', tooltip: 'If selected, MSB (left) to LSB (right)' }, + { type: 'menu-radio', id: 'bpp', caption: 'BPP', img: 'fas fa-dice-one', tooltip: 'Bits per pixel', + items: [ + { text: '1' }, + { text: '2' }, + { text: '4' }, + { text: '8' } + ]}, { type: 'html', id: 'width', html: toolbarHTMLItem('width','Width:',2) }, { type: 'html', id: 'height', html: toolbarHTMLItem('height','Height:',2) }, { type: 'break', id: 'break1' }, - { type: 'menu-radio', id: 'charsel', caption: 'Characters', img: 'icon-folder', items: [ - //{ text: 'ISO (256 chars)', value:'0-255' }, - { text: 'ASCII (upper+lower)', id:'32-95' }, - { text: 'ASCII (upper only)', id:'32-127' } - ]}, + { type: 'menu-radio', id: 'charsel', caption: 'Characters', img: 'icon-folder', + tooltip: 'Range of characters to encode, from first to last', + //text: function(item) { refreshCharSel(item); return item.caption; }, + items: [ + //{ text: 'ISO (256 chars)', value:'0-255' }, + { text: 'ASCII (upper only)', id:'32-95' }, + { text: 'ASCII (upper+lower)', id:'32-127' } + ]}, { type: 'html', id: 'lochar', html: toolbarHTMLItem('lochar','First:',3) }, { type: 'html', id: 'hichar', html: toolbarHTMLItem('hichar','Last:',3) }, - /* + /* { type: 'spacer' }, - { type: 'check', id: 'item1', caption: 'Check', img: 'icon-page', checked: true }, - { type: 'break', id: 'break0' }, - { type: 'radio', id: 'item3', group: '1', caption: 'Radio 1', icon: 'fa-star', checked: true }, - { type: 'radio', id: 'item4', group: '1', caption: 'Radio 2', icon: 'fa-star-empty' }, { type: 'button', id: 'item5', caption: 'Item 5', icon: 'fa-home' } */ ] @@ -312,10 +418,10 @@ $('#layout').w2layout({ name: 'layout', panels: [ { type: 'top', size: 50, resizable: false, style: pstyle, content: 'top' }, - { type: 'left', size: 200, resizable: true, style: pstyle, content: paramsForm }, +// { type: 'left', size: 200, resizable: true, style: pstyle, content: paramsForm }, { type: 'main', style: pstyle, content: codeTextarea }, { type: 'preview', size: '50%', resizable: true, style: pstyle, content: previewCanvas }, - { type: 'right', size: 200, resizable: true, style: pstyle, content: 'right' }, + { type: 'left', size: '25%', resizable: true, style: pstyle, content: $("#instructions") }, { type: 'bottom', size: 200, resizable: true, style: pstyle, content: 'bottom' } ] }); @@ -323,10 +429,4 @@ $('#layout').w2layout({ w2ui['layout'].content('top', w2ui['toolbar']); w2ui['layout'].content('bottom', w2ui['fontGrid']); -w2ui.toolbar.set('preset', {selected:'8x8'}); -w2ui.toolbar.set('bpp', {value:'1'}); -w2ui.toolbar.set('width', {value:'8'}); -w2ui.toolbar.set('height', {value:'8'}); -w2ui.toolbar.set('lochar', {value:'32'}); -w2ui.toolbar.set('hichar', {value:'95'}); - +loadPreset('_8x8'); diff --git a/tools/fontgen/index.html b/tools/fontgen/index.html index 240fb00e..75eaba20 100644 --- a/tools/fontgen/index.html +++ b/tools/fontgen/index.html @@ -22,8 +22,21 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
+ + + +
+

8bitworkshop Bitmap Font Encoder

+
    +
  1. Select a font below (check out the search and filter options.)
  2. +
  3. Choose a preset platform, or your own encoding options.
  4. +
  5. Select a range of characters.
  6. +
  7. Check out the preview bitmap to make sure none of your characters are visibly cut off, or increase your height/width (if your platform supports it.)
  8. +
  9. Copy the output to the clipboard, paste it into your code.
  10. +
+
@@ -33,9 +46,24 @@ if (window.location.host.endsWith('8bitworkshop.com')) { + + + + + + + - + +