First working version
This commit is contained in:
parent
dbf765dff4
commit
a0b32a783b
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.vscode/
|
.vscode/
|
||||||
pkg/
|
pkg/
|
||||||
|
package-lock.json
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
```
|
```
|
||||||
wasm-pack build
|
wasm-pack build
|
||||||
|
cd www
|
||||||
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
This app uses:
|
This app uses:
|
||||||
|
|
72
docs/0.bootstrap.js
Normal file
72
docs/0.bootstrap.js
Normal file
File diff suppressed because one or more lines are too long
315
docs/bootstrap.js
vendored
Normal file
315
docs/bootstrap.js
vendored
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
|
/******/ // install a JSONP callback for chunk loading
|
||||||
|
/******/ function webpackJsonpCallback(data) {
|
||||||
|
/******/ var chunkIds = data[0];
|
||||||
|
/******/ var moreModules = data[1];
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // add "moreModules" to the modules object,
|
||||||
|
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||||||
|
/******/ var moduleId, chunkId, i = 0, resolves = [];
|
||||||
|
/******/ for(;i < chunkIds.length; i++) {
|
||||||
|
/******/ chunkId = chunkIds[i];
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||||||
|
/******/ resolves.push(installedChunks[chunkId][0]);
|
||||||
|
/******/ }
|
||||||
|
/******/ installedChunks[chunkId] = 0;
|
||||||
|
/******/ }
|
||||||
|
/******/ for(moduleId in moreModules) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
|
||||||
|
/******/ modules[moduleId] = moreModules[moduleId];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
|
||||||
|
/******/
|
||||||
|
/******/ while(resolves.length) {
|
||||||
|
/******/ resolves.shift()();
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var installedModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ // object to store loaded and loading chunks
|
||||||
|
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||||||
|
/******/ // Promise = chunk loading, 0 = chunk loaded
|
||||||
|
/******/ var installedChunks = {
|
||||||
|
/******/ "main": 0
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // script path function
|
||||||
|
/******/ function jsonpScriptSrc(chunkId) {
|
||||||
|
/******/ return __webpack_require__.p + "" + chunkId + ".bootstrap.js"
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // object to store loaded and loading wasm modules
|
||||||
|
/******/ var installedWasmModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ function promiseResolve() { return Promise.resolve(); }
|
||||||
|
/******/
|
||||||
|
/******/ var wasmImportObjects = {
|
||||||
|
/******/ "../pkg/mapgen_demo_bg.wasm": function() {
|
||||||
|
/******/ return {
|
||||||
|
/******/ "./mapgen_demo_bg.js": {
|
||||||
|
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_object_drop_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_instanceof_Window_adf3196bdc02b386": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_instanceof_Window_adf3196bdc02b386"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_document_6cc8d0b87c0a99b9": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_document_6cc8d0b87c0a99b9"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_body_8c888fe47d81765f": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_body_8c888fe47d81765f"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_createElement_5bdf88a5af9f17c5": function(p0i32,p1i32,p2i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_createElement_5bdf88a5af9f17c5"](p0i32,p1i32,p2i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_setinnerHTML_4ff235db1a3cb4d8": function(p0i32,p1i32,p2i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_setinnerHTML_4ff235db1a3cb4d8"](p0i32,p1i32,p2i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_appendChild_77215fd672b162c5": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_appendChild_77215fd672b162c5"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_call_8e95613cc6524977": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_call_8e95613cc6524977"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_newnoargs_f3b8a801d5d4b079": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_newnoargs_f3b8a801d5d4b079"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_self_07b2f89e82ceb76d": function() {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_self_07b2f89e82ceb76d"]();
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_window_ba85d88572adc0dc": function() {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_window_ba85d88572adc0dc"]();
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_globalThis_b9277fc37e201fe5": function() {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_globalThis_b9277fc37e201fe5"]();
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_global_e16303fe83e1d57f": function() {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_global_e16303fe83e1d57f"]();
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_is_undefined": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_is_undefined"](p0i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_throw"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbindgen_rethrow": function(p0i32) {
|
||||||
|
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_rethrow"](p0i32);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ },
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ if(installedModules[moduleId]) {
|
||||||
|
/******/ return installedModules[moduleId].exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = installedModules[moduleId] = {
|
||||||
|
/******/ i: moduleId,
|
||||||
|
/******/ l: false,
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Flag the module as loaded
|
||||||
|
/******/ module.l = true;
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // This file contains only the entry chunk.
|
||||||
|
/******/ // The chunk loading function for additional chunks
|
||||||
|
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
|
||||||
|
/******/ var promises = [];
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // JSONP chunk loading for javascript
|
||||||
|
/******/
|
||||||
|
/******/ var installedChunkData = installedChunks[chunkId];
|
||||||
|
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
|
||||||
|
/******/
|
||||||
|
/******/ // a Promise means "currently loading".
|
||||||
|
/******/ if(installedChunkData) {
|
||||||
|
/******/ promises.push(installedChunkData[2]);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ // setup Promise in chunk cache
|
||||||
|
/******/ var promise = new Promise(function(resolve, reject) {
|
||||||
|
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
|
||||||
|
/******/ });
|
||||||
|
/******/ promises.push(installedChunkData[2] = promise);
|
||||||
|
/******/
|
||||||
|
/******/ // start chunk loading
|
||||||
|
/******/ var script = document.createElement('script');
|
||||||
|
/******/ var onScriptComplete;
|
||||||
|
/******/
|
||||||
|
/******/ script.charset = 'utf-8';
|
||||||
|
/******/ script.timeout = 120;
|
||||||
|
/******/ if (__webpack_require__.nc) {
|
||||||
|
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||||
|
/******/ }
|
||||||
|
/******/ script.src = jsonpScriptSrc(chunkId);
|
||||||
|
/******/
|
||||||
|
/******/ // create error before stack unwound to get useful stacktrace later
|
||||||
|
/******/ var error = new Error();
|
||||||
|
/******/ onScriptComplete = function (event) {
|
||||||
|
/******/ // avoid mem leaks in IE.
|
||||||
|
/******/ script.onerror = script.onload = null;
|
||||||
|
/******/ clearTimeout(timeout);
|
||||||
|
/******/ var chunk = installedChunks[chunkId];
|
||||||
|
/******/ if(chunk !== 0) {
|
||||||
|
/******/ if(chunk) {
|
||||||
|
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||||
|
/******/ var realSrc = event && event.target && event.target.src;
|
||||||
|
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||||
|
/******/ error.name = 'ChunkLoadError';
|
||||||
|
/******/ error.type = errorType;
|
||||||
|
/******/ error.request = realSrc;
|
||||||
|
/******/ chunk[1](error);
|
||||||
|
/******/ }
|
||||||
|
/******/ installedChunks[chunkId] = undefined;
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ var timeout = setTimeout(function(){
|
||||||
|
/******/ onScriptComplete({ type: 'timeout', target: script });
|
||||||
|
/******/ }, 120000);
|
||||||
|
/******/ script.onerror = script.onload = onScriptComplete;
|
||||||
|
/******/ document.head.appendChild(script);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/ // Fetch + compile chunk loading for webassembly
|
||||||
|
/******/
|
||||||
|
/******/ var wasmModules = {"0":["../pkg/mapgen_demo_bg.wasm"]}[chunkId] || [];
|
||||||
|
/******/
|
||||||
|
/******/ wasmModules.forEach(function(wasmModuleId) {
|
||||||
|
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
|
||||||
|
/******/
|
||||||
|
/******/ // a Promise means "currently loading" or "already loaded".
|
||||||
|
/******/ if(installedWasmModuleData)
|
||||||
|
/******/ promises.push(installedWasmModuleData);
|
||||||
|
/******/ else {
|
||||||
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/mapgen_demo_bg.wasm":"f138b06b088ae74c6a29"}[wasmModuleId] + ".module.wasm");
|
||||||
|
/******/ var promise;
|
||||||
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
/******/ return WebAssembly.instantiate(items[0], items[1]);
|
||||||
|
/******/ });
|
||||||
|
/******/ } else if(typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
|
/******/ promise = WebAssembly.instantiateStreaming(req, importObject);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });
|
||||||
|
/******/ promise = bytesPromise.then(function(bytes) {
|
||||||
|
/******/ return WebAssembly.instantiate(bytes, importObject);
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
/******/ promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {
|
||||||
|
/******/ return __webpack_require__.w[wasmModuleId] = (res.instance || res).exports;
|
||||||
|
/******/ }));
|
||||||
|
/******/ }
|
||||||
|
/******/ });
|
||||||
|
/******/ return Promise.all(promises);
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = modules;
|
||||||
|
/******/
|
||||||
|
/******/ // expose the module cache
|
||||||
|
/******/ __webpack_require__.c = installedModules;
|
||||||
|
/******/
|
||||||
|
/******/ // define getter function for harmony exports
|
||||||
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||||
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||||
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // define __esModule on exports
|
||||||
|
/******/ __webpack_require__.r = function(exports) {
|
||||||
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||||
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||||
|
/******/ }
|
||||||
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // create a fake namespace object
|
||||||
|
/******/ // mode & 1: value is a module id, require it
|
||||||
|
/******/ // mode & 2: merge all properties of value into the ns
|
||||||
|
/******/ // mode & 4: return value when already ns object
|
||||||
|
/******/ // mode & 8|1: behave like require
|
||||||
|
/******/ __webpack_require__.t = function(value, mode) {
|
||||||
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||||
|
/******/ if(mode & 8) return value;
|
||||||
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||||
|
/******/ var ns = Object.create(null);
|
||||||
|
/******/ __webpack_require__.r(ns);
|
||||||
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||||
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||||
|
/******/ return ns;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||||
|
/******/ __webpack_require__.n = function(module) {
|
||||||
|
/******/ var getter = module && module.__esModule ?
|
||||||
|
/******/ function getDefault() { return module['default']; } :
|
||||||
|
/******/ function getModuleExports() { return module; };
|
||||||
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||||
|
/******/ return getter;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Object.prototype.hasOwnProperty.call
|
||||||
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||||
|
/******/
|
||||||
|
/******/ // __webpack_public_path__
|
||||||
|
/******/ __webpack_require__.p = "";
|
||||||
|
/******/
|
||||||
|
/******/ // on error function for async loading
|
||||||
|
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
|
||||||
|
/******/
|
||||||
|
/******/ // object with all WebAssembly.instance exports
|
||||||
|
/******/ __webpack_require__.w = {};
|
||||||
|
/******/
|
||||||
|
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
|
||||||
|
/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
|
||||||
|
/******/ jsonpArray.push = webpackJsonpCallback;
|
||||||
|
/******/ jsonpArray = jsonpArray.slice();
|
||||||
|
/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
|
||||||
|
/******/ var parentJsonpFunction = oldJsonpFunction;
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // Load entry module and return exports
|
||||||
|
/******/ return __webpack_require__(__webpack_require__.s = "./bootstrap.js");
|
||||||
|
/******/ })
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ ({
|
||||||
|
|
||||||
|
/***/ "./bootstrap.js":
|
||||||
|
/*!**********************!*\
|
||||||
|
!*** ./bootstrap.js ***!
|
||||||
|
\**********************/
|
||||||
|
/*! no static exports found */
|
||||||
|
/***/ (function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
eval("// A dependency graph that contains any wasm must all be imported\n// asynchronously. This `bootstrap.js` file does the single async import, so\n// that no one else needs to worry about it again.\n__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./index.js */ \"./index.js\"))\n .catch(e => console.error(\"Error importing `index.js`:\", e));\n\n\n//# sourceURL=webpack:///./bootstrap.js?");
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
/******/ });
|
BIN
docs/f138b06b088ae74c6a29.module.wasm
Normal file
BIN
docs/f138b06b088ae74c6a29.module.wasm
Normal file
Binary file not shown.
|
@ -2,30 +2,10 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Mapgen demo</title>
|
<title>Hello wasm-pack!</title>
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
#fps {
|
|
||||||
white-space: pre;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Map generator demo</h1>
|
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
|
||||||
<button id="play-pause"></button>
|
<script src="./bootstrap.js"></script>
|
||||||
<div id="fps"></div>
|
|
||||||
<canvas id="demo-canvas"></canvas>
|
|
||||||
<script src='./index.js'></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
199
docs/index.js
199
docs/index.js
|
@ -1,199 +0,0 @@
|
||||||
import { Universe, Cell } from "wasm-game-of-life";
|
|
||||||
import { memory } from "wasm-game-of-life/wasm_game_of_life_bg";
|
|
||||||
|
|
||||||
const CELL_SIZE = 8; // px
|
|
||||||
const GRID_COLOR = "#CCCCCC";
|
|
||||||
const DEAD_COLOR = "#FFFFFF";
|
|
||||||
const ALIVE_COLOR = "#000000";
|
|
||||||
|
|
||||||
// Construct the universe, and get its width and height.
|
|
||||||
// const universe = Universe.new_spaceship();
|
|
||||||
const universe = Universe.new();
|
|
||||||
const width = universe.width();
|
|
||||||
const height = universe.height();
|
|
||||||
|
|
||||||
// Give the canvas room for all of our cells and a 1px border
|
|
||||||
// around each of them.
|
|
||||||
const canvas = document.getElementById("game-of-life-canvas");
|
|
||||||
canvas.height = (CELL_SIZE + 1) * height + 1;
|
|
||||||
canvas.width = (CELL_SIZE + 1) * width + 1;
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
let animationId = null;
|
|
||||||
|
|
||||||
const renderLoop = () => {
|
|
||||||
fps.render();
|
|
||||||
for (let i = 0; i < 9; i++) {
|
|
||||||
universe.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawGrid();
|
|
||||||
drawCells();
|
|
||||||
|
|
||||||
animationId = requestAnimationFrame(renderLoop);
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawGrid = () => {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.strokeStyle = GRID_COLOR;
|
|
||||||
|
|
||||||
// Vertical lines.
|
|
||||||
for (let i = 0; i <= width; i++) {
|
|
||||||
ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
|
|
||||||
ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Horizontal lines.
|
|
||||||
for (let j = 0; j <= height; j++) {
|
|
||||||
ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
|
|
||||||
ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getIndex = (row, column) => {
|
|
||||||
return row * width + column;
|
|
||||||
};
|
|
||||||
|
|
||||||
const drawCells = () => {
|
|
||||||
const cellsPtr = universe.cells();
|
|
||||||
|
|
||||||
// This is updated!
|
|
||||||
const cells = new Uint8Array(memory.buffer, cellsPtr, width * height / 8);
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
|
|
||||||
// Alive cells.
|
|
||||||
ctx.fillStyle = ALIVE_COLOR;
|
|
||||||
for (let row = 0; row < height; row++) {
|
|
||||||
for (let col = 0; col < width; col++) {
|
|
||||||
const idx = getIndex(row, col);
|
|
||||||
if (!bitIsSet(idx, cells)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.fillRect(
|
|
||||||
col * (CELL_SIZE + 1) + 1,
|
|
||||||
row * (CELL_SIZE + 1) + 1,
|
|
||||||
CELL_SIZE,
|
|
||||||
CELL_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dead cells.
|
|
||||||
ctx.fillStyle = DEAD_COLOR;
|
|
||||||
for (let row = 0; row < height; row++) {
|
|
||||||
for (let col = 0; col < width; col++) {
|
|
||||||
const idx = getIndex(row, col);
|
|
||||||
if (bitIsSet(idx, cells)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.fillRect(
|
|
||||||
col * (CELL_SIZE + 1) + 1,
|
|
||||||
row * (CELL_SIZE + 1) + 1,
|
|
||||||
CELL_SIZE,
|
|
||||||
CELL_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
};
|
|
||||||
|
|
||||||
const bitIsSet = (n, arr) => {
|
|
||||||
const byte = Math.floor(n / 8);
|
|
||||||
const mask = 1 << (n % 8);
|
|
||||||
return (arr[byte] & mask) === mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPaused = () => {
|
|
||||||
return animationId === null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const playPauseButton = document.getElementById("play-pause");
|
|
||||||
|
|
||||||
const play = () => {
|
|
||||||
playPauseButton.textContent = "⏸";
|
|
||||||
renderLoop();
|
|
||||||
};
|
|
||||||
|
|
||||||
const pause = () => {
|
|
||||||
playPauseButton.textContent = "▶";
|
|
||||||
cancelAnimationFrame(animationId);
|
|
||||||
animationId = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
playPauseButton.addEventListener("click", event => {
|
|
||||||
if (isPaused()) {
|
|
||||||
play();
|
|
||||||
} else {
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addEventListener("click", event => {
|
|
||||||
const boundingRect = canvas.getBoundingClientRect();
|
|
||||||
|
|
||||||
const scaleX = canvas.width / boundingRect.width;
|
|
||||||
const scaleY = canvas.height / boundingRect.height;
|
|
||||||
|
|
||||||
const canvasLeft = (event.clientX - boundingRect.left) * scaleX;
|
|
||||||
const canvasTop = (event.clientY - boundingRect.top) * scaleY;
|
|
||||||
|
|
||||||
const row = Math.min(Math.floor(canvasTop / (CELL_SIZE + 1)), height - 1);
|
|
||||||
const col = Math.min(Math.floor(canvasLeft / (CELL_SIZE + 1)), width - 1);
|
|
||||||
|
|
||||||
universe.toggle_cell(row, col);
|
|
||||||
|
|
||||||
drawGrid();
|
|
||||||
drawCells();
|
|
||||||
});
|
|
||||||
|
|
||||||
const fps = new class {
|
|
||||||
constructor() {
|
|
||||||
this.fps = document.getElementById("fps");
|
|
||||||
this.frames = [];
|
|
||||||
this.lastFrameTimeStamp = performance.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// Convert the delta time since the last frame render into a measure
|
|
||||||
// of frames per second.
|
|
||||||
const now = performance.now();
|
|
||||||
const delta = now - this.lastFrameTimeStamp;
|
|
||||||
this.lastFrameTimeStamp = now;
|
|
||||||
const fps = 1 / delta * 1000;
|
|
||||||
|
|
||||||
// Save only the latest 100 timings.
|
|
||||||
this.frames.push(fps);
|
|
||||||
if (this.frames.length > 100) {
|
|
||||||
this.frames.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the max, min, and mean of our 100 latest timings.
|
|
||||||
let min = Infinity;
|
|
||||||
let max = -Infinity;
|
|
||||||
let sum = 0;
|
|
||||||
for (let i = 0; i < this.frames.length; i++) {
|
|
||||||
sum += this.frames[i];
|
|
||||||
min = Math.min(this.frames[i], min);
|
|
||||||
max = Math.max(this.frames[i], max);
|
|
||||||
}
|
|
||||||
let mean = sum / this.frames.length;
|
|
||||||
|
|
||||||
// Render the statistics.
|
|
||||||
this.fps.textContent = `
|
|
||||||
Frames per Second:
|
|
||||||
latest = ${Math.round(fps)}
|
|
||||||
avg of last 100 = ${Math.round(mean)}
|
|
||||||
min of last 100 = ${Math.round(min)}
|
|
||||||
max of last 100 = ${Math.round(max)}
|
|
||||||
`.trim();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
play();
|
|
Loading…
Reference in New Issue
Block a user