├── .babelrc
├── .gitignore
├── src
├── Screen
│ ├── crtlines.png
│ ├── CRTScreen.js
│ └── index.js
├── exampleCartridges
│ ├── cast.p8.png
│ ├── hello.p8.png
│ ├── camera.p8.png
│ ├── otomat.p8.png
│ └── zengarden.p8.png
├── OS
│ ├── sound.lib.js
│ ├── math.lib.js
│ ├── readCartridge.lib.js
│ ├── index.js
│ ├── font.lib.js
│ └── graphics.lib.js
├── JSGS.js
├── index.js
├── Controller
│ ├── OnScreen.js
│ └── Keyboard.js
├── index.html
├── Ram.js
├── style.css
└── vendor
│ ├── glfx.js
│ └── pngtoy.js
├── utils
└── build
│ ├── index.js
│ ├── dev.server.js
│ └── webpack.config.js
├── LICENCE
├── package.json
└── README.md
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist
3 | node_modules
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/src/Screen/crtlines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/Screen/crtlines.png
--------------------------------------------------------------------------------
/src/exampleCartridges/cast.p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/exampleCartridges/cast.p8.png
--------------------------------------------------------------------------------
/src/exampleCartridges/hello.p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/exampleCartridges/hello.p8.png
--------------------------------------------------------------------------------
/src/exampleCartridges/camera.p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/exampleCartridges/camera.p8.png
--------------------------------------------------------------------------------
/src/exampleCartridges/otomat.p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/exampleCartridges/otomat.p8.png
--------------------------------------------------------------------------------
/src/exampleCartridges/zengarden.p8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/burakcan/jsgs/HEAD/src/exampleCartridges/zengarden.p8.png
--------------------------------------------------------------------------------
/src/OS/sound.lib.js:
--------------------------------------------------------------------------------
1 | export default function getSoundFunctions(ram) {
2 | function music(n, fadeLen, channelMask) {}
3 |
4 | function sfx(n, channel, offset) {}
5 |
6 | return {
7 | music,
8 | sfx,
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/utils/build/index.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const NODE_ENV = process.env.NODE_ENV;
3 |
4 | switch (NODE_ENV) {
5 | case 'development': {
6 | return require('./dev.server')();
7 | }
8 |
9 | default: { // production
10 | const config = require('./webpack.config.js');
11 | const compiler = webpack(config);
12 |
13 | return compiler.run(function(err, stats) {
14 | if (err) throw err;
15 |
16 | console.log(stats.toString({
17 | colors : true,
18 | chunks : false
19 | }));
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/utils/build/dev.server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const webpack = require('webpack');
3 | const config = require('./webpack.config');
4 | const historyApiFallback = require('connect-history-api-fallback');
5 | const devMiddleware = require('webpack-dev-middleware');
6 |
7 | module.exports = function(options) {
8 | options = options || {};
9 |
10 | const PORT = options.port || 4000;
11 | const app = express();
12 | const compiler = webpack(config);
13 |
14 | app.use(historyApiFallback());
15 |
16 | app.use(devMiddleware(compiler, {
17 | publicPath: config.output.publicPath,
18 | stats: {
19 | colors: true,
20 | chunks: false,
21 | }
22 | }));
23 |
24 | app.listen(PORT, 'localhost', err => {
25 | if (err) throw err;
26 |
27 | console.log(`Listening at http://localhost:${PORT}`);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/src/JSGS.js:
--------------------------------------------------------------------------------
1 | export default class JSGS {
2 | constructor(options) {
3 | this.devices = options.devices;
4 | this.os = options.os;
5 |
6 | this.os
7 | .sendEvent('boot', this)
8 | .sendEvent('cartridgeMount', this);
9 |
10 | this.updateLoop(() => {
11 | this.os.update();
12 | this.devices.screens.forEach(
13 | screen => screen.update(this.devices.ram)
14 | );
15 | });
16 | }
17 |
18 | updateLoop(fn, fps) {
19 | fn();
20 |
21 | let then = Date.now();
22 | fps = fps || 30;
23 | const interval = 1000 / fps;
24 |
25 | return (function loop(time){
26 | requestAnimationFrame(loop);
27 |
28 | const now = Date.now();
29 | const delta = now - then;
30 |
31 | if (delta > interval) {
32 | then = now - (delta % interval);
33 | fn();
34 | }
35 | }(0));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/OS/math.lib.js:
--------------------------------------------------------------------------------
1 | export default {
2 | rnd(x) {
3 | return Math.random() * x;
4 | },
5 |
6 | sgn(x) {
7 | return (x < 0) ? -1 : 1;
8 | },
9 |
10 | max: Math.max,
11 |
12 | min: Math.min,
13 |
14 | mid(x, y, z) {
15 | return Math.max(x, Math.min(y, z));
16 | },
17 |
18 | flr: Math.floor,
19 |
20 | cos(x) { // x = 0 - 1
21 | return Math.cos((x * 360) * (3.1415/180));
22 | },
23 |
24 | sin(x) {
25 | return Math.sin((-x * 360) * (3.1415/180));
26 | },
27 |
28 | atan2: Math.atan2,
29 |
30 | sqrt: Math.sqrt,
31 |
32 | abs: Math.abs,
33 |
34 | srand(x) {},
35 |
36 | band(x, y) {
37 | return x & y;
38 | },
39 |
40 | bor(x, y) {
41 | return x | y;
42 | },
43 |
44 | bxor(x, y) {
45 | return x ^ y;
46 | },
47 |
48 | bnot(x) {
49 | return ~x;
50 | },
51 |
52 | shl(x, y) {},
53 |
54 | shr(x, y) {},
55 | }
56 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import 'normalize.css';
2 | import './style.css';
3 | import 'script!./vendor/pngtoy';
4 | import 'script!./vendor/glfx';
5 | import JSGS from './JSGS';
6 | import OS from './OS';
7 | import Ram from './Ram';
8 | import Screen from './Screen';
9 | import CRTScreen from './Screen/CRTScreen';
10 | import KeyboardController from './Controller/Keyboard';
11 | import OnScreenController from './Controller/OnScreen';
12 | import exampleCartridge from './exampleCartridges/hello.p8.png';
13 |
14 | const screen = new Screen({ size: 128 });
15 | const ram = new Ram(0x8000);
16 | const controller = new KeyboardController();
17 | const os = new OS();
18 |
19 | const machine = new JSGS({
20 | os: os,
21 | devices: {
22 | controller: controller,
23 | ram: ram,
24 | cartridge: exampleCartridge,
25 | screens: [screen],
26 | },
27 | });
28 |
29 | screen.mountCanvas(
30 | document.getElementById('screen')
31 | );
32 |
--------------------------------------------------------------------------------
/src/Controller/OnScreen.js:
--------------------------------------------------------------------------------
1 | import KeyboardController from './Keyboard';
2 |
3 | export default class OnSreenController extends KeyboardController {
4 | constructor(machine) {
5 | super(machine);
6 | this.buildButtons();
7 | }
8 |
9 | buildButtons() {
10 | const wrapper = document.getElementById('mobileButtons');
11 |
12 | this.keys.forEach((key, i) => {
13 | const button = document.createElement('button');
14 | button.innerHTML = i;
15 | button.classList.add(`b_${key}`);
16 |
17 | button.addEventListener('touchstart', () => {
18 | const index = this.keys.indexOf(key);
19 | if (index < 0) return false;
20 |
21 | this.status[index] = true;
22 | });
23 |
24 | button.addEventListener('touchend', () => {
25 | const index = this.keys.indexOf(key);
26 | if (index < 0) return false;
27 |
28 | this.status[index] = false;
29 | });
30 |
31 | wrapper.appendChild(button)
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | JSGS
6 |
12 |
13 |
14 |
18 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/Screen/CRTScreen.js:
--------------------------------------------------------------------------------
1 | import Screen from './';
2 | import crtlines from './crtlines.png';
3 |
4 | export default class CRTScreen extends Screen {
5 | createCanvas(options) {
6 | const canvas = super.createCanvas(options);
7 | const glCanvas = this.glCanvas = fx.canvas();
8 |
9 | this.lines = new Image();
10 | this.lines.src = crtlines;
11 | this.srcctx = canvas.getContext('2d');
12 |
13 | glCanvas.width = glCanvas.height = 512;
14 | glCanvas.style.dispay = 'block';
15 | glCanvas.style.imageRendering = 'pixelated';
16 |
17 | return canvas;
18 | }
19 |
20 | mountCanvas(element) {
21 | element.appendChild(this.glCanvas);
22 | }
23 |
24 | update(ram) {
25 | super.update(ram);
26 |
27 | const halfSize = this.size / 2;
28 |
29 | this.srcctx.drawImage(this.lines, 0, 0, this.size, this.size);
30 |
31 | this.glCanvas
32 | .draw(this.glCanvas.texture(this.canvas))
33 | .bulgePinch(halfSize, halfSize, this.size * 0.75, 0.12)
34 | .vignette(0.15, 0.5)
35 | .update();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "JSGS",
3 | "version": "0.0.9",
4 | "main": "index.js",
5 | "author": "Burak Can",
6 | "license": "MIT",
7 | "repository": "https://gitlab.com/burakcan/jsgs.git",
8 | "scripts": {
9 | "clean": "rimraf dist",
10 | "build": "npm run clean && NODE_ENV=production node ./utils/build",
11 | "start-dev": "NODE_ENV=development node ./utils/build"
12 | },
13 | "dependencies": {
14 | "babel-core": "^6.18.2",
15 | "babel-loader": "^6.2.7",
16 | "babel-preset-es2015": "^6.18.0",
17 | "connect-history-api-fallback": "^1.3.0",
18 | "css-loader": "^0.25.0",
19 | "escodegen": "^1.8.1",
20 | "estraverse": "^4.2.0",
21 | "express": "^4.14.0",
22 | "file-loader": "^0.9.0",
23 | "html-webpack-plugin": "^2.24.1",
24 | "json-loader": "^0.5.4",
25 | "lua2js": "^0.0.11",
26 | "normalize.css": "^5.0.0",
27 | "rimraf": "^2.5.4",
28 | "script-loader": "^0.7.0",
29 | "style-loader": "^0.13.1",
30 | "uglify-js": "github:mishoo/UglifyJS2#harmony",
31 | "webpack": "2.1.0-beta.25",
32 | "webpack-dev-middleware": "^1.8.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Controller/Keyboard.js:
--------------------------------------------------------------------------------
1 | export default class KeyboardController {
2 | constructor() {
3 | this.keys = [
4 | 37, 39, 38, 40, 90, 88, // Player 1 (left, right, up, down, z, x)
5 | ];
6 |
7 | this.status = [
8 | false, false, false, false, false, false, // player 1
9 | false, false, false, false, false, false, // player 2
10 | ];
11 |
12 | this.btnpWait = {};
13 |
14 | document.addEventListener('keydown', event => {
15 | const index = this.keys.indexOf(event.keyCode);
16 | if (index < 0) return false;
17 |
18 | this.status[index] = true;
19 | });
20 |
21 | document.addEventListener('keyup', event => {
22 | const index = this.keys.indexOf(event.keyCode);
23 | if (index < 0) return false;
24 |
25 | this.status[index] = false;
26 | });
27 |
28 | this.api = {
29 | btn: this.btn.bind(this),
30 | btnp: this.btnp.bind(this),
31 | };
32 | }
33 |
34 | btn(which, player = 0) {
35 | return this.status[which];
36 | }
37 |
38 | btnp(which, player = 0) {
39 | const pressed = this.btn(which, player);
40 |
41 | if (!pressed) {
42 | this.btnpWait[`${which}${player}`] = false;
43 | return pressed;
44 | }
45 |
46 | if (this.btnpWait[`${which}${player}`]) return false;
47 |
48 | this.btnpWait[`${which}${player}`] = true;
49 |
50 | setTimeout(() => {
51 | this.btnpWait[`${which}${player}`] = false;
52 | }, 120);
53 |
54 | return pressed;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Ram.js:
--------------------------------------------------------------------------------
1 | export default class Ram {
2 | constructor(size) {
3 | this.size = size;
4 | this.arr = new Uint8Array(size);
5 |
6 | this.api = {
7 | peek: this.peek.bind(this),
8 | poke: this.poke.bind(this),
9 | memset: this.memset.bind(this),
10 | memcpy: this.memcpy.bind(this),
11 | memread: this.memread.bind(this),
12 | memwrite: this.memwrite.bind(this),
13 | reload: this.reload.bind(this),
14 | cstore: this.cstore.bind(this),
15 | };
16 | }
17 |
18 | ifInRange(addr, fn) {
19 | if (addr >= 0x00 && addr < this.size) {
20 | return fn();
21 | }
22 |
23 | throw new Error(`BAD MEMORY ACCESS! 0x${addr.toString(16)}`);
24 | }
25 |
26 | peek(addr) {
27 | return this.ifInRange(addr, () => this.arr[addr]);
28 | }
29 |
30 | poke(addr, val) {
31 | return this.ifInRange(addr, () => this.arr[addr] = val);
32 | }
33 |
34 | memset(dest_addr, value, length) {
35 | this.arr.fill(value, dest_addr, dest_addr + length);
36 | }
37 |
38 | memread(dest_addr, length) {
39 | return this.arr.slice(dest_addr, dest_addr + length);
40 | }
41 |
42 | memwrite(dest_addr, data) {
43 | const length = data.length - 1;
44 | for (let i = 0; i <= length; i++) {
45 | this.arr[dest_addr + i] = data[i];
46 | }
47 | }
48 |
49 | memcpy(dest_addr, source_addr, length) {
50 | length = length - 1;
51 | for (let i = 0; i <= length; i++) {
52 | this.arr[dest_addr + i] = this.arr[source_addr + i];
53 | }
54 | }
55 |
56 | reload() {}
57 |
58 | cstore() {}
59 | }
60 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | body, html {
2 | background: #000;
3 | box-sizing: border-box;
4 | }
5 |
6 | body * {
7 | box-sizing: inherit;
8 | }
9 |
10 | #layout.desktop #screen {
11 | position: fixed;
12 | left: 50%;
13 | top: 50%;
14 | width: 90vmin;
15 | height: 90vmin;
16 | transform: translateX(-50%) translateY(-50%);
17 | }
18 |
19 | #layout.desktop #screen canvas {
20 | width: 100%;
21 | }
22 |
23 | #layout.desktop #mobileButtons {
24 | display: none;
25 | }
26 |
27 | #layout.mobile {
28 | display: flex;
29 | position: fixed;
30 | left: 0;
31 | top: 0;
32 | width: 100%;
33 | height: 100%;
34 | flex-direction: column;
35 | background: #CCC;
36 | }
37 |
38 | #layout.mobile #screen {
39 | position: relative;
40 | padding: 20px;
41 | flex: 1;
42 | }
43 |
44 | #layout.mobile #screen canvas {
45 | width: 100% !important;
46 | border: 20px solid #EEEEEE;
47 | }
48 |
49 | #layout.mobile #mobileButtons {
50 | flex: 1;
51 | position: relative;
52 | }
53 |
54 | #layout.mobile #mobileButtons button {
55 | position: absolute;
56 | display: block;
57 | width: 15%;
58 | height: 0;
59 | padding-bottom: 15%;
60 | background: #aaa;
61 | border-radius: 50%;
62 | outline: none;
63 | border: none;
64 | }
65 |
66 | #layout.mobile #mobileButtons button.b_37 {
67 | right: 38%;
68 | top: 35%;
69 | }
70 |
71 | #layout.mobile #mobileButtons button.b_38 {
72 | right: 25%;
73 | top: 20%;
74 | }
75 |
76 | #layout.mobile #mobileButtons button.b_39 {
77 | right: 12%;
78 | top: 35%;
79 | }
80 |
81 | #layout.mobile #mobileButtons button.b_40 {
82 | right: 25%;
83 | top: 50%;
84 | }
85 |
86 | #layout.mobile #mobileButtons button.b_90 {
87 | left: 25%;
88 | top: 25%;
89 | }
90 |
91 | #layout.mobile #mobileButtons button.b_88 {
92 | left: 15%;
93 | top: 45%;
94 | }
95 |
--------------------------------------------------------------------------------
/utils/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | const srcPath = path.join(__dirname, '../../src');
6 | const outPath = path.join(__dirname, '../../dist');
7 |
8 | const config = {
9 | module: {
10 | loaders: [{
11 | test: /\.css/,
12 | loaders: ['style', 'css'],
13 | }, {
14 | test: /\.js/,
15 | exclude: [/node_modules/],
16 | loader: 'babel',
17 | }, {
18 | test: /\.png/,
19 | loader: 'file',
20 | }, {
21 | test: /\.json/,
22 | loader: 'json',
23 | }],
24 | },
25 |
26 | entry: {
27 | main: path.join(srcPath, '/index.js'),
28 | },
29 |
30 | output: {
31 | path: outPath,
32 | filename: '[name].js',
33 | publicPath: '/',
34 | },
35 |
36 | resolve: {},
37 |
38 | plugins: [
39 | new HtmlWebpackPlugin({
40 | template: path.join(srcPath, 'index.html'),
41 | filename: 'index.html',
42 | inject: 'body',
43 | chunks: ['main'],
44 | }),
45 | ],
46 |
47 | externals: [],
48 | };
49 |
50 | if (process.env.NODE_ENV === 'production') {
51 | config.plugins.push(
52 | new webpack.optimize.UglifyJsPlugin({
53 | compress: {
54 | warnings: false,
55 | dead_code: true,
56 | drop_debugger: true,
57 | conditionals: true,
58 | unsafe: true,
59 | evaluate: true,
60 | booleans: true,
61 | loops: true,
62 | unused: true,
63 | if_return: true,
64 | join_vars: true,
65 | cascade: true,
66 | collapse_vars: true,
67 | negate_iife: true,
68 | pure_getters: true,
69 | drop_console: true,
70 | keep_fargs: false,
71 | },
72 | 'screw-ie8': true,
73 | mangle: true,
74 | stats: true,
75 | })
76 | );
77 | }
78 |
79 | module.exports = config;
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | JSGS is an experimental (WIP) javascript implementation of the Pico-8 fantasy console.
4 |
5 | #### Demos
6 | - [http://hello-world-p8.netlify.com/](http://hello-world-p8.netlify.com/)
7 | - [http://cast.netlify.com/](http://cast.netlify.com/)
8 | - [http://3dcamera.netlify.com/](http://3dcamera.netlify.com/)
9 | - [http://fireball.netlify.com/](http://fireball.netlify.com/)
10 |
11 | #### What's implemented?
12 | - Graphics api, font
13 | - Math api
14 | - Ram / Ram api
15 | - Reading cartridges, running lua code
16 |
17 | #### What's missing / Quirks
18 | - Sound (Help needed)
19 | - sspr function
20 | - Cursor
21 | - stat function
22 | - Not 100% compatible with Pico-8's Lua flavor.
23 | - No shorthand assignments
24 | - all() is not implemented (help needed)
25 |
26 | #### Extra features
27 | - Multiple screen (canvas) support
28 | - CRT Filter (optional)
29 | - On screen / Touch controller (very naìve now)
30 | - Custom color palette
31 |
32 | ### How to use?
33 | It's not yet packaged to be used by importing into your project. For now, the only way to run your cartridges
34 | is manually editing the cartridge url in `src/index.js` file. For cloning/installing/running the project, see
35 | "Development" section below.
36 |
37 | #### Classes / Options
38 | ###### JSGS
39 | The JSGS class is the class which we use for creating pico-8 machine instances.
40 | ```javascript
41 | const machine = new JSGS({
42 | os: new OS(), // an "OS" instance
43 | devices: {
44 | controller: new KeyboardController(), // a "Controller" instance
45 | ram: new Ram(0x8000), // a "Ram" instance
46 | cartridge: "http://example.com/cartridge.p8.png", // url to a p8.png cartridge
47 | screen: [new Screen({ size: 128 })], // An array of "Screen" instances
48 | },
49 | });
50 | ```
51 |
52 | ###### Ram
53 | ```javascipt
54 | // instantiate a 32kb ram
55 | const ram = new Ram(0x8000);
56 | ```
57 |
58 | ###### Screen / CRTScreen
59 | ```javascript
60 | const screen = new Screen({
61 | size: 128, // a px size (number)
62 | palette: Screen.greenPalette // And array of 16 hex colors. Defaults to pico-8 palette
63 | });
64 |
65 | // Screen with crt filter
66 | const crtScreen = new CRTScreen({
67 | size: 128,
68 | });
69 |
70 | // Mount to dom
71 | screen.mountCanvas(element);
72 | crtScreen.mountCanvas(element);
73 | ```
74 |
75 | ## Development
76 | ### Requirements
77 | For development, you will need [Node.js](http://nodejs.org/) >=6.0.0 and NPM(comes bundled with Node.js) installed on your environment.
78 |
79 | ### Install
80 | Clone the project and install dependencies:
81 |
82 | $ git clone https://github.com/burakcan/jsgs.git
83 | $ cd jsgs
84 | $ npm install
85 |
86 | ### Start & watch
87 |
88 | $ npm run start-dev
89 |
90 | Now you can browse the app at http://localhost:4000
91 |
92 | ### Build for production
93 |
94 | $ npm run build
95 |
--------------------------------------------------------------------------------
/src/Screen/index.js:
--------------------------------------------------------------------------------
1 | export default class Screen {
2 | constructor(options) {
3 | this.type = 'defaultScreen';
4 | this.px = options.size / 128;
5 | this.size = options.size;
6 | this.palette = options.palette || this.constructor.defaultPalette;
7 | this.canvas = this.createCanvas(options);
8 | this.ctx = this.canvas.getContext('2d');
9 | }
10 |
11 | update(ram) {
12 | for (let addr = 0x6000; addr <= 0x7FFF; addr++) {
13 | const data = ram.arr[addr];
14 | const dataBinary = ("000000000" + data.toString(2)).substr(-8);
15 | const [color1, color2] = [
16 | this.palette[
17 | parseInt(dataBinary.substring(0, 4), 2)
18 | ],
19 | this.palette[
20 | parseInt(dataBinary.substring(4, 8), 2)
21 | ],
22 | ];
23 |
24 | const i = addr - 0x6000;
25 | const x = (i * 2) % 128;
26 | const y = Math.floor(i / 64);
27 |
28 | this.ctx.fillStyle = color1;
29 | this.ctx.fillRect(x * this.px, y * this.px, this.px, this.px);
30 |
31 | this.ctx.fillStyle = color2;
32 | this.ctx.fillRect(x * this.px + this.px, y * this.px, this.px, this.px);
33 | };
34 | }
35 |
36 | createCanvas({ element, size }) {
37 | const canvas = document.createElement('canvas');
38 | canvas.width = canvas.height = size;
39 |
40 | canvas.style.dispay = 'block';
41 | canvas.style.imageRendering = 'pixelated';
42 |
43 | return canvas;
44 | }
45 |
46 | mountCanvas(element) {
47 | element.appendChild(this.canvas);
48 | }
49 | }
50 |
51 | Screen.utils = {};
52 |
53 | Screen.utils.hexToRgb = function(hex) {
54 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
55 |
56 | return result ? {
57 | r: parseInt(result[1], 16),
58 | g: parseInt(result[2], 16),
59 | b: parseInt(result[3], 16)
60 | } : null;
61 | }
62 |
63 | Screen.utils.componentToHex = function(c) {
64 | var hex = c.toString(16);
65 | return hex.length == 1 ? "0" + hex : hex;
66 | }
67 |
68 | Screen.utils.rgbToHex = function({r, g, b}) {
69 | return "#" + Screen.utils.componentToHex(r) + Screen.utils.componentToHex(g) + Screen.utils.componentToHex(b);
70 | }
71 |
72 |
73 | Screen.defaultPalette = [
74 | '#000000', '#1D2B53', '#7E2553', '#008751',
75 | '#AB5236', '#5F574F', '#C2C3C7', '#FFF1E8',
76 | '#FF004D', '#FFA300', '#FFEC27', '#00E436',
77 | '#29ADFF', '#83769C', '#FF77A8', '#FFCCAA',
78 | ];
79 |
80 | Screen.grayscalePalette = Screen.defaultPalette.map(color => {
81 | const { r, g, b } = Screen.utils.hexToRgb(color);
82 | const w = Math.floor(0.299 * r + 0.587 * g + 0.114 * b);
83 | return Screen.utils.rgbToHex({ r: w, g: w, b: w });
84 | });
85 |
86 | Screen.greenPalette = Screen.defaultPalette.map(color => {
87 | const { r, g, b } = Screen.utils.hexToRgb(color);
88 | const rbc = Math.floor((0.299 * r + 0.587 * g + 0.114 * b) * (1/2));
89 | const gc = Math.floor(rbc * 2);
90 | return Screen.utils.rgbToHex({ r: rbc, g: gc, b: rbc });
91 | });
92 |
--------------------------------------------------------------------------------
/src/OS/readCartridge.lib.js:
--------------------------------------------------------------------------------
1 | // http://www.lexaloffle.com/bbs/?tid=27845
2 |
3 | export default function readCartridge($bmp) {
4 | function pad(byte) {
5 | "use strict";
6 | return byte.toString().replace(/^(.(..)*)$/, '0$1');
7 | }
8 |
9 | function stringy(byte) {
10 | "use strict";
11 | return pad(byte.toString(16));
12 | }
13 |
14 | function buildString(str, len) {
15 | "use strict";
16 | var reg = new RegExp('.{1,' + len + '}', 'g');
17 |
18 | str = str.match(reg);
19 | str.forEach(function (m, idx) {
20 | str[idx] += "\n";
21 | });
22 |
23 | return str.join('');
24 | }
25 |
26 | function decompress(code) {
27 | "use strict";
28 | var mode = 0, copy, i = 8, lua = '', codelen = (code.charCodeAt(4) << 8) | code.charCodeAt(5);
29 | var dict = "\n 0123456789abcdefghijklmnopqrstuvwxyz!#%(){}[]<>+=/*:;.,~_".split('');
30 | var byte, offset, length, buffer;
31 |
32 | while (lua.length < codelen) {
33 | byte = code.charCodeAt(i);
34 |
35 | if (mode === 1) {
36 | lua += code.charAt(i);
37 | mode = 0;
38 | } else if (mode === 2) {
39 | offset = lua.length - ((copy - 60) * 16 + (byte & 15));
40 | length = (byte >> 4) + 2;
41 | buffer = lua.substring(offset, offset + length);
42 | lua += buffer;
43 | mode = 0;
44 | } else if (byte === 0) {
45 | mode = 1;
46 | } else if (byte <= 59) {
47 | lua += dict[byte - 1];
48 | } else if (byte >= 60) {
49 | mode = 2;
50 | copy = byte;
51 | }
52 |
53 | i++;
54 | }
55 |
56 | return lua;
57 | }
58 |
59 | function getData(bmp) {
60 | "use strict";
61 | var gfx = '', map = '', gff = '', music = '', sfx = '', lua = '', imgData = bmp.bitmap, dataLen = imgData.length, i = 0, n = 0, r, g, b, a, byte, compressed, loop, lastbyte, loops = [], mode, speed, start, end, notes = '', tmp_music = [], track, step, note, version;
62 |
63 | if (bmp.width !== 160 || bmp.height !== 205) {
64 | return alert('Image is the wrong size.');
65 | }
66 |
67 | while (i < dataLen) {
68 | // get the last 2 bytes of each value and shift left if necessary
69 | r = (imgData[i++] & 3) << 4;
70 | g = (imgData[i++] & 3) << 2;
71 | b = (imgData[i++] & 3);
72 | a = (imgData[i++] & 3) << 6;
73 |
74 | // compile new byte, convert to hex and pad left if needed
75 | byte = (r | g | b | a);
76 |
77 | if (n < 8192) {
78 | // change endianness and append to output string
79 | gfx += stringy(byte).split('').reverse().join('');
80 | } else if (n < 12288) {
81 | map += stringy(byte);
82 | } else if (n < 12544) {
83 | gff += stringy(byte);
84 | } else if (n < 12800) {
85 | track = Math.floor((n - 12544) / 4);
86 | note = stringy(byte & 127);
87 |
88 | if (n % 4 === 0) {
89 | tmp_music.push([null, '']);
90 | }
91 |
92 | tmp_music[track][0] = stringy(((byte & 128) >> 7 - n % 4) | tmp_music[track][0]);
93 | tmp_music[track][1] += note;
94 | } else if (n < 17152) {
95 | step = (n - 12800) % 68;
96 |
97 | if (step < 64 && n % 2 === 1) {
98 | note = (byte << 8) + lastbyte;
99 | notes += (stringy(note & 63) + ((note & 448) >> 6).toString(16) + ((note & 3584) >> 9).toString(16) + ((note & 28672) >> 12).toString(16));
100 | } else if (step === 64) {
101 | mode = pad(byte);
102 | } else if (step === 65) {
103 | speed = byte;
104 | } else if (step === 66) {
105 | start = byte;
106 | } else if (step === 67) {
107 | end = byte;
108 | sfx += mode + stringy(speed) + stringy(start) + stringy(end) + notes + "\n";
109 | notes = '';
110 | }
111 | } else if (n < 32768) {
112 | if (n === 17152) {
113 | compressed = (byte === 58);
114 | }
115 |
116 | lua += String.fromCharCode(byte);
117 | } else if (n === 32768) {
118 | version = byte;
119 | }
120 |
121 | lastbyte = byte;
122 | n++;
123 | }
124 |
125 | if (compressed) lua = decompress(lua);
126 | gfx = buildString(gfx, 128);
127 | gff = buildString(gff, 256);
128 | map = buildString(map, 256);
129 |
130 | tmp_music.forEach(function (m) {
131 | music += m[0] + ' ' + m[1] + "\n";
132 | });
133 |
134 | const result = {
135 | version: version,
136 | code: lua,
137 | gfx: gfx.replace(/(\r\n|\n|\r)/gm,""),
138 | gff: gff.replace(/(\r\n|\n|\r)/gm,""),
139 | map: map.replace(/(\r\n|\n|\r)/gm,""),
140 | sfx: sfx.replace(/(\r\n|\n|\r)/gm,""),
141 | music: music.replace(/(\r\n|\n|\r)/gm,""),
142 | };
143 |
144 | return result;
145 | }
146 |
147 | return getData($bmp);
148 | };
149 |
--------------------------------------------------------------------------------
/src/OS/index.js:
--------------------------------------------------------------------------------
1 | import getGraphicsFunctions from './graphics.lib';
2 | import getSoundFunctions from './sound.lib';
3 | import mathLib from './math.lib';
4 | import readCartridge from './readCartridge.lib';
5 | import lua2js from 'lua2js';
6 | import escodegen from 'escodegen';
7 | import estraverse from 'estraverse';
8 |
9 | export default class OS {
10 | constructor(machine) {
11 | this.$ = {};
12 | this.bootTime = 0;
13 | }
14 |
15 | sendEvent(type, machine, payload) {
16 | switch (type) {
17 | case 'boot':
18 | this.boot(machine);
19 | break;
20 |
21 | case 'cartridgeMount':
22 | this.boot(machine).then(
23 | () => this.cartridgeMount(machine)
24 | );
25 | break;
26 |
27 | case 'cartridgeEject':
28 | this.boot(machine).then(
29 | () => this.cartridgeEject(machine)
30 | );
31 | break;
32 | }
33 |
34 | return this;
35 | }
36 |
37 | boot(machine) {
38 | if (this.bootProgress) return this.bootProgress;
39 | this.bootProgress = new Promise(resolve => {
40 | this.$ = Object.assign(
41 | this.$,
42 | lua2js.stdlib,
43 | machine.devices.ram.api,
44 | mathLib,
45 | getGraphicsFunctions(machine.devices.ram),
46 | getSoundFunctions(machine.devices.ram),
47 | machine.devices.controller.api,
48 | { time: this.getUptime.bind(this) }
49 | );
50 |
51 | // flush defaults to ram
52 | this.$.clip();
53 | this.$.color(6);
54 |
55 | // return resolve(this); // DEVELOPMENT
56 |
57 | let i = 1;
58 |
59 | const loadingAnim = setInterval(() => {
60 | this.$.cls();
61 | if (i >= 98) {
62 | this.bootTime = Date.now();
63 | clearInterval(loadingAnim);
64 | resolve(this);
65 | } else {
66 | this.$.print("javascript gaming system", 4, 4, 8);
67 | if (i >= 20) this.$.print("checking devices", 4, 12, 7);
68 |
69 | if (i >= 40) {
70 | this.$.print('booting' + '.'.repeat(Math.floor((i-40) / 15)), 4, 20, 7);
71 | }
72 |
73 | i += parseInt(Math.random() * 2);
74 | }
75 | }, 10);
76 | });
77 |
78 | return this.bootProgress;
79 | }
80 |
81 | cartridgeMount(machine) {
82 | const { cartridge } = machine.devices;
83 |
84 | this.$.print("reading cartridge", 4, 4, 7);
85 |
86 | this
87 | .loadCartridge(cartridge, machine)
88 | .then(cartridgeData =>
89 | setTimeout(() => this.runCartridge(cartridgeData), 500)
90 | );
91 | }
92 |
93 | cartridgeEject(machine) {
94 | console.log('ejected', machine);
95 | }
96 |
97 | loadCartridge(url, machine) {
98 | const png = new PngToy();
99 |
100 | return (
101 | png
102 | .fetch(url)
103 | .then(() => png.decode().then(readCartridge))
104 | .then(cartridgeData => {
105 | let gfxi = 0;
106 | const gfxData = cartridgeData.gfx + cartridgeData.map + cartridgeData.gff;
107 | for (let x = 0x0000; x <= 0x30ff; x++) {
108 | machine.devices.ram.poke(x,
109 | parseInt(`${gfxData[gfxi]}${gfxData[gfxi+1]}`, 16)
110 | );
111 | gfxi = gfxi + 2;
112 | }
113 |
114 | let sfxi = 0;
115 | for (let x = 0x3200; x <= 0x42ff; x++) {
116 | machine.devices.ram.poke(x,
117 | parseInt(`${cartridgeData.sfx[sfxi]}${cartridgeData.sfx[sfxi+1]}`, 16)
118 | );
119 | sfxi = sfxi + 2;
120 | }
121 |
122 | return cartridgeData;
123 | })
124 | );
125 | }
126 |
127 | runCartridge(____cartridgeData____) {
128 | this.$.cls();
129 | const ____BLACKLIST____ =
130 | Object
131 | .keys(window)
132 | .join()
133 | .replace('console', '_');
134 |
135 | const ____self____ = this;
136 | const ____api____ = Object.keys(this.$).map(key => {
137 | if (typeof ____self____.$[key] === 'function') {
138 | return `
139 | function ${ key }() {
140 | return ____self____.$['${key}'].apply(null, arguments);
141 | }
142 | `;
143 | }
144 | return '';
145 | });
146 |
147 | ____api____.push(`var __lua = ____self____.$.__lua`);
148 |
149 | /*h*/eval(`
150 | (function(${____BLACKLIST____}) {
151 | ${ ____api____.join(';') }
152 |
153 | function _init() {}
154 | function _update() {}
155 | function _draw() {}
156 |
157 | function add(tbl, item) {
158 | console.log(tbl, item);
159 | tbl[Object.keys(tbl).length] = item;
160 | }
161 |
162 | function all() {
163 | return [() => {}, () => {}, () => {}];
164 | }
165 |
166 | function count(tbl) {
167 | return Object.keys(tbl).length;
168 | }
169 |
170 | function menuitem() {}
171 |
172 | ${ this.transpileLua(____cartridgeData____.code).replace('~=', '!=') }
173 |
174 | _init()
175 | _update();
176 | _draw();
177 |
178 | ____self____._draw = _draw;
179 | ____self____._update = _update;
180 | })();
181 | `);
182 | }
183 |
184 | _update() {}
185 | _draw() {}
186 |
187 | update() {
188 | this._update();
189 | this._draw();
190 | }
191 |
192 | transpileLua(code) {
193 | const ast = lua2js.parse(code, {
194 | decorateLuaObjects: false,
195 | encloseWithFunctions: false,
196 | forceVar: false,
197 | luaCalls: false,
198 | luaOperators: false,
199 | noSharedObjects: false,
200 | allowRegularFunctions: true,
201 | });
202 |
203 | const result = escodegen.generate(ast);
204 | const globalVars = [];
205 |
206 | estraverse.traverse(ast, {
207 | enter(node, parent) {
208 | if (node.type === "AssignmentExpression" &&
209 | node.left.name &&
210 | !globalVars.includes(node.left.name)
211 | ) {
212 | globalVars.push(node.left.name);
213 | }
214 | },
215 | });
216 |
217 | return `
218 | var ${globalVars.join()};
219 | ${result.substring(1, result.length - 1)}
220 | `;
221 | }
222 |
223 | getUptime() {
224 | return Date.now() - this.bootTime;
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/src/OS/font.lib.js:
--------------------------------------------------------------------------------
1 | export default {
2 | a: [
3 | 1, 1, 1,
4 | 1, 0, 1,
5 | 1, 1, 1,
6 | 1, 0, 1,
7 | 1, 0, 1,
8 | ],
9 | b: [
10 | 1, 1, 1,
11 | 1, 0, 1,
12 | 1, 1, 0,
13 | 1, 0, 1,
14 | 1, 1, 1,
15 | ],
16 | c: [
17 | 0, 1, 1,
18 | 1, 0, 0,
19 | 1, 0, 0,
20 | 1, 0, 0,
21 | 0, 1, 1,
22 | ],
23 | d: [
24 | 1, 1, 0,
25 | 1, 0, 1,
26 | 1, 0, 1,
27 | 1, 0, 1,
28 | 1, 1, 1,
29 | ],
30 | e: [
31 | 1, 1, 1,
32 | 1, 0, 0,
33 | 1, 1, 0,
34 | 1, 0, 0,
35 | 1, 1, 1,
36 | ],
37 | f: [
38 | 1, 1, 1,
39 | 1, 0, 0,
40 | 1, 1, 0,
41 | 1, 0, 0,
42 | 1, 0, 0,
43 | ],
44 | g: [
45 | 0, 1, 1,
46 | 1, 0, 0,
47 | 1, 0, 0,
48 | 1, 0, 1,
49 | 1, 1, 1,
50 | ],
51 | h: [
52 | 1, 0, 1,
53 | 1, 0, 1,
54 | 1, 1, 1,
55 | 1, 0, 1,
56 | 1, 0, 1,
57 | ],
58 | i: [
59 | 1, 1, 1,
60 | 0, 1, 0,
61 | 0, 1, 0,
62 | 0, 1, 0,
63 | 1, 1, 1,
64 | ],
65 | j: [
66 | 1, 1, 1,
67 | 0, 1, 0,
68 | 0, 1, 0,
69 | 0, 1, 0,
70 | 1, 1, 0,
71 | ],
72 | k: [
73 | 1, 0, 1,
74 | 1, 0, 1,
75 | 1, 1, 0,
76 | 1, 0, 1,
77 | 1, 0, 1,
78 | ],
79 | l: [
80 | 1, 0, 0,
81 | 1, 0, 0,
82 | 1, 0, 0,
83 | 1, 0, 0,
84 | 1, 1, 1,
85 | ],
86 | m: [
87 | 1, 1, 1,
88 | 1, 1, 1,
89 | 1, 0, 1,
90 | 1, 0, 1,
91 | 1, 0, 1,
92 | ],
93 | n: [
94 | 1, 1, 0,
95 | 1, 0, 1,
96 | 1, 0, 1,
97 | 1, 0, 1,
98 | 1, 0, 1,
99 | ],
100 | o: [
101 | 0, 1, 1,
102 | 1, 0, 1,
103 | 1, 0, 1,
104 | 1, 0, 1,
105 | 1, 1, 0,
106 | ],
107 | p: [
108 | 1, 1, 1,
109 | 1, 0, 1,
110 | 1, 1, 1,
111 | 1, 0, 0,
112 | 1, 0, 0,
113 | ],
114 | q: [
115 | 0, 1, 0,
116 | 1, 0, 1,
117 | 1, 0, 1,
118 | 1, 1, 0,
119 | 0, 1, 1,
120 | ],
121 | r: [
122 | 1, 1, 1,
123 | 1, 0, 1,
124 | 1, 1, 0,
125 | 1, 0, 1,
126 | 1, 0, 1,
127 | ],
128 | s: [
129 | 0, 1, 1,
130 | 1, 0, 0,
131 | 1, 1, 1,
132 | 0, 0, 1,
133 | 1, 1, 0,
134 | ],
135 | t: [
136 | 1, 1, 1,
137 | 0, 1, 0,
138 | 0, 1, 0,
139 | 0, 1, 0,
140 | 0, 1, 0,
141 | ],
142 | u: [
143 | 1, 0, 1,
144 | 1, 0, 1,
145 | 1, 0, 1,
146 | 1, 0, 1,
147 | 0, 1, 1,
148 | ],
149 | v: [
150 | 1, 0, 1,
151 | 1, 0, 1,
152 | 1, 0, 1,
153 | 1, 0, 1,
154 | 0, 1, 0,
155 | ],
156 | w: [
157 | 1, 0, 1,
158 | 1, 0, 1,
159 | 1, 0, 1,
160 | 1, 1, 1,
161 | 1, 1, 1,
162 | ],
163 | x: [
164 | 1, 0, 1,
165 | 1, 0, 1,
166 | 0, 1, 0,
167 | 1, 0, 1,
168 | 1, 0, 1,
169 | ],
170 | y: [
171 | 1, 0, 1,
172 | 1, 0, 1,
173 | 1, 1, 1,
174 | 0, 0, 1,
175 | 1, 1, 1,
176 | ],
177 | z: [
178 | 1, 1, 1,
179 | 0, 0, 1,
180 | 0, 1, 0,
181 | 1, 0, 0,
182 | 1, 1, 1,
183 | ],
184 | "0": [
185 | 1, 1, 1,
186 | 1, 0, 1,
187 | 1, 0, 1,
188 | 1, 0, 1,
189 | 1, 1, 1,
190 | ],
191 | "1": [
192 | 1, 1, 0,
193 | 0, 1, 0,
194 | 0, 1, 0,
195 | 0, 1, 0,
196 | 1, 1, 1,
197 | ],
198 | "2": [
199 | 1, 1, 1,
200 | 0, 0, 1,
201 | 1, 1, 1,
202 | 1, 0, 0,
203 | 1, 1, 1,
204 | ],
205 | "3": [
206 | 1, 1, 1,
207 | 0, 0, 1,
208 | 0, 1, 1,
209 | 0, 0, 1,
210 | 1, 1, 1,
211 | ],
212 | "4": [
213 | 1, 0, 1,
214 | 1, 0, 1,
215 | 1, 1, 1,
216 | 0, 0, 1,
217 | 0, 0, 1,
218 | ],
219 | "5": [
220 | 1, 1, 1,
221 | 1, 0, 0,
222 | 1, 1, 1,
223 | 0, 0, 1,
224 | 1, 1, 1,
225 | ],
226 | "6": [
227 | 1, 0, 0,
228 | 1, 0, 0,
229 | 1, 1, 1,
230 | 1, 0, 1,
231 | 1, 1, 1,
232 | ],
233 | "7": [
234 | 1, 1, 1,
235 | 0, 0, 1,
236 | 0, 0, 1,
237 | 0, 0, 1,
238 | 0, 0, 1,
239 | ],
240 | "8": [
241 | 1, 1, 1,
242 | 1, 0, 1,
243 | 1, 1, 1,
244 | 1, 0, 1,
245 | 1, 1, 1,
246 | ],
247 | "9": [
248 | 1, 1, 1,
249 | 1, 0, 1,
250 | 1, 1, 1,
251 | 0, 0, 1,
252 | 0, 0, 1,
253 | ],
254 | "!": [
255 | 0, 1, 0,
256 | 0, 1, 0,
257 | 0, 1, 0,
258 | 0, 0, 0,
259 | 0, 1, 0,
260 | ],
261 | '"': [
262 | 1, 0, 1,
263 | 1, 0, 1,
264 | 0, 0, 0,
265 | 0, 0, 0,
266 | 0, 0, 0,
267 | ],
268 | "#": [
269 | 1, 0, 1,
270 | 1, 1, 1,
271 | 1, 0, 1,
272 | 1, 1, 1,
273 | 1, 0, 1,
274 | ],
275 | "%": [
276 | 1, 0, 1,
277 | 0, 0, 1,
278 | 0, 1, 0,
279 | 1, 0, 0,
280 | 1, 0, 1,
281 | ],
282 | "'": [
283 | 0, 1, 0,
284 | 1, 0, 0,
285 | 0, 0, 0,
286 | 0, 0, 0,
287 | 0, 0, 0,
288 | ],
289 | "(": [
290 | 0, 1, 0,
291 | 1, 0, 0,
292 | 1, 0, 0,
293 | 1, 0, 0,
294 | 0, 1, 0,
295 | ],
296 | ")": [
297 | 0, 1, 0,
298 | 0, 0, 1,
299 | 0, 0, 1,
300 | 0, 0, 1,
301 | 0, 1, 0,
302 | ],
303 | "*": [
304 | 1, 0, 1,
305 | 0, 1, 0,
306 | 1, 1, 1,
307 | 0, 1, 0,
308 | 1, 0, 1,
309 | ],
310 | "+": [
311 | 0, 0, 0,
312 | 0, 1, 0,
313 | 1, 1, 1,
314 | 0, 1, 0,
315 | 0, 0, 0,
316 | ],
317 | ",": [
318 | 0, 0, 0,
319 | 0, 0, 0,
320 | 0, 0, 0,
321 | 0, 1, 0,
322 | 1, 0, 0,
323 | ],
324 | "-": [
325 | 0, 0, 0,
326 | 0, 0, 0,
327 | 1, 1, 1,
328 | 0, 0, 0,
329 | 0, 0, 0,
330 | ],
331 | ".": [
332 | 0, 0, 0,
333 | 0, 0, 0,
334 | 0, 0, 0,
335 | 0, 0, 0,
336 | 0, 1, 0,
337 | ],
338 | "/": [
339 | 0, 0, 1,
340 | 0, 1, 0,
341 | 0, 1, 0,
342 | 0, 1, 0,
343 | 1, 0, 0,
344 | ],
345 | ":": [
346 | 0, 0, 0,
347 | 0, 1, 0,
348 | 0, 0, 0,
349 | 0, 1, 0,
350 | 0, 0, 0,
351 | ],
352 | "<": [
353 | 0, 0, 1,
354 | 0, 1, 0,
355 | 1, 0, 0,
356 | 0, 1, 0,
357 | 0, 0, 1,
358 | ],
359 | ">": [
360 | 1, 0, 0,
361 | 0, 1, 0,
362 | 0, 0, 1,
363 | 0, 1, 0,
364 | 1, 0, 0,
365 | ],
366 | "=": [
367 | 0, 0, 0,
368 | 1, 1, 1,
369 | 0, 0, 0,
370 | 1, 1, 1,
371 | 0, 0, 0,
372 | ],
373 | "?": [
374 | 1, 1, 1,
375 | 0, 0, 1,
376 | 0, 1, 1,
377 | 0, 0, 0,
378 | 0, 1, 0,
379 | ],
380 | "[": [
381 | 1, 1, 0,
382 | 1, 0, 0,
383 | 1, 0, 0,
384 | 1, 0, 0,
385 | 1, 1, 0,
386 | ],
387 | "]": [
388 | 0, 1, 1,
389 | 0, 0, 1,
390 | 0, 0, 1,
391 | 0, 0, 1,
392 | 0, 1, 1,
393 | ],
394 | "^": [
395 | 0, 1, 0,
396 | 1, 0, 1,
397 | 0, 0, 0,
398 | 0, 0, 0,
399 | 0, 0, 0,
400 | ],
401 | "~": [
402 | 0, 0, 0,
403 | 0, 0, 1,
404 | 1, 1, 1,
405 | 1, 0, 0,
406 | 0, 0, 0,
407 | ],
408 | }
409 |
--------------------------------------------------------------------------------
/src/OS/graphics.lib.js:
--------------------------------------------------------------------------------
1 | import font from './font.lib';
2 |
3 | export default function getGraphicsFunctions(ram) {
4 | function memoize(fn) {
5 | return function () {
6 | var args = Array.prototype.slice.call(arguments),
7 | hash = "",
8 | i = args.length;
9 | let currentArg = null;
10 | while (i--) {
11 | currentArg = args[i];
12 | hash += (currentArg === Object(currentArg)) ?
13 | JSON.stringify(currentArg) : currentArg;
14 | fn.memoize || (fn.memoize = {});
15 | }
16 | return (hash in fn.memoize) ? fn.memoize[hash] :
17 | fn.memoize[hash] = fn.apply(this, args);
18 | };
19 | }
20 |
21 | function _color8toHexStr(color8) {
22 | return (
23 | (str => '00'.substring(0, 2 - str.length) + str)
24 | (color8.toString(16))
25 | );
26 | }
27 |
28 | const flags = [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80];
29 | const initialColors = [
30 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
31 | 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
32 | ];
33 |
34 | const color8toHexStr = memoize(_color8toHexStr);
35 |
36 | function pget(x, y) {
37 | x = Math.floor(x);
38 | y = Math.floor(y);
39 |
40 | if (
41 | x < 0 || x > 127 ||
42 | y < 0 || y > 127
43 | ) {
44 | return 0;
45 | }
46 |
47 | const addr = 0x6000 + (64 * y) + Math.floor(x / 2);
48 | const side = x % 2 === 0 ? 'left' : 'right';
49 |
50 | if (side === 'left') {
51 | return parseInt(color8toHexStr(ram.peek(addr))[0], 16);
52 | } else if (side === 'right') {
53 | return parseInt(color8toHexStr(ram.peek(addr))[0], 16);
54 | }
55 | }
56 |
57 | function pset(x, y, colorIndex, color8) {
58 | const [camX, camY] = _getCamera();
59 | const [cx1, cy1, cx2, cy2] = _getClip();
60 |
61 | x = Math.floor(x + camX);
62 | y = Math.floor(y + camY);
63 |
64 | if (
65 | x < cx1 || x > cx2 ||
66 | y < cy1 || y > cy2
67 | ) {
68 | return false;
69 | }
70 |
71 | const drawPalette = ram.memread(0x5000, 16);
72 |
73 | if (colorIndex === undefined) {
74 | colorIndex = ram.arr[0x5f25]; // default color: color()
75 | }
76 |
77 | let colorStr;
78 |
79 | if (!color8) {
80 | color8 = drawPalette[colorIndex % 16];
81 | } else {
82 | color8 = drawPalette[initialColors.indexOf(color8)];
83 | }
84 |
85 | const addr = 0x6000 + (64 * y) + Math.floor(x / 2);
86 | const beforePoke = color8toHexStr(ram.arr[addr]);
87 | const side = x % 2 === 0 ? 'left' : 'right';
88 |
89 | if (side === 'left') {
90 | colorStr = color8toHexStr(color8)[0] + beforePoke[1];
91 | } else if (side === 'right') {
92 | colorStr = beforePoke[0] + color8toHexStr(color8)[0];
93 | }
94 |
95 | ram.arr[addr] = parseInt(colorStr, 16);
96 | }
97 |
98 | function cls() {
99 | ram.memset(0x6000, 0x00, 0x8000 - 0x6000);
100 | }
101 |
102 | function line(x0, y0, x1, y1, colorIndex){
103 | x0 = Math.floor(x0);
104 | y0 = Math.floor(y0);
105 | x1 = Math.floor(x1);
106 | y1 = Math.floor(y1);
107 |
108 | if (colorIndex === undefined) {
109 | colorIndex = ram.peek(0x5f25);
110 | }
111 |
112 | let dx = Math.abs(x1-x0);
113 | let dy = Math.abs(y1-y0);
114 | let sx = (x0 < x1) ? 1 : -1;
115 | let sy = (y0 < y1) ? 1 : -1;
116 | let err = dx-dy;
117 |
118 | while(true){
119 | pset(x0, y0, colorIndex);
120 |
121 | if ((x0 === x1) && (y0 === y1)) break;
122 | const e2 = 2 * err;
123 | if (e2 >- dy){ err -= dy; x0 += sx; }
124 | if (e2 < dx){ err += dx; y0 += sy; }
125 | }
126 | }
127 |
128 | function rect(x1, y1, x2, y2, colorIndex) {
129 | if (colorIndex === undefined) {
130 | colorIndex = ram.peek(0x5f25);
131 | }
132 |
133 | line(x1, y1, x2, y1, colorIndex);
134 | line(x1, y1, x1, y2, colorIndex);
135 | line(x2, y1, x2, y2, colorIndex);
136 | line(x1, y2, x2, y2, colorIndex);
137 | }
138 |
139 | function rectfill(x1, y1, x2, y2, colorIndex) {
140 | if (colorIndex === undefined) {
141 | colorIndex = ram.peek(0x5f25);
142 | }
143 |
144 | for (let i = y1; i < y2; i++) {
145 | for (let j = x1; j < x2 ; j++) {
146 | pset(j, i, colorIndex);
147 | }
148 | }
149 | }
150 |
151 | function circ(x0, y0, r, colorIndex) {
152 | x0 = Math.floor(x0);
153 | y0 = Math.floor(y0);
154 | r = Math.floor(r);
155 |
156 | if (colorIndex === undefined) {
157 | colorIndex = ram.peek(0x5f25);
158 | }
159 |
160 | let x = r - 1;
161 | let y = 0;
162 | let rError = 1 - x;
163 |
164 | while (x >= y) {
165 | pset(x + x0, y + y0, colorIndex);
166 | pset(y + x0, x + y0, colorIndex);
167 | pset(-x + x0, y + y0, colorIndex);
168 | pset(-y + x0, x + y0, colorIndex);
169 | pset(-x + x0, -y + y0, colorIndex);
170 | pset(-y + x0, -x + y0, colorIndex);
171 | pset(x + x0, -y + y0, colorIndex);
172 | pset(y + x0, -x + y0, colorIndex);
173 | y++;
174 |
175 | if (rError < 0) {
176 | rError += 2 * y + 1;
177 | } else {
178 | x--;
179 | rError+= 2 * (y - x + 1);
180 | }
181 | }
182 | }
183 |
184 | function circfill(x0, y0, radius, colorIndex) {
185 | let x = radius - 1;
186 | let y = 0;
187 | let radiusError = 1 - x;
188 |
189 | if (colorIndex === undefined) {
190 | colorIndex = ram.peek(0x5f25);
191 | }
192 |
193 | while (x >= y) {
194 | line(-x + x0, y + y0, x + x0, y + y0, colorIndex);
195 | line(-y + x0, x + y0, y + x0, x + y0, colorIndex);
196 | line(-x + x0, -y + y0, x + x0, -y + y0, colorIndex);
197 | line(-y + x0, -x + y0, y + x0, -x + y0, colorIndex);
198 | y++;
199 |
200 | if (radiusError < 0) {
201 | radiusError += 2 * y + 1;
202 | } else {
203 | x--;
204 | radiusError+= 2 * (y - x + 1);
205 | }
206 | }
207 | }
208 |
209 | function mset(celX, celY, sNum) {
210 | let mapStartAddr = 0x2000; // Map (rows 0-31)
211 |
212 | if (celY >= 32) {
213 | mapStartAddr = 0x1000;
214 | }
215 |
216 | const tile = (celY * 128) + celX;
217 | ram.arr[mapStartAddr + tile] = sNum;
218 | }
219 |
220 | function mget(celX, celY) {
221 | celX = Math.floor(celX);
222 | celY = Math.floor(celY);
223 |
224 | let mapStartAddr = 0x2000; // Map (rows 0-31)
225 |
226 | if (celY >= 32) {
227 | mapStartAddr = 0x1000;
228 | }
229 |
230 | const tile = (celY * 128) + celX;
231 | return ram.arr[mapStartAddr + tile];
232 | }
233 |
234 | function map(celX, celY, sx, sy, celW, celH, layer) {
235 | for (let x = celX; x < celX + celW; x++) {
236 | for (let y = celY; y < celY + celH; y++) {
237 | const sprNum = mget(x, y);
238 |
239 | if (layer !== undefined && !fget(sprNum, layer)) {
240 | continue;
241 | }
242 |
243 | if (sprNum !== 0) {
244 | spr(sprNum, sx + ((x - celX) * 8), sy + ((y - celY) * 8));
245 | }
246 | }
247 | }
248 | }
249 |
250 | function spr(n, x, y, w, h, flip_x, flip_y) {
251 | x = Math.floor(x);
252 | y = Math.floor(y);
253 |
254 | const sx = (n % 16) * 4;
255 | const sy = Math.floor(n / 16) * 8;
256 | const startAddr = 0x0000 + sx + (sy * 64);
257 | const drawPalette = ram.memread(0x5000, 16);
258 |
259 | for (let i = 0; i < 8; i++) {
260 | for (let j = 0; j < 8; j=j+2) {
261 | const val = ram.arr[startAddr + (64 * i) + j / 2];
262 | const str = color8toHexStr(val);
263 |
264 | let x1 = flip_x ? x - j + 7 : x + j;
265 | let x2 = flip_x ? x - j + 6 : x + j + 1;
266 |
267 | let y1 = flip_y ? y - i + 7 : y + i;
268 | let y2 = y1;
269 |
270 | if (color8toHexStr(drawPalette[parseInt(str[0], 16)])[1] === "0") {
271 | pset(
272 | x1,
273 | y1,
274 | null,
275 | parseInt(str[0] + '0', 16)
276 | );
277 | }
278 |
279 | if (color8toHexStr(drawPalette[parseInt(str[1], 16)])[1] === "0") {
280 | pset(
281 | x2,
282 | y2,
283 | null,
284 | parseInt(str[1] + '0', 16)
285 | );
286 | }
287 | }
288 | }
289 | }
290 |
291 | function sget(x, y) {
292 | x = Math.floor(x);
293 | y = Math.floor(y);
294 |
295 | const addr = 0x0000 + (64 * y) + Math.floor(x / 2);
296 | const side = x % 2 === 0 ? 'left' : 'right';
297 |
298 | if (side === 'left') {
299 | return parseInt(color8toHexStr(ram.peek(addr))[0], 16);
300 | } else if (side === 'right') {
301 | return parseInt(color8toHexStr(ram.peek(addr))[0], 16);
302 | }
303 | }
304 |
305 | function sset(x, y, colorIndex) {
306 | x = Math.floor(x);
307 | y = Math.floor(y);
308 |
309 | const drawPalette = ram.memread(0x5000, 16);
310 |
311 | if (colorIndex === undefined) {
312 | colorIndex = ram.peek(0x5f25);
313 | }
314 |
315 | let colorStr;
316 |
317 | const color8 = drawPalette[colorIndex % 16];
318 | const addr = 0x0000 + (64 * y) + Math.floor(x / 2);
319 | const beforePoke = color8toHexStr(ram.peek(addr));
320 | const side = x % 2 === 0 ? 'left' : 'right';
321 |
322 | if (side === 'left') {
323 | colorStr = color8toHexStr(color8)[0] + beforePoke[1];
324 | } else if (side === 'right') {
325 | colorStr = beforePoke[0] + color8toHexStr(color8)[0];
326 | }
327 |
328 | ram.poke(addr, parseInt(colorStr, 16));
329 | }
330 |
331 | function print(text, x = 0, y = 0, colorIndex) {
332 | x = Math.floor(x);
333 | y = Math.floor(y);
334 | text = String(text);
335 |
336 | if (colorIndex === undefined) {
337 | colorIndex = ram.peek(0x5f25);
338 | }
339 |
340 | text = text.toLowerCase();
341 | for (let i = 0; i < text.length; i++) {
342 | const letter = font[text[i]];
343 |
344 | if (!letter) continue;
345 |
346 | for (let j = 0; j < 15; j++) {
347 | const lx = j % 3;
348 | const ly = Math.floor(j / 3);
349 |
350 | if (letter[j]) {
351 | pset(
352 | lx + x + (i * 4),
353 | ly + y,
354 | colorIndex
355 | );
356 | }
357 | }
358 | }
359 | }
360 |
361 | function pal(c1, c2, p = 0) {
362 | if (c1 === undefined && c2 === undefined) {
363 | ram.memwrite(0x5000, initialColors); // load initial draw palette to ram
364 | ram.memwrite(0x5f10, initialColors); // load initial screen palette to ram
365 | return;
366 | }
367 |
368 | let startAddr = 0x5000; // draw palette
369 |
370 | if (p === 1) {
371 | startAddr = 0x5f10;
372 | }
373 |
374 | const drawPalette = ram.memread(startAddr, 16);
375 | drawPalette[c1] = initialColors[c2];
376 | ram.memwrite(startAddr, drawPalette);
377 | }
378 |
379 | function palt(c, t) {
380 | if (c === undefined && t === undefined) {
381 | ram.memwrite(0x5000, initialColors); // load initial draw palette to ram
382 | palt(0, true);
383 | return;
384 | }
385 |
386 | const current = ram.peek(0x5000 + c);
387 | let str = color8toHexStr(current);
388 |
389 | if (t) {
390 | str = str[0] + "1";
391 | } else {
392 | str = str[0] + "0";
393 | }
394 |
395 | ram.poke(0x5000 + c, parseInt(str, 16));
396 | }
397 |
398 | function _getCamera() {
399 | const xSign = ram.arr[0x5f28] === 1 ? -1 : 1;
400 | const ySign = ram.arr[0x5f2a] === 1 ? -1 : 1;
401 |
402 | const x = ram.arr[0x5f29];
403 | const y = ram.arr[0x5f2b];
404 |
405 | return [
406 | x * xSign,
407 | y * ySign,
408 | ];
409 | }
410 |
411 | function camera(x = 0, y = 0) {
412 | x = Math.floor(x);
413 | y = Math.floor(y);
414 |
415 | if (x < 0) { ram.poke(0x5f28, 1) } else { ram.poke(0x5f28, 0) }
416 | if (y < 0) { ram.poke(0x5f2a, 1) } else { ram.poke(0x5f2a, 0) }
417 |
418 | ram.poke(0x5f29, Math.abs(x));
419 | ram.poke(0x5f2b, Math.abs(y));
420 | }
421 |
422 | function _getClip() {
423 | return [
424 | ram.arr[0x5f20],
425 | ram.arr[0x5f21],
426 | ram.arr[0x5f22],
427 | ram.arr[0x5f23],
428 | ];
429 | }
430 |
431 | function clip(x = 0, y = 0, w = 127, h = 127) {
432 | x = Math.floor(x);
433 | y = Math.floor(y);
434 | w = Math.floor(w);
435 | h = Math.floor(h);
436 |
437 | ram.poke(0x5f20, x);
438 | ram.poke(0x5f21, y);
439 | ram.poke(0x5f22, x + w);
440 | ram.poke(0x5f23, y + h);
441 | }
442 |
443 | function color(colorIndex = 0) {
444 | ram.poke(0x5f25, colorIndex);
445 | }
446 |
447 | function _getCursor() {
448 | // TODO: Implement usage of this to print
449 | return [
450 | ram.peek(0x5f26),
451 | ram.peek(0x5f27),
452 | ];
453 | }
454 |
455 | function cursor(x, y) {
456 | // TODO: Implement usage of this to print
457 |
458 | x = Math.floor(x);
459 | y = Math.floor(y);
460 |
461 | ram.poke(0x5f26, x);
462 | ram.poke(0x5f27, y);
463 | }
464 |
465 | function fget(n, f) {
466 | const addr = 0x3000 + n;
467 |
468 | if (f === undefined) {
469 | return ram.arr[addr];
470 | }
471 |
472 | return (ram.arr[addr] & flags[f]) === flags[f];
473 | }
474 |
475 | function fset(n, f, v) {
476 | const addr = 0x3000 + n;
477 |
478 | if (arguments.length === 2) {
479 | return ram.poke(addr, f);
480 | }
481 |
482 | if (fget(n, f) && v) {
483 | return;
484 | }
485 |
486 | if (fget(n, f) && !v) {
487 | ram.poke(addr, fget(n) - flags[f]);
488 | }
489 |
490 | if (!fget(n, f) && v) {
491 | ram.poke(addr, fget(n) + flags[f]);
492 | }
493 | }
494 |
495 | function stat() {
496 | return '';
497 | }
498 |
499 | ram.memwrite(0x5000, initialColors); // load initial draw palette to ram
500 | ram.memwrite(0x5f10, initialColors); // load initial screen palette to ram
501 | palt(0, true);
502 |
503 | return {
504 | camera,
505 | clip,
506 | cls,
507 | color,
508 | cursor,
509 | fget,
510 | fset,
511 | pget,
512 | pset,
513 | line,
514 | rect,
515 | rectfill,
516 | circ,
517 | circfill,
518 | spr,
519 | sget,
520 | sset,
521 | print,
522 | pal,
523 | palt,
524 | map,
525 | mget,
526 | mset,
527 | stat,
528 | };
529 | }
530 |
--------------------------------------------------------------------------------
/src/vendor/glfx.js:
--------------------------------------------------------------------------------
1 | /*
2 | * glfx.js
3 | * http://evanw.github.com/glfx.js/
4 | *
5 | * Copyright 2011 Evan Wallace
6 | * Released under the MIT license
7 | */
8 | window.fx=function(){function q(a,d,c){return Math.max(a,Math.min(d,c))}function w(b){return{_:b,loadContentsOf:function(b){a=this._.gl;this._.loadContentsOf(b)},destroy:function(){a=this._.gl;this._.destroy()}}}function A(a){return w(r.fromElement(a))}function B(b,d){var c=a.UNSIGNED_BYTE;if(a.getExtension("OES_texture_float")&&a.getExtension("OES_texture_float_linear")){var e=new r(100,100,a.RGBA,a.FLOAT);try{e.drawTo(function(){c=a.FLOAT})}catch(g){}e.destroy()}this._.texture&&this._.texture.destroy();
9 | this._.spareTexture&&this._.spareTexture.destroy();this.width=b;this.height=d;this._.texture=new r(b,d,a.RGBA,c);this._.spareTexture=new r(b,d,a.RGBA,c);this._.extraTexture=this._.extraTexture||new r(0,0,a.RGBA,c);this._.flippedShader=this._.flippedShader||new h(null,"uniform sampler2D texture;varying vec2 texCoord;void main(){gl_FragColor=texture2D(texture,vec2(texCoord.x,1.0-texCoord.y));}");this._.isInitialized=!0}function C(a,d,c){this._.isInitialized&&
10 | a._.width==this.width&&a._.height==this.height||B.call(this,d?d:a._.width,c?c:a._.height);a._.use();this._.texture.drawTo(function(){h.getDefaultShader().drawRect()});return this}function D(){this._.texture.use();this._.flippedShader.drawRect();return this}function f(a,d,c,e){(c||this._.texture).use();this._.spareTexture.drawTo(function(){a.uniforms(d).drawRect()});this._.spareTexture.swapWith(e||this._.texture)}function E(a){a.parentNode.insertBefore(this,a);a.parentNode.removeChild(a);return this}
11 | function F(){var b=new r(this._.texture.width,this._.texture.height,a.RGBA,a.UNSIGNED_BYTE);this._.texture.use();b.drawTo(function(){h.getDefaultShader().drawRect()});return w(b)}function G(){var b=this._.texture.width,d=this._.texture.height,c=new Uint8Array(4*b*d);this._.texture.drawTo(function(){a.readPixels(0,0,b,d,a.RGBA,a.UNSIGNED_BYTE,c)});return c}function k(b){return function(){a=this._.gl;return b.apply(this,arguments)}}function x(a,d,c,e,g,l,n,p){var m=c-g,h=e-l,f=n-g,k=p-l;g=a-c+g-n;l=
12 | d-e+l-p;var q=m*k-f*h,f=(g*k-f*l)/q,m=(m*l-g*h)/q;return[c-a+f*c,e-d+f*e,f,n-a+m*n,p-d+m*p,m,a,d,1]}function y(a){var d=a[0],c=a[1],e=a[2],g=a[3],l=a[4],n=a[5],p=a[6],m=a[7];a=a[8];var f=d*l*a-d*n*m-c*g*a+c*n*p+e*g*m-e*l*p;return[(l*a-n*m)/f,(e*m-c*a)/f,(c*n-e*l)/f,(n*p-g*a)/f,(d*a-e*p)/f,(e*g-d*n)/f,(g*m-l*p)/f,(c*p-d*m)/f,(d*l-c*g)/f]}function z(a){var d=a.length;this.xa=[];this.ya=[];this.u=[];this.y2=[];a.sort(function(a,b){return a[0]-b[0]});for(var c=0;c0.0){color.rgb=(color.rgb-0.5)/(1.0-contrast)+0.5;}else{color.rgb=(color.rgb-0.5)*(1.0+contrast)+0.5;}gl_FragColor=color;}");
15 | f.call(this,a.brightnessContrast,{brightness:q(-1,b,1),contrast:q(-1,d,1)});return this}function t(a){a=new z(a);for(var d=[],c=0;256>c;c++)d.push(q(0,Math.floor(256*a.interpolate(c/255)),255));return d}function I(b,d,c){b=t(b);1==arguments.length?d=c=b:(d=t(d),c=t(c));for(var e=[],g=0;256>g;g++)e.splice(e.length,0,b[g],d[g],c[g],255);this._.extraTexture.initFromBytes(256,1,e);this._.extraTexture.use(1);a.curves=a.curves||new h(null,"uniform sampler2D texture;uniform sampler2D map;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);color.r=texture2D(map,vec2(color.r)).r;color.g=texture2D(map,vec2(color.g)).g;color.b=texture2D(map,vec2(color.b)).b;gl_FragColor=color;}");
16 | a.curves.textures({map:1});f.call(this,a.curves,{});return this}function J(b){a.denoise=a.denoise||new h(null,"uniform sampler2D texture;uniform float exponent;uniform float strength;uniform vec2 texSize;varying vec2 texCoord;void main(){vec4 center=texture2D(texture,texCoord);vec4 color=vec4(0.0);float total=0.0;for(float x=-4.0;x<=4.0;x+=1.0){for(float y=-4.0;y<=4.0;y+=1.0){vec4 sample=texture2D(texture,texCoord+vec2(x,y)/texSize);float weight=1.0-abs(dot(sample.rgb-center.rgb,vec3(0.25)));weight=pow(weight,exponent);color+=sample*weight;total+=weight;}}gl_FragColor=color/total;}");
17 | for(var d=0;2>d;d++)f.call(this,a.denoise,{exponent:Math.max(0,b),texSize:[this.width,this.height]});return this}function K(b,d){a.hueSaturation=a.hueSaturation||new h(null,"uniform sampler2D texture;uniform float hue;uniform float saturation;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float angle=hue*3.14159265;float s=sin(angle),c=cos(angle);vec3 weights=(vec3(2.0*c,-sqrt(3.0)*s-c,sqrt(3.0)*s-c)+1.0)/3.0;float len=length(color.rgb);color.rgb=vec3(dot(color.rgb,weights.xyz),dot(color.rgb,weights.zxy),dot(color.rgb,weights.yzx));float average=(color.r+color.g+color.b)/3.0;if(saturation>0.0){color.rgb+=(average-color.rgb)*(1.0-1.0/(1.001-saturation));}else{color.rgb+=(average-color.rgb)*(-saturation);}gl_FragColor=color;}");
18 | f.call(this,a.hueSaturation,{hue:q(-1,b,1),saturation:q(-1,d,1)});return this}function L(b){a.noise=a.noise||new h(null,"uniform sampler2D texture;uniform float amount;varying vec2 texCoord;float rand(vec2 co){return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);}void main(){vec4 color=texture2D(texture,texCoord);float diff=(rand(texCoord)-0.5)*amount;color.r+=diff;color.g+=diff;color.b+=diff;gl_FragColor=color;}");
19 | f.call(this,a.noise,{amount:q(0,b,1)});return this}function M(b){a.sepia=a.sepia||new h(null,"uniform sampler2D texture;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float r=color.r;float g=color.g;float b=color.b;color.r=min(1.0,(r*(1.0-(0.607*amount)))+(g*(0.769*amount))+(b*(0.189*amount)));color.g=min(1.0,(r*0.349*amount)+(g*(1.0-(0.314*amount)))+(b*0.168*amount));color.b=min(1.0,(r*0.272*amount)+(g*0.534*amount)+(b*(1.0-(0.869*amount))));gl_FragColor=color;}");
20 | f.call(this,a.sepia,{amount:q(0,b,1)});return this}function N(b,d){a.unsharpMask=a.unsharpMask||new h(null,"uniform sampler2D blurredTexture;uniform sampler2D originalTexture;uniform float strength;uniform float threshold;varying vec2 texCoord;void main(){vec4 blurred=texture2D(blurredTexture,texCoord);vec4 original=texture2D(originalTexture,texCoord);gl_FragColor=mix(blurred,original,1.0+strength);}");
21 | this._.extraTexture.ensureFormat(this._.texture);this._.texture.use();this._.extraTexture.drawTo(function(){h.getDefaultShader().drawRect()});this._.extraTexture.use(1);this.triangleBlur(b);a.unsharpMask.textures({originalTexture:1});f.call(this,a.unsharpMask,{strength:d});this._.extraTexture.unuse(1);return this}function O(b){a.vibrance=a.vibrance||new h(null,"uniform sampler2D texture;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float average=(color.r+color.g+color.b)/3.0;float mx=max(color.r,max(color.g,color.b));float amt=(mx-average)*(-amount*3.0);color.rgb=mix(color.rgb,vec3(mx),amt);gl_FragColor=color;}");
22 | f.call(this,a.vibrance,{amount:q(-1,b,1)});return this}function P(b,d){a.vignette=a.vignette||new h(null,"uniform sampler2D texture;uniform float size;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float dist=distance(texCoord,vec2(0.5,0.5));color.rgb*=smoothstep(0.8,size*0.799,dist*(amount+size));gl_FragColor=color;}");
23 | f.call(this,a.vignette,{size:q(0,b,1),amount:q(0,d,1)});return this}function Q(b,d,c){a.lensBlurPrePass=a.lensBlurPrePass||new h(null,"uniform sampler2D texture;uniform float power;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);color=pow(color,vec4(power));gl_FragColor=vec4(color);}");var e="uniform sampler2D texture0;uniform sampler2D texture1;uniform vec2 delta0;uniform vec2 delta1;uniform float power;varying vec2 texCoord;"+
24 | s+"vec4 sample(vec2 delta){float offset=random(vec3(delta,151.7182),0.0);vec4 color=vec4(0.0);float total=0.0;for(float t=0.0;t<=30.0;t++){float percent=(t+offset)/30.0;color+=texture2D(texture0,texCoord+delta*percent);total+=1.0;}return color/total;}";
25 | a.lensBlur0=a.lensBlur0||new h(null,e+"void main(){gl_FragColor=sample(delta0);}");a.lensBlur1=a.lensBlur1||new h(null,e+"void main(){gl_FragColor=(sample(delta0)+sample(delta1))*0.5;}");a.lensBlur2=a.lensBlur2||(new h(null,e+"void main(){vec4 color=(sample(delta0)+2.0*texture2D(texture1,texCoord))/3.0;gl_FragColor=pow(color,vec4(power));}")).textures({texture1:1});for(var e=
26 | [],g=0;3>g;g++){var l=c+2*g*Math.PI/3;e.push([b*Math.sin(l)/this.width,b*Math.cos(l)/this.height])}b=Math.pow(10,q(-1,d,1));f.call(this,a.lensBlurPrePass,{power:b});this._.extraTexture.ensureFormat(this._.texture);f.call(this,a.lensBlur0,{delta0:e[0]},this._.texture,this._.extraTexture);f.call(this,a.lensBlur1,{delta0:e[1],delta1:e[2]},this._.extraTexture,this._.extraTexture);f.call(this,a.lensBlur0,{delta0:e[1]});this._.extraTexture.use(1);f.call(this,a.lensBlur2,{power:1/b,delta0:e[2]});return this}
27 | function R(b,d,c,e,g,l){a.tiltShift=a.tiltShift||new h(null,"uniform sampler2D texture;uniform float blurRadius;uniform float gradientRadius;uniform vec2 start;uniform vec2 end;uniform vec2 delta;uniform vec2 texSize;varying vec2 texCoord;"+s+"void main(){vec4 color=vec4(0.0);float total=0.0;float offset=random(vec3(12.9898,78.233,151.7182),0.0);vec2 normal=normalize(vec2(start.y-end.y,end.x-start.x));float radius=smoothstep(0.0,1.0,abs(dot(texCoord*texSize-start,normal))/gradientRadius)*blurRadius;for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec4 sample=texture2D(texture,texCoord+delta/texSize*percent*radius);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}");
28 | var n=c-b,p=e-d,m=Math.sqrt(n*n+p*p);f.call(this,a.tiltShift,{blurRadius:g,gradientRadius:l,start:[b,d],end:[c,e],delta:[n/m,p/m],texSize:[this.width,this.height]});f.call(this,a.tiltShift,{blurRadius:g,gradientRadius:l,start:[b,d],end:[c,e],delta:[-p/m,n/m],texSize:[this.width,this.height]});return this}function S(b){a.triangleBlur=a.triangleBlur||new h(null,"uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;"+s+"void main(){vec4 color=vec4(0.0);float total=0.0;float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec4 sample=texture2D(texture,texCoord+delta*percent);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}");
29 | f.call(this,a.triangleBlur,{delta:[b/this.width,0]});f.call(this,a.triangleBlur,{delta:[0,b/this.height]});return this}function T(b,d,c){a.zoomBlur=a.zoomBlur||new h(null,"uniform sampler2D texture;uniform vec2 center;uniform float strength;uniform vec2 texSize;varying vec2 texCoord;"+s+"void main(){vec4 color=vec4(0.0);float total=0.0;vec2 toCenter=center-texCoord*texSize;float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=0.0;t<=40.0;t++){float percent=(t+offset)/40.0;float weight=4.0*(percent-percent*percent);vec4 sample=texture2D(texture,texCoord+toCenter*percent*strength/texSize);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}");
30 | f.call(this,a.zoomBlur,{center:[b,d],strength:c,texSize:[this.width,this.height]});return this}function U(b,d,c,e){a.colorHalftone=a.colorHalftone||new h(null,"uniform sampler2D texture;uniform vec2 center;uniform float angle;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;float pattern(float angle){float s=sin(angle),c=cos(angle);vec2 tex=texCoord*texSize-center;vec2 point=vec2(c*tex.x-s*tex.y,s*tex.x+c*tex.y)*scale;return(sin(point.x)*sin(point.y))*4.0;}void main(){vec4 color=texture2D(texture,texCoord);vec3 cmy=1.0-color.rgb;float k=min(cmy.x,min(cmy.y,cmy.z));cmy=(cmy-k)/(1.0-k);cmy=clamp(cmy*10.0-3.0+vec3(pattern(angle+0.26179),pattern(angle+1.30899),pattern(angle)),0.0,1.0);k=clamp(k*10.0-5.0+pattern(angle+0.78539),0.0,1.0);gl_FragColor=vec4(1.0-cmy-k,color.a);}");
31 | f.call(this,a.colorHalftone,{center:[b,d],angle:c,scale:Math.PI/e,texSize:[this.width,this.height]});return this}function V(b,d,c,e){a.dotScreen=a.dotScreen||new h(null,"uniform sampler2D texture;uniform vec2 center;uniform float angle;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;float pattern(){float s=sin(angle),c=cos(angle);vec2 tex=texCoord*texSize-center;vec2 point=vec2(c*tex.x-s*tex.y,s*tex.x+c*tex.y)*scale;return(sin(point.x)*sin(point.y))*4.0;}void main(){vec4 color=texture2D(texture,texCoord);float average=(color.r+color.g+color.b)/3.0;gl_FragColor=vec4(vec3(average*10.0-5.0+pattern()),color.a);}");
32 | f.call(this,a.dotScreen,{center:[b,d],angle:c,scale:Math.PI/e,texSize:[this.width,this.height]});return this}function W(b){a.edgeWork1=a.edgeWork1||new h(null,"uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;"+s+"void main(){vec2 color=vec2(0.0);vec2 total=vec2(0.0);float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec3 sample=texture2D(texture,texCoord+delta*percent).rgb;float average=(sample.r+sample.g+sample.b)/3.0;color.x+=average*weight;total.x+=weight;if(abs(t)<15.0){weight=weight*2.0-1.0;color.y+=average*weight;total.y+=weight;}}gl_FragColor=vec4(color/total,0.0,1.0);}");
33 | a.edgeWork2=a.edgeWork2||new h(null,"uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;"+s+"void main(){vec2 color=vec2(0.0);vec2 total=vec2(0.0);float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec2 sample=texture2D(texture,texCoord+delta*percent).xy;color.x+=sample.x*weight;total.x+=weight;if(abs(t)<15.0){weight=weight*2.0-1.0;color.y+=sample.y*weight;total.y+=weight;}}float c=clamp(10000.0*(color.y/total.y-color.x/total.x)+0.5,0.0,1.0);gl_FragColor=vec4(c,c,c,1.0);}");
34 | f.call(this,a.edgeWork1,{delta:[b/this.width,0]});f.call(this,a.edgeWork2,{delta:[0,b/this.height]});return this}function X(b,d,c){a.hexagonalPixelate=a.hexagonalPixelate||new h(null,"uniform sampler2D texture;uniform vec2 center;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;void main(){vec2 tex=(texCoord*texSize-center)/scale;tex.y/=0.866025404;tex.x-=tex.y*0.5;vec2 a;if(tex.x+tex.y-floor(tex.x)-floor(tex.y)<1.0)a=vec2(floor(tex.x),floor(tex.y));else a=vec2(ceil(tex.x),ceil(tex.y));vec2 b=vec2(ceil(tex.x),floor(tex.y));vec2 c=vec2(floor(tex.x),ceil(tex.y));vec3 TEX=vec3(tex.x,tex.y,1.0-tex.x-tex.y);vec3 A=vec3(a.x,a.y,1.0-a.x-a.y);vec3 B=vec3(b.x,b.y,1.0-b.x-b.y);vec3 C=vec3(c.x,c.y,1.0-c.x-c.y);float alen=length(TEX-A);float blen=length(TEX-B);float clen=length(TEX-C);vec2 choice;if(alen0.0){coord*=mix(1.0,smoothstep(0.0,radius/distance,percent),strength*0.75);}else{coord*=mix(1.0,pow(percent,1.0+strength*0.75)*radius/distance,1.0-percent);}}coord+=center;");
37 | f.call(this,a.bulgePinch,{radius:c,strength:q(-1,e,1),center:[b,d],texSize:[this.width,this.height]});return this}function $(b,d,c){a.matrixWarp=a.matrixWarp||u("uniform mat3 matrix;uniform bool useTextureSpace;","if(useTextureSpace)coord=coord/texSize*2.0-1.0;vec3 warp=matrix*vec3(coord,1.0);coord=warp.xy/warp.z;if(useTextureSpace)coord=(coord*0.5+0.5)*texSize;");b=Array.prototype.concat.apply([],b);if(4==b.length)b=
38 | [b[0],b[1],0,b[2],b[3],0,0,0,1];else if(9!=b.length)throw"can only warp with 2x2 or 3x3 matrix";f.call(this,a.matrixWarp,{matrix:d?y(b):b,texSize:[this.width,this.height],useTextureSpace:c|0});return this}function aa(a,d){var c=x.apply(null,d),e=x.apply(null,a),c=y(c);return this.matrixWarp([c[0]*e[0]+c[1]*e[3]+c[2]*e[6],c[0]*e[1]+c[1]*e[4]+c[2]*e[7],c[0]*e[2]+c[1]*e[5]+c[2]*e[8],c[3]*e[0]+c[4]*e[3]+c[5]*e[6],c[3]*e[1]+c[4]*e[4]+c[5]*e[7],c[3]*e[2]+c[4]*e[5]+c[5]*e[8],c[6]*e[0]+c[7]*e[3]+c[8]*e[6],
39 | c[6]*e[1]+c[7]*e[4]+c[8]*e[7],c[6]*e[2]+c[7]*e[5]+c[8]*e[8]])}function ba(b,d,c,e){a.swirl=a.swirl||u("uniform float radius;uniform float angle;uniform vec2 center;","coord-=center;float distance=length(coord);if(distance>1;this.xa[e]>a?c=e:d=e}var e=this.xa[c]-
53 | this.xa[d],g=(this.xa[c]-a)/e;a=(a-this.xa[d])/e;return g*this.ya[d]+a*this.ya[c]+((g*g*g-g)*this.y2[d]+(a*a*a-a)*this.y2[c])*e*e/6};var r=function(){function b(b,c,d,f){this.gl=a;this.id=a.createTexture();this.width=b;this.height=c;this.format=d;this.type=f;a.bindTexture(a.TEXTURE_2D,this.id);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,
54 | a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE);b&&c&&a.texImage2D(a.TEXTURE_2D,0,this.format,b,c,0,this.format,this.type,null)}function d(a){null==c&&(c=document.createElement("canvas"));c.width=a.width;c.height=a.height;a=c.getContext("2d");a.clearRect(0,0,c.width,c.height);return a}b.fromElement=function(c){var d=new b(0,0,a.RGBA,a.UNSIGNED_BYTE);d.loadContentsOf(c);return d};b.prototype.loadContentsOf=function(b){this.width=b.width||b.videoWidth;this.height=b.height||b.videoHeight;a.bindTexture(a.TEXTURE_2D,
55 | this.id);a.texImage2D(a.TEXTURE_2D,0,this.format,this.format,this.type,b)};b.prototype.initFromBytes=function(b,c,d){this.width=b;this.height=c;this.format=a.RGBA;this.type=a.UNSIGNED_BYTE;a.bindTexture(a.TEXTURE_2D,this.id);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,b,c,0,a.RGBA,this.type,new Uint8Array(d))};b.prototype.destroy=function(){a.deleteTexture(this.id);this.id=null};b.prototype.use=function(b){a.activeTexture(a.TEXTURE0+(b||0));a.bindTexture(a.TEXTURE_2D,this.id)};b.prototype.unuse=function(b){a.activeTexture(a.TEXTURE0+
56 | (b||0));a.bindTexture(a.TEXTURE_2D,null)};b.prototype.ensureFormat=function(b,c,d,f){if(1==arguments.length){var h=arguments[0];b=h.width;c=h.height;d=h.format;f=h.type}if(b!=this.width||c!=this.height||d!=this.format||f!=this.type)this.width=b,this.height=c,this.format=d,this.type=f,a.bindTexture(a.TEXTURE_2D,this.id),a.texImage2D(a.TEXTURE_2D,0,this.format,b,c,0,this.format,this.type,null)};b.prototype.drawTo=function(b){a.framebuffer=a.framebuffer||a.createFramebuffer();a.bindFramebuffer(a.FRAMEBUFFER,
57 | a.framebuffer);a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.id,0);if(a.checkFramebufferStatus(a.FRAMEBUFFER)!==a.FRAMEBUFFER_COMPLETE)throw Error("incomplete framebuffer");a.viewport(0,0,this.width,this.height);b();a.bindFramebuffer(a.FRAMEBUFFER,null)};var c=null;b.prototype.fillUsingCanvas=function(b){b(d(this));this.format=a.RGBA;this.type=a.UNSIGNED_BYTE;a.bindTexture(a.TEXTURE_2D,this.id);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c);return this};
58 | b.prototype.toImage=function(b){this.use();h.getDefaultShader().drawRect();var f=4*this.width*this.height,k=new Uint8Array(f),n=d(this),p=n.createImageData(this.width,this.height);a.readPixels(0,0,this.width,this.height,a.RGBA,a.UNSIGNED_BYTE,k);for(var m=0;m-1){return a==="IEND"?!!PngToy._findChunk(this.chunks,"IEND"):PngToy["_"+a](this)}else{return PngToy._findChunk(this.chunks,a)}},getGammaLUT:function(c,b,f){c=c||1;b=b||2.2;f=f||1;var a=new Uint8Array(256),e=0,d=1/(c*b*f);for(;e<256;e++){a[e]=Math.round(Math.pow(e/255,d)*255)}return a},guessDisplayGamma:function(){return navigator.userAgent.indexOf("Mac OS")>-1?1.8:2.2}};PngToy._blockSize=3000000;PngToy._delay=7;PngToy._getChunks=function(b,F,k,a){var x=this,C=8,v=b.byteLength,e=[],d,w,m,A,h,g,B,E,p,z,D,t=!0,y=["iTXT","tIME","tEXt","zTXt"],l=PngToy._findChunk;if(k&&!this.table){this.table=new Uint32Array(256);for(var q=0,u;q<256;q++){h=q>>>0;for(u=0;u<8;u++){h=(h&1)?3988292384^(h>>>1):h>>>1}this.table[q]=h}}while(C2147483647&&!a){return{error:"Invalid chunk size."}}A=C;C=A+w;h=o();d=new PngToy.Chunk(m,A,w,h);if(k){c(d);if(!d.crcOk&&!a){return{error:"Invalid CRC in chunk "+m}}}if(d.isReserved&&!a){return{error:"Invalid chunk name: "+m}}e.push(d)}if(!a){if(!f("IHDR",1,1)){return{error:"Invalid number of IHDR chunks."}}if(!f("tIME",0,1)){return{error:"Invalid number of tIME chunks."}}if(!f("zTXt",0,-1)){return{error:"Invalid number of zTXt chunks."}}if(!f("tEXt",0,-1)){return{error:"Invalid number of tEXt chunks."}}if(!f("iTXt",0,-1)){return{error:"Invalid number of iTXt chunks."}}if(!f("pHYs",0,1)){return{error:"Invalid number of pHYs chunks."}}if(!f("sPLT",0,-1)){return{error:"Invalid number of sPLT chunks."}}if(!f("iCCP",0,1)){return{error:"Invalid number of iCCP chunks."}}if(!f("sRGB",0,1)){return{error:"Invalid number of sRGB chunks."}}if(!f("sBIT",0,1)){return{error:"Invalid number of sBIT chunks."}}if(!f("gAMA",0,1)){return{error:"Invalid number of gAMA chunks."}}if(!f("cHRM",0,1)){return{error:"Invalid number of cHRM chunks."}}if(!f("PLTE",0,1)){return{error:"Invalid number of PLTE chunks."}}if(!f("tRNS",0,1)){return{error:"Invalid number of tRNS chunks."}}if(!f("hIST",0,1)){return{error:"Invalid number of hIST chunks."}}if(!f("bKGD",0,1)){return{error:"Invalid number of bKGD chunks."}}if(!f("IDAT",1,-1)){return{error:"Invalid number of IDAT chunks."}}if(!f("IEND",1,1)){return{error:"Invalid number of IEND chunks."}}if(e[0].name!=="IHDR"||e[e.length-1].name!=="IEND"){return{error:"Invalid PNG chunk order."}}g=F.getUint8(l(e,"IHDR").offset+9);B=l(e,"PLTE");p=l(e,"hIST");E=l(e,"tRNS");z=l(e,"oFFs");D=l(e,"sTER");if(l(e,"iCCP")&&l(e,"sRGB")){return{error:"Both iCCP and sRGB cannot be present."}}if(g===3&&!B){return{error:"Missing PLTE chunk."}}if((g===0||g===4)&&B){return{error:"PLTE chunk should not appear with this color type."}}if((g===4||g===6)&&E){return{error:"tRNS chunk should not appear with this color type."}}if(p&&!B){return{error:"hIST chunk can only appear if a PLTE chunk is present."}}if(B){if(!r("PLTE","IDAT")){return{error:"Invalid chunk order for PLTE."}}if(p&&!s("PLTE","hIST","IDAT")){return{error:"Invalid chunk order for hIST."}}if(E&&!s("PLTE","tRNS","IDAT")){return{error:"Invalid chunk order for tRNS."}}if(l(e,"bKGD")&&!s("PLTE","bKGD","IDAT")){return{error:"Invalid chunk order for bKGD."}}if(!r("cHRM","PLTE")){return{error:"Invalid chunk order for cHRM."}}if(!r("gAMA","PLTE")){return{error:"Invalid chunk order for gAMA."}}if(!r("iCCP","PLTE")){return{error:"Invalid chunk order for iCCP."}}if(!r("sRGB","PLTE")){return{error:"Invalid chunk order for sRGB."}}}if(z&&!r("oFFs","IDAT")){return{error:"Invalid chunk order for oFFs."}}if(D&&!r("sTER","IDAT")){return{error:"Invalid chunk order for sTER."}}for(q=e.length-2;q>0;q--){if(t&&e[q].name!=="IDAT"&&y.indexOf(e[q].name)<0){t=!1}else{if(!t&&e[q].name==="IDAT"){return{error:"Invalid chunk inside IDAT chunk sequence."}}}}}return{chunks:e};function f(i,H,G){var j=PngToy._findChunks(e,i);return G<0?j.length>=H:j.length>=H&&j.length<=G}function s(j,G,i){return r(j,G)&&r(G,i)}function r(j,H){var G=-1,I=-1,J,K=e.length;for(J=0;J>>0),K=H.length,J;for(J=0;J>>8)^x.table[(I^H[J])&255]}return(I^-1)>>>0}}function n(){var j=o(),i=String.fromCharCode;return i((j&4278190080)>>>24)+i((j&16711680)>>>16)+i((j&65280)>>>8)+i((j&255)>>>0)}function o(){var j=F.getUint32(C);C+=4;return j>>>0}};PngToy._getChunks.table=null;PngToy._findChunk=function(b,d){for(var c=0,a;a=b[c++];){if(a.name===d){return a}}return null};PngToy._findChunks=function(b,e){for(var c=0,d=[],a;a=b[c++];){if(a.name===e){d.push(a)}}return d};PngToy._getStr=function(j,e,d){var g="",c=e,a=-1,h,k=!1,b=String.fromCharCode,f=" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"%&'()*+,-./:;<=>?_";d+=c;for(;c-1){g+=h}else{k=!0}continue}break}return{offset:c,text:g,warning:k}};PngToy.Chunk=function(c,d,b,a){this.name=c;this.offset=d;this.length=b;this.crc=a;this.crcOk=!0;this.isCritical=!(c.charCodeAt(0)&32);this.isPrivate=!!(c.charCodeAt(1)&32);this.isReserved=!!(c.charCodeAt(2)&32);this.isCopySafe=!!(c.charCodeAt(3)&32)};PngToy._IHDR=function(d){var g=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"IHDR"),e,f;if(!b){return{error:"Critical - IHDR chunk is missing."}}e=b.offset;f={width:g.getUint32(e),height:g.getUint32(e+4),depth:g.getUint8(e+8),type:g.getUint8(e+9),compression:g.getUint8(e+10),filter:g.getUint8(e+11),interlaced:g.getUint8(e+12)};if(!a){if([0,2,3,4,6].indexOf(f.type)<0){return{error:"Invalid color type."}}switch(f.type){case 0:if([1,2,4,8,16].indexOf(f.depth)<0){return{error:"Invalid color depth."}}break;case 3:if([1,2,4,8].indexOf(f.depth)<0){return{error:"Invalid color depth."}}break;default:if([8,16].indexOf(f.depth)<0){return{error:"Invalid color depth."}}}if(!f.width||!f.height){return{error:"Invalid dimension."}}if(f.compression){return{error:"Invalid compression type."}}if(f.filter){return{error:"Invalid filter type."}}if(f.interlaced<0||f.interlaced>1){return{error:"Invalid interlace mode "+f.interlaced}}}return f};PngToy._IDAT=function(f){var b=f.buffer,d=f.chunks,a=f.allowInvalid,g=0,c,j=!1,h=new pako.Inflate(),e=!1;while(c=d[g++]){if(c.name==="IDAT"){e=!0;break}}while(c){j=c.name==="IEND";if(c.name==="IDAT"){h.push(new Uint8Array(b,c.offset,c.length),j)}c=d[g++]}if(!j&&!a){return{error:"Critical - missing IEND chunk."}}return e?(h.err?{error:h.msg}:{buffer:h.result}):(a?{buffer:null}:{error:"Critical - no IDAT chunk(s)."})};PngToy._PLTE=function(e){var b=e.buffer,d=e.chunks,a=e.allowInvalid,c=PngToy._findChunk(d,"PLTE"),f;if(!c){return null}f=new Uint8Array(b,c.offset,c.length);if(!a){if(f.length%3){return{error:"Invalid palette size."}}if(f.length<3||f.length>3*256){return{error:"Invalid number of palette entries."}}}return{palette:f,length:f.length/3}};PngToy._sPLT=function(d){var f=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunks(c,"sPLT"),e=[];if(!b.length){return null}b.forEach(function(h){var p={depth:null,name:null,palette:[],entries:0},m,o,l,q,g,n=[],k,j;o=h.offset;m=PngToy._getStr(f,o,80);p.name=m.text;o=m.offset;p.depth=f.getUint8(o++);q=p.depth===8?6:10;g=p.depth===8?1:2;l=h.length-(o-h.offset);j=q===6?f.getUint8.bind(f):f.getUint16.bind(f);for(k=0;k>1};break;case 2:h={alphas:new Uint16Array(b.slice(c.offset,c.offset+c.length)),length:c.length/6};break;case 3:h={alphas:new Uint8Array(b,c.offset,c.length),length:c.length};break;default:return a?{alphas:null,length:0}:{error:"tRNS chunk is not valid for this color type."}}if(!a&&g&&h.length>g.length){return{error:"tRNS chunk contains more entries than palette entries."}}return h};PngToy._hIST=function(e){var i=e.view,c=e.chunks,a=e.allowInvalid,b=PngToy._findChunk(c,"hIST"),g=PngToy._PLTE(e),d=[],h,f;if(!b){return null}if(!a&&b.length%2){return{error:"Invalid length of hIST chunk."}}h=b.offset;f=h+b.length;for(;h31&&b<127)&&!(b>160&&b<256)){return{error:"ICC profile contains illegal chars in name."}}}}k.name=g;if(l.getUint8(j++)&&!a){return{error:"Invalid compression type."}}try{k.icc=pako.inflate(new Uint8Array(l.buffer,j,c.length-(j-c.offset)))}catch(e){if(!a){return{error:e}}}return k};PngToy._gAMA=function(e){var f=e.view,c=e.chunks,a=e.allowInvalid,b=PngToy._findChunk(c,"gAMA"),d;if(!b){return null}d=f.getUint32(b.offset)/100000;if(!a){}return{gamma:d}};PngToy._cHRM=function(d){var g=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"cHRM"),f,e;if(!b){return null}e=b.offset;f={whiteX:g.getUint32(e)/100000,whiteY:g.getUint32(e+4)/100000,redX:g.getUint32(e+8)/100000,redY:g.getUint32(e+12)/100000,greenX:g.getUint32(e+16)/100000,greenY:g.getUint32(e+20)/100000,blueX:g.getUint32(e+24)/100000,blueY:g.getUint32(e+28)/100000};if(!a){}return f};PngToy._sRGB=function(d){var g=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"sRGB"),e,f=["Perceptual","Relative colorimetric","Saturation","Absolute colorimetric"];if(!b){return null}e=g.getUint8(b.offset);if(!a){if(e<0||e>3){return{error:"Invalid range for sRGB render intent."}}}return{intent:e,desc:f[e]||null}};PngToy._pHYs=function(d){var g=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"pHYs"),e,f={};if(!b){return null}e=b.offset;f.ppuX=g.getUint32(e);f.ppuY=g.getUint32(e+4);f.unit=g.getUint8(e+8);if(f.unit===1){f.desc="Meters"}else{f.desc="ratio"}if(!a){if(f.ppuX>2147483647||f.ppuY>2147483647){return{error:"Invalid unit lengths."}}if(f.unit<0||f.unit>1){return{error:"Invalid unit for pHYs chunk."}}}else{f.ppuX&=2147483647;f.ppuY&=2147483647;f.unit&=1}return f};PngToy._bKGD=function(c){var e=c.view,b=c.chunks,a=PngToy._findChunk(b,"bKGD"),d=PngToy._IHDR(c);if(!a){return null}switch(d.type){case 0:case 4:return{background:[e.getUint16(a.offset)]};case 2:case 6:return{background:new Uint16Array(e.buffer,a.offset,6)};default:return{index:e.getUint8(a.offset)}}};PngToy._tIME=function(e){var h=e.view,c=e.chunks,a=e.allowInvalid,b=PngToy._findChunk(c,"tIME"),f,g;if(!b){return null}f=b.offset;g={year:h.getUint16(f),month:h.getUint8(f+2),day:h.getUint8(f+3),hour:h.getUint8(f+4),minute:h.getUint8(f+5),second:h.getUint8(f+6),date:null};if(!a){if(g.year<0||g.year>65535||g.month<1||g.month>12||g.day<1||g.day>31||g.hour<0||g.hour>23||g.minute<0||g.minute>59||g.second<0||g.second>60){return{error:"Invalid timestamp."}}}try{g.date=new Date(g.year,g.month-1,g.day,g.hour,g.minute,Math.min(59,g.second))}catch(d){if(!a){return{error:d}}}return g};PngToy._oFFs=function(d){var g=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"oFFs"),e,f={};if(!b){return null}e=b.offset;f.x=g.getInt32(e);f.y=g.getInt32(e+4);f.unit=g.getUint8(e+8);f.desc=["Pixels","Micrometers"][f.unit]||"Invalid";if(!a){if(f.unit<0||f.unit>1){return{error:"Invalid unit for oFFs chunk."}}}return f};PngToy._sCAL=function(d){var h=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"sCAL"),f,e,g={};if(!b.length){return null}f=b.offset;g.unit=h.getUint8(f++);g.desc=["meters","radians"][g.unit]||null;e=PngToy._getStr(h,f,100000);g.unitsX=e.text;f=e.offset;e=PngToy._getStr(h,f,b.length-(f-b.offset));g.unitsY=e.text;if(!a){if(g.unit<1||g.unit>2){return{error:"Invalid unit"}}}return g};PngToy._pCAL=function(d){var l=d.view,c=d.chunks,a=d.allowInvalid,b=PngToy._findChunk(c,"pCAL"),m=!1,j,g,k={},h=[],e=0,f;if(!b.length){return null}j=b.offset;g=PngToy._getStr(l,j,80);k.calName=g.text;j=g.offset;if(g.warn){m=!0}k.x0=l.getInt32(j);k.x1=l.getInt32(j+4);k.eqType=l.getUint8(j+8);k.eqDesc=["Linear mapping","Base-e exponential mapping","Arbitrary-base exponential mapping","Hyperbolic mapping"][k.eqType]||null;k.paramCount=l.getUint8(j+9);j+=10;g=PngToy._getStr(l,j,10000);k.unitName=g.text;j=g.offset;if(g.warn){m=!0}f=k.paramCount-1;for(;e3){return{error:"Invalid equation type."}}if(m){return{error:"One or more text field contains illegal chars."}}}return k};PngToy.prototype.decode=function(){var a=this;return new Promise(function(Q,P){var C=a.getChunk("IHDR"),Z=C.width,B=C.height,Y=C.type,m=C.depth,g=m/8,D=g===2,M=[1,0,3,1,2,0,4][Y],G=D?65535:255,l=M*g,F=Z*l,E=F+Math.ceil(l),S=a.getChunk("IDAT").buffer,o=new Uint8Array(Math.max(1,Math.ceil(Z*l)*B)),z=[r,s,t,u,v],R=0,n=0,i=0,N=0,ab=0,O,f=S.byteLength,T=S.length,H=[0,4,0,2,0,1,0],I=[0,0,4,0,2,0,1],U=[8,8,4,4,2,2,1],V=[8,8,8,4,4,2,2],d=[8,4,4,2,2,1,1],c=[8,8,4,4,2,2,1],L,W,X,J,e,b,aa;a.debug={pixelWidth:M,byteWidth:g,delta:l,lineLen:F,lineDlt:E,filters:[],preFilt:-1,postFilt:-1,srcPos:-1,srcLen:S.length,pass:0,x:-1,stepX:0,stepY:0,stepsX:0,stepsY:0};if(C.interlaced){if(typeof console!=="undefined"){console.log("WARN: In current alpha interlaced PNGs will not decode properly unless all line-filters are filter 0.")}L=ab=J=0;W=X=e=b=8;setTimeout(k,PngToy._delay)}else{setTimeout(j,PngToy._delay)}function j(){try{var x,ad,y,ac=a.debug.filters,h=PngToy._blockSize;l=Math.ceil(l);while(ab0){y=S[R++];x=z[y];if(ac.indexOf(y)<0){ac.push(y)}ad=Math.min(f,R+F);i=n;while(R=T){ab=B;continue}ad=S[R++];if(ae.indexOf(ad)<0){ae.push(ad)}if(ad<0||ad>4){a.debug.preFilt=S[R-2];a.debug.postFilt=S[R];a.debug.srcPos=R;a.debug.pass=L;a.debug.x=aa;a.debug.stepX=W;a.debug.stepY=X;a.debug.stepsX=Z/W;a.debug.stepsY=B/X}ac=z[ad];lineEnd=Math.min(f,Math.ceil(R+F));i=ab*F;N=Math.max(0,i-F);aa=J;while(aa>>0}function q(h){return h>>0}function r(h){return h}function s(w,h){return w+p(h)}function t(x,h,w){return x+q(w)}function u(x,h,w){return x+((p(h)+q(w))>>>1)}function v(y,h,w,x){return y+K(p(h),q(w),q(x))}function K(h,w,x){var y=h+w-x,ac=Math.abs(y-h),ad=Math.abs(y-w),ae=Math.abs(y-x);if(ac<=ad&&ac<=ae){return h}if(ad<=ae){return w}return x}})};PngToy.prototype.convertToRGBA=function(a,c){var b=this;c=c||{};return new Promise(function(O,N){if(a.type===6&&a.depth===8&&!c.useGamma){var R=c.ignoreAspectRatio?null:b.getChunk("pHYs"),L=R?R.ppuY/(R.ppuX||1):1,M=R?R.ppuX/(R.ppuY||1):1;if(c.ignoreAspectRatio||(!c.ignoreAspectRatio&&L===1&&M===1)){O({bitmap:a.bitmap,width:a.width,height:a.height,ratioX:L,ratioY:M})}return}var J,S,H,k,G,d,U=a.width,D=a.height,T=a.type,g=a.depth,e=g/8,I=[1,0,3,1,2,0,4][T],l=p(T,g),Q=a.bitmap,j=new Uint8Array(U*D*4),P=0,i=0,E=Q.byteLength,K,F;if(a.type===3){J=b.getChunk("PLTE");G=J?J.palette:[]}S=b.getChunk("tRNS");d=S&&S.alphas?S.alphas:[];H=b.getChunk("pHYs");k=b.getChunk("gAMA");k=k?k.gamma:1;(function f(){var h=PngToy._blockSize,V=U*e*I,w=P+V;if(c.useGamma){F=F?F:b.getGammaLUT(k,c.gamma||1);while(P0){if(P>=w){P=Math.ceil(P);w=P+V}K=l();j[i++]=F[K[0]];j[i++]=F[K[1]];j[i++]=F[K[2]];j[i++]=K[3];h--}}else{while(P0){if(P>=w){P=Math.ceil(P);w=P+V}K=l();j[i++]=K[0];j[i++]=K[1];j[i++]=K[2];j[i++]=K[3];h--}}if(P>V))?255:0,h=d.length?((d[0]>>>8)&(128>>V)===W?0:255):255;P+=e;return[W,W,W,h]}function t(){var w=Q[P|0],V=((P-(P|0))/e)<<1,W=(((w>>>V)&3)*85)&255,h=d.length?((((d[0]>>>8)&3)*85)&255===W?0:255):255;P+=e;return[W,W,W,h]}function u(){var w=Q[P|0],V=((P-(P|0))/e),W=V?(w&15)<<4:w&240,h=d.length?(((d[0]&3840)>>>4)===W?0:255):255;P+=e;return[W,W,W,h]}function m(){var h=Q[P|0],w=(P-(P|0))/e,V=(h&(128>>>w))?1:0,W=V*3;P+=e;return[G[W],G[W+1],G[W+2],255]}function n(){var w=Q[P|0],V=((P-(P|0))/e)<<1,W=((w<>>6,X=W*3,h=W>>4,X=W*3,h=W>>8)?0:255;w&=255;return[w,w,w,h]}function s(){var w=Q[P++],h=d.length&&d[0]===w?0:255;w&=255;return[w,w,w,h]}function z(){var Z=Q[P++],Y=Q[P++],X=Q[P++],W,V,w,h=255;if(d.length){W=d[0]>>>8;V=d[1]>>>8;w=d[2]>>>8;if(W===Z&&V===Y&&w===X){h=0}}return[Z&255,Y&255,X&255,h]}function B(){return[Q[P++],Q[P++],Q[P++],Q[P++]]}function A(){var W=Q[P++],V=Q[P++],w=Q[P++],h=d.length&&d[0]===W&&d[1]===V&&d[2]===w?0:255;return[W&255,V&255,w&255,h]}function v(){var h=Q[P++];return[h,h,h,Q[P++]]}function x(){var h=Q[P++]&255;return[h,h,h,Q[P++]&255]}function y(){var w=Q[P++],h=w*3;return[G[h],G[h+1],G[h+2],w=1){o=g.width;k=(g.height*f.ratioY)|0}else{if(f.ratioY<1){o=(g.width*f.ratioX)|0;k=g.height}}m.width=o;m.height=k;n.drawImage(g,0,0,o,k);g=m}e(g)}catch(j){d(j)}},d)})};(function(a){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=a()}else{if(typeof define==="function"&&define.amd){define([],a)}else{var b;if(typeof window!=="undefined"){b=window}else{if(typeof global!=="undefined"){b=global}else{if(typeof self!=="undefined"){b=self}else{b=this}}}b.pako=a()}}})(function(){var a,d,c;return(function b(k,f,h){function j(p,q){if(!f[p]){if(!k[p]){var i=typeof require=="function"&&require;if(!q&&i){return i(p,!0)}if(e){return e(p,!0)}var m=new Error("Cannot find module '"+p+"'");throw m.code="MODULE_NOT_FOUND",m}var n=f[p]={exports:{}};k[p][0].call(n.exports,function(l){var o=k[p][1][l];return j(o?o:l)},n,n.exports,b,k,f,h)}return f[p].exports}var e=typeof require=="function"&&require;for(var g=0;g=252?6:j>=248?5:j>=240?4:j>=224?3:j>=192?2:1)}f[254]=f[254]=1;h.string2buf=function(u){var o,q,r,t,s,v=u.length,p=0;for(t=0;t>>6);o[s++]=128|(q&63)}else{if(q<65536){o[s++]=224|(q>>>12);o[s++]=128|(q>>>6&63);o[s++]=128|(q&63)}else{o[s++]=240|(q>>>18);o[s++]=128|(q>>>12&63);o[s++]=128|(q>>>6&63);o[s++]=128|(q&63)}}}}return o};function g(o,q){if(q<65537){if((o.subarray&&m)||(!o.subarray&&l)){return String.fromCharCode.apply(null,n.shrinkBuf(o,q))}}var r="";for(var p=0;p4){v[u++]=65533;r+=q-1;continue}p&=q===2?31:q===3?15:7;while(q>1&&r1){v[u++]=65533;continue}if(p<65536){v[u++]=p}else{p-=65536;v[u++]=55296|((p>>10)&1023);v[u++]=56320|(p&1023)}}return g(v,u)};h.utf8border=function(o,p){var q;p=p||o.length;if(p>o.length){p=o.length}q=p-1;while(q>=0&&(o[q]&192)===128){q--}if(q<0){return p}if(q===0){return p}return(q+f[o[q]]>p)?q:p}},{"./common":1}],3:[function(h,g,f){function e(i,j,k,m){var o=(i&65535)|0,p=((i>>>16)&65535)|0,l=0;while(k!==0){l=k>2000?2000:k;k-=l;do{o=(o+j[m++])|0;p=(p+o)|0}while(--l);o%=65521;p%=65521}return(o|(p<<16))|0}g.exports=e},{}],4:[function(g,f,e){f.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],5:[function(i,h,g){var f=PngToy._getChunks.table;function e(k,j,n,o){var p=f,l=o+n;k^=-1;for(var m=o;m>>8)^p[(k^j[m])&255]}return(k^(-1))}h.exports=e},{}],6:[function(h,g,e){function f(){this.text=0;this.time=0;this.xflags=0;this.os=0;this.extra=null;this.extra_len=0;this.name="";this.comment="";this.hcrc=0;this.done=!1}g.exports=f},{}],7:[function(i,h,f){var e=30;var j=12;h.exports=function g(H,F){var G;var k;var y;var l;var m;var s;var r;var K;var I;var J;var E;var w;var n;var z;var o;var B;var q;var v;var C;var A;var p;var t;var u;var x,D;G=H.state;k=H.next_in;x=H.input;y=k+(H.avail_in-5);l=H.next_out;D=H.output;m=l-(F-H.avail_out);s=l+(H.avail_out-257);r=G.dmax;K=G.wsize;I=G.whave;J=G.wnext;E=G.window;w=G.hold;n=G.bits;z=G.lencode;o=G.distcode;B=(1<>>24;w>>>=C;n-=C;C=(v>>>16)&255;if(C===0){D[l++]=v&65535}else{if(C&16){A=v&65535;C&=15;if(C){if(n>>=C;n-=C}if(n<15){w+=x[k++]<>>24;w>>>=C;n-=C;C=(v>>>16)&255;if(C&16){p=v&65535;C&=15;if(nr){H.msg="invalid distance too far back";G.mode=e;break top}w>>>=C;n-=C;C=l-m;if(p>C){C=p-C;if(C>I){if(G.sane){H.msg="invalid distance too far back";G.mode=e;break top}}t=0;u=E;if(J===0){t+=K-C;if(C2){D[l++]=u[t++];D[l++]=u[t++];D[l++]=u[t++];A-=3}if(A){D[l++]=u[t++];if(A>1){D[l++]=u[t++]}}}else{t=l-p;do{D[l++]=D[t++];D[l++]=D[t++];D[l++]=D[t++];A-=3}while(A>2);if(A){D[l++]=D[t++];if(A>1){D[l++]=D[t++]}}}}else{if((C&64)===0){v=o[(v&65535)+(w&((1<>3;k-=A;n-=A<<3;w&=(1<>>24)&255)+((aB>>>8)&65280)+((aB&65280)<<8)+((aB&255)<<24))}function P(){this.mode=0;this.last=!1;this.wrap=0;this.havedict=!1;this.flags=0;this.dmax=0;this.check=0;this.total=0;this.head=null;this.wbits=0;this.wsize=0;this.whave=0;this.wnext=0;this.window=null;this.hold=0;this.bits=0;this.length=0;this.offset=0;this.extra=0;this.lencode=null;this.distcode=null;this.lenbits=0;this.distbits=0;this.ncode=0;this.nlen=0;this.ndist=0;this.have=0;this.next=null;this.lens=new am.Buf16(320);this.work=new am.Buf16(288);this.lendyn=null;this.distdyn=null;this.sane=0;this.back=0;this.was=0}function N(aC){var aB;if(!aC||!aC.state){return ay}aB=aC.state;aC.total_in=aC.total_out=aB.total=0;aC.msg="";if(aB.wrap){aC.adler=aB.wrap&1}aB.mode=D;aB.last=0;aB.havedict=0;aB.dmax=32768;aB.head=null;aB.hold=0;aB.bits=0;aB.lencode=aB.lendyn=new am.Buf32(w);aB.distcode=aB.distdyn=new am.Buf32(v);aB.sane=1;aB.back=-1;return aw}function L(aC){var aB;if(!aC||!aC.state){return ay}aB=aC.state;aB.wsize=0;aB.whave=0;aB.wnext=0;return N(aC)}function M(aC,aD){var aE;var aB;if(!aC||!aC.state){return ay}aB=aC.state;if(aD<0){aE=0;aD=-aD}else{aE=(aD>>4)+1;if(aD<48){aD&=15}}if(aD&&(aD<8||aD>15)){return ay}if(aB.window!==null&&aB.wbits!==aD){aB.window=null}aB.wrap=aE;aB.wbits=aD;return L(aC)}function K(aD,aE){var aB;var aC;if(!aD){return ay}aC=new P();aD.state=aC;aC.window=null;aB=M(aD,aE);if(aB!==aw){aD.state=null}return aB}function J(aB){return K(aB,n)}var an=!0;var T,s;function A(aB){if(an){var aC;T=new am.Buf32(512);s=new am.Buf32(32);aC=0;while(aC<144){aB.lens[aC++]=8}while(aC<256){aB.lens[aC++]=9}while(aC<280){aB.lens[aC++]=7}while(aC<288){aB.lens[aC++]=8}G(W,aB.lens,0,288,T,0,aB.work,{bits:9});aC=0;while(aC<32){aB.lens[aC++]=5}G(t,aB.lens,0,32,s,0,aB.work,{bits:5});an=!1}aB.lencode=T;aB.lenbits=9;aB.distcode=s;aB.distbits=5}function al(aG,aE,aD,aB){var aC;var aF=aG.state;if(aF.window===null){aF.wsize=1<=aF.wsize){am.arraySet(aF.window,aE,aD-aF.wsize,aF.wsize,0);aF.wnext=0;aF.whave=aF.wsize}else{aC=aF.wsize-aF.wnext;if(aC>aB){aC=aB}am.arraySet(aF.window,aE,aD-aB,aC,aF.wnext);aB-=aC;if(aB){am.arraySet(aF.window,aE,aD-aB,aB,0);aF.wnext=aB;aF.whave=aF.wsize}else{aF.wnext+=aC;if(aF.wnext===aF.wsize){aF.wnext=0}if(aF.whave>>8)&255;a2.check=m(a2.check,aJ,2,0);aO=0;aD=0;a2.mode=B;break}a2.flags=0;if(a2.head){a2.head.done=!1}if(!(a2.wrap&1)||(((aO&255)<<8)+(aO>>8))%31){a3.msg="incorrect header check";a2.mode=f;break}if((aO&15)!==ar){a3.msg="unknown compression method";a2.mode=f;break}aO>>>=4;aD-=4;aU=(aO&15)+8;if(a2.wbits===0){a2.wbits=aU}else{if(aU>a2.wbits){a3.msg="invalid window size";a2.mode=f;break}}a2.dmax=1<>8)&1)}if(a2.flags&512){aJ[0]=aO&255;aJ[1]=(aO>>>8)&255;a2.check=m(a2.check,aJ,2,0)}aO=0;aD=0;a2.mode=ai;case ai:while(aD<32){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>8)&255;aJ[2]=(aO>>>16)&255;aJ[3]=(aO>>>24)&255;a2.check=m(a2.check,aJ,4,0)}aO=0;aD=0;a2.mode=ad;case ad:while(aD<16){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>8)}if(a2.flags&512){aJ[0]=aO&255;aJ[1]=(aO>>>8)&255;a2.check=m(a2.check,aJ,2,0)}aO=0;aD=0;a2.mode=x;case x:if(a2.flags&1024){while(aD<16){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>8)&255;a2.check=m(a2.check,aJ,2,0)}aO=0;aD=0}else{if(a2.head){a2.head.extra=null}}a2.mode=z;case z:if(a2.flags&1024){aE=a2.length;if(aE>aI){aE=aI}if(aE){if(a2.head){aU=a2.head.extra_len-a2.length;if(!a2.head.extra){a2.head.extra=new Array(a2.head.extra_len)}am.arraySet(a2.head.extra,aP,aW,aE,aU)}if(a2.flags&512){a2.check=m(a2.check,aP,aE,aW)}aI-=aE;aW+=aE;a2.length-=aE}if(a2.length){break inf_leave}}a2.length=0;a2.mode=ac;case ac:if(a2.flags&2048){if(aI===0){break inf_leave}aE=0;do{aU=aP[aW+aE++];if(a2.head&&aU&&(a2.length<65536)){a2.head.name+=String.fromCharCode(aU)}}while(aU&&aE>9)&1);a2.head.done=!0}a3.adler=a2.check=0;a2.mode=aj;break;case p:while(aD<32){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=aD&7;aD-=aD&7;a2.mode=g;break}while(aD<3){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=1;aD-=1;switch((aO&3)){case 0:a2.mode=af;break;case 1:A(a2);a2.mode=R;if(aF===az){aO>>>=2;aD-=2;break inf_leave}break;case 2:a2.mode=ah;break;case 3:a3.msg="invalid block type";a2.mode=f}aO>>>=2;aD-=2;break;case af:aO>>>=aD&7;aD-=aD&7;while(aD<32){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>16)^65535)){a3.msg="invalid stored block lengths";a2.mode=f;break}a2.length=aO&65535;aO=0;aD=0;a2.mode=l;if(aF===az){break inf_leave}case l:a2.mode=k;case k:aE=a2.length;if(aE){if(aE>aI){aE=aI}if(aE>aT){aE=aT}if(aE===0){break inf_leave}am.arraySet(aZ,aP,aW,aE,a0);aI-=aE;aW+=aE;aT-=aE;a0+=aE;a2.length-=aE;break}a2.mode=aj;break;case ah:while(aD<14){if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=5;aD-=5;a2.ndist=(aO&31)+1;aO>>>=5;aD-=5;a2.ncode=(aO&15)+4;aO>>>=4;aD-=4;if(a2.nlen>286||a2.ndist>30){a3.msg="too many length or distance symbols";a2.mode=f;break}a2.have=0;a2.mode=V;case V:while(a2.have>>=3;aD-=3}while(a2.have<19){a2.lens[aY[a2.have++]]=0}a2.lencode=a2.lendyn;a2.lenbits=7;aX={bits:a2.lenbits};a1=G(i,a2.lens,0,19,a2.lencode,0,a2.work,aX);a2.lenbits=aX.bits;if(a1){a3.msg="invalid code lengths set";a2.mode=f;break}a2.have=0;a2.mode=h;case h:while(a2.have>>24;aM=(aK>>>16)&255;aN=aK&65535;if((aL)<=aD){break}if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=aL;aD-=aL;a2.lens[a2.have++]=aN}else{if(aN===16){aV=aL+2;while(aD>>=aL;aD-=aL;if(a2.have===0){a3.msg="invalid bit length repeat";a2.mode=f;break}aU=a2.lens[a2.have-1];aE=3+(aO&3);aO>>>=2;aD-=2}else{if(aN===17){aV=aL+3;while(aD>>=aL;aD-=aL;aU=0;aE=3+(aO&7);aO>>>=3;aD-=3}else{aV=aL+7;while(aD>>=aL;aD-=aL;aU=0;aE=11+(aO&127);aO>>>=7;aD-=7}}if(a2.have+aE>a2.nlen+a2.ndist){a3.msg="invalid bit length repeat";a2.mode=f;break}while(aE--){a2.lens[a2.have++]=aU}}}if(a2.mode===f){break}if(a2.lens[256]===0){a3.msg="invalid code -- missing end-of-block";a2.mode=f;break}a2.lenbits=9;aX={bits:a2.lenbits};a1=G(W,a2.lens,0,a2.nlen,a2.lencode,0,a2.work,aX);a2.lenbits=aX.bits;if(a1){a3.msg="invalid literal/lengths set";a2.mode=f;break}a2.distbits=6;a2.distcode=a2.distdyn;aX={bits:a2.distbits};a1=G(t,a2.lens,a2.nlen,a2.ndist,a2.distcode,0,a2.work,aX);a2.distbits=aX.bits;if(a1){a3.msg="invalid distances set";a2.mode=f;break}a2.mode=R;if(aF===az){break inf_leave}case R:a2.mode=Q;case Q:if(aI>=6&&aT>=258){a3.next_out=a0;a3.avail_out=aT;a3.next_in=aW;a3.avail_in=aI;a2.hold=aO;a2.bits=aD;F(a3,aC);a0=a3.next_out;aZ=a3.output;aT=a3.avail_out;aW=a3.next_in;aP=a3.input;aI=a3.avail_in;aO=a2.hold;aD=a2.bits;if(a2.mode===aj){a2.back=-1}break}a2.back=0;for(;;){aK=a2.lencode[aO&((1<>>24;aM=(aK>>>16)&255;aN=aK&65535;if(aL<=aD){break}if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>aQ)];aL=aK>>>24;aM=(aK>>>16)&255;aN=aK&65535;if((aQ+aL)<=aD){break}if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=aQ;aD-=aQ;a2.back+=aQ}aO>>>=aL;aD-=aL;a2.back+=aL;a2.length=aN;if(aM===0){a2.mode=X;break}if(aM&32){a2.back=-1;a2.mode=aj;break}if(aM&64){a3.msg="invalid literal/length code";a2.mode=f;break}a2.extra=aM&15;a2.mode=S;case S:if(a2.extra){aV=a2.extra;while(aD>>=a2.extra;aD-=a2.extra;a2.back+=a2.extra}a2.was=a2.length;a2.mode=q;case q:for(;;){aK=a2.distcode[aO&((1<>>24;aM=(aK>>>16)&255;aN=aK&65535;if((aL)<=aD){break}if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>aQ)];aL=aK>>>24;aM=(aK>>>16)&255;aN=aK&65535;if((aQ+aL)<=aD){break}if(aI===0){break inf_leave}aI--;aO+=aP[aW++]<>>=aQ;aD-=aQ;a2.back+=aQ}aO>>>=aL;aD-=aL;a2.back+=aL;if(aM&64){a3.msg="invalid distance code";a2.mode=f;break}a2.offset=aN;a2.extra=(aM)&15;a2.mode=r;case r:if(a2.extra){aV=a2.extra;while(aD>>=a2.extra;aD-=a2.extra;a2.back+=a2.extra}if(a2.offset>a2.dmax){a3.msg="invalid distance too far back";a2.mode=f;break}a2.mode=Y;case Y:if(aT===0){break inf_leave}aE=aC-aT;if(a2.offset>aE){aE=a2.offset-aE;if(aE>a2.whave){if(a2.sane){a3.msg="invalid distance too far back";a2.mode=f;break}}if(aE>a2.wnext){aE-=a2.wnext;aG=a2.wsize-aE}else{aG=a2.wnext-aE}if(aE>a2.length){aE=a2.length}aH=a2.window}else{aH=aZ;aG=a0-a2.offset;aE=a2.length}if(aE>aT){aE=aT}aT-=aE;a2.length-=aE;do{aZ[a0++]=aH[aG++]}while(--aE);if(a2.length===0){a2.mode=Q}break;case X:if(aT===0){break inf_leave}aZ[a0++]=a2.length;aT--;a2.mode=Q;break;case g:if(a2.wrap){while(aD<32){if(aI===0){break inf_leave}aI--;aO|=aP[aW++]<=1;Q--){if(x[Q]!==0){break}}if(V>Q){V=Q}if(Q===0){X[Y++]=(1<<24)|(64<<16)|0;X[Y++]=(1<<24)|(64<<16)|0;U.bits=1;return 0}for(R=1;R0&&(Z===e||Q!==1)){return -1}T[1]=0;for(L=1;Lj)||(Z===h&&aa>i)){return 1}var I=0;for(;;){I++;E=L-z;if(ab[W]A){F=B[C+ab[W]];G=t[u+ab[W]]}else{F=32+64;G=0}}J=1<<(L-z);D=1<>z)+D]=(E<<24)|(F<<16)|G|0}while(D!==0);J=1<<(L-1);while(H&J){J>>=1}if(J!==0){H&=J-1;H+=J}else{H=0}W++;if(--x[L]===0){if(L===Q){break}L=M[N+ab[W]]}if(L>V&&(H&P)!==O){if(z===0){z=V}S+=R;y=L-z;K=1<j)||(Z===h&&aa>i)){return 1}O=H&P;X[O]=(V<<24)|(y<<16)|(S-Y)|0}}if(H!==0){X[S+H]=((L-z)<<24)|(64<<16)|0}U.bits=V;return 0}},{"../utils/common":1}],10:[function(g,f,e){f.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],11:[function(g,f,e){function h(){this.input=null;this.next_in=0;this.avail_in=0;this.total_in=0;this.output=null;this.next_out=0;this.avail_out=0;this.total_out=0;this.msg="";this.state=null;this.data_type=2;this.adler=0}f.exports=h},{}],"/lib/inflate.js":[function(m,k,f){var q=m("./zlib/inflate");var p=m("./utils/common");var n=m("./utils/strings");var e=m("./zlib/constants");var l=m("./zlib/messages");var r=m("./zlib/zstream");var g=m("./zlib/gzheader");var o=Object.prototype.toString;function i(t){if(!(this instanceof i)){return new i(t)}this.options=p.assign({chunkSize:16384,windowBits:0,to:""},t||{});var s=this.options;if(s.raw&&(s.windowBits>=0)&&(s.windowBits<16)){s.windowBits=-s.windowBits;if(s.windowBits===0){s.windowBits=-15}}if((s.windowBits>=0)&&(s.windowBits<16)&&!(t&&t.windowBits)){s.windowBits+=32}if((s.windowBits>15)&&(s.windowBits<48)){if((s.windowBits&15)===0){s.windowBits|=15}}this.err=0;this.msg="";this.ended=!1;this.chunks=[];this.strm=new r();this.strm.avail_out=0;var u=q.inflateInit2(this.strm,s.windowBits);if(u!==e.Z_OK){throw new Error(l[u])}this.header=new g();q.inflateGetHeader(this.strm,this.header)}i.prototype.push=function(v,y){var B=this.strm;var u=this.options.chunkSize;var x=this.options.dictionary;var A,s;var z,C,D;var w;var t=!1;if(this.ended){return !1}s=(y===~~y)?y:((y===!0)?e.Z_FINISH:e.Z_NO_FLUSH);if(typeof v==="string"){B.input=n.binstring2buf(v)}else{if(o.call(v)==="[object ArrayBuffer]"){B.input=new Uint8Array(v)}else{B.input=v}}B.next_in=0;B.avail_in=B.input.length;do{if(B.avail_out===0){B.output=new p.Buf8(u);B.next_out=0;B.avail_out=u}A=q.inflate(B,e.Z_NO_FLUSH);if(A===e.Z_NEED_DICT&&x){if(typeof x==="string"){w=n.string2buf(x)}else{if(o.call(x)==="[object ArrayBuffer]"){w=new Uint8Array(x)}else{w=x}}A=q.inflateSetDictionary(this.strm,w)}if(A===e.Z_BUF_ERROR&&t===!0){A=e.Z_OK;t=!1}if(A!==e.Z_STREAM_END&&A!==e.Z_OK){this.onEnd(A);this.ended=!0;return !1}if(B.next_out){if(B.avail_out===0||A===e.Z_STREAM_END||(B.avail_in===0&&(s===e.Z_FINISH||s===e.Z_SYNC_FLUSH))){if(this.options.to==="string"){z=n.utf8border(B.output,B.next_out);C=B.next_out-z;D=n.buf2string(B.output,z);B.next_out=C;B.avail_out=u-C;if(C){p.arraySet(B.output,B.output,z,C,0)}this.onData(D)}else{this.onData(p.shrinkBuf(B.output,B.next_out))}}}if(B.avail_in===0&&B.avail_out===0){t=!0}}while((B.avail_in>0||B.avail_out===0)&&A!==e.Z_STREAM_END);if(A===e.Z_STREAM_END){s=e.Z_FINISH}if(s===e.Z_FINISH){A=q.inflateEnd(this.strm);this.onEnd(A);this.ended=!0;return A===e.Z_OK}if(s===e.Z_SYNC_FLUSH){this.onEnd(e.Z_OK);B.avail_out=0;return !0}return !0};i.prototype.onData=function(s){this.chunks.push(s)};i.prototype.onEnd=function(s){if(s===e.Z_OK){if(this.options.to==="string"){this.result=this.chunks.join("")}else{this.result=p.flattenChunks(this.chunks)}}this.chunks=[];this.err=s;this.msg=this.strm.msg};function h(t,u){var s=new i(u);s.push(t,!0);if(s.err){throw s.msg}return s.result}function j(s,t){t=t||{};t.raw=!0;return h(s,t)}f.Inflate=i;f.inflate=h;f.inflateRaw=j;f.ungzip=h},{"./utils/common":1,"./utils/strings":2,"./zlib/constants":4,"./zlib/gzheader":6,"./zlib/inflate":8,"./zlib/messages":10,"./zlib/zstream":11}]},{},[])("/lib/inflate.js")});function PngImage(){var m="",i=this,j=new PngToy(),a,b,n=0,g=0,c=!1;this.onload=null;this.onerror=null;Object.defineProperty(this,"src",{get:function(){return m},set:function(h){m=h;k()}});Object.defineProperty(this,"width",{get:function(){return n}});Object.defineProperty(this,"height",{get:function(){return g}});Object.defineProperty(this,"naturalWidth",{get:function(){return n}});Object.defineProperty(this,"naturalHeight",{get:function(){return g}});Object.defineProperty(this,"image",{get:function(){return b}});Object.defineProperty(this,"pngtoy",{get:function(){return j}});Object.defineProperty(this,"complete",{get:function(){return c}});function k(){j.fetch(m).then(e,f)}function e(h){j.decode(h).then(d,f)}function d(h){a=h;n=h.width;g=h.height;j.convertToCanvas(h,{ignoreAspectRatio:!1,useGamma:!1}).then(l.bind(i),f.bind(i))}function l(h){b=h;c=!0;if(i.onload){i.onload({timeStamp:Date.now()})}}function f(h){if(i.onerror){i.onerror({message:h,timeStamp:Date.now()})}}};
7 | window.PngToy = PngToy;
8 |
--------------------------------------------------------------------------------