-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
tercoli
committed
Sep 13, 2020
0 parents
commit 3112aee
Showing
19 changed files
with
695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Empty AssemblyScript Project |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// The Game of Life, also known simply as Life, is a | ||
// cellular automaton devised by the British | ||
// mathematician John Horton Conway in 1970. | ||
// | ||
// https://en.wikipedia.org/wiki/Conway's_Game_of_Life | ||
|
||
let width: i32; | ||
let height: i32; | ||
let size: i32; | ||
|
||
/** Initializes width and height. Called once from JS. */ | ||
export function init(inputWidth: i32, inputHeight: i32): void { | ||
width = inputWidth; | ||
height = inputHeight; | ||
size = width * height; | ||
} | ||
|
||
/** Performs one step. Called about 30 times a second from JS. */ | ||
export function step(): void { | ||
// The universe of the Game of Life is an infinite two-dimensional | ||
// orthogonal grid of square "cells", each of which is in one | ||
// of two possible states, alive or dead. | ||
|
||
for (let row = 0; row < height; ++row) { | ||
// Create the torus ilusion. Top and bottom are connected. | ||
let rowMinus1 = row == 0 ? height - 1 : row - 1; | ||
let rowPlus1 = row == height - 1 ? 0 : row + 1; | ||
|
||
for (let column = 0; column < width; ++column) { | ||
// Create the torus ilusion. Left and right are connected. | ||
let columnMinus1 = column == 0 ? width - 1 : column - 1; | ||
let columnPlus1 = column == width - 1 ? 0 : column + 1; | ||
|
||
// Every cell interacts with its eight neighbours, | ||
// which are the cells that are horizontally, | ||
// vertically, or diagonally adjacent: | ||
let aliveNeighbors = | ||
load<u8>(rowMinus1 * width + columnMinus1) + | ||
load<u8>(rowMinus1 * width + column) + | ||
load<u8>(rowMinus1 * width + columnPlus1) + | ||
load<u8>(row * width + columnMinus1) + | ||
load<u8>(row * width + columnPlus1) + | ||
load<u8>(rowPlus1 * width + columnMinus1) + | ||
load<u8>(rowPlus1 * width + column) + | ||
load<u8>(rowPlus1 * width + columnPlus1); | ||
|
||
let alive = load<u8>(row * width + column); | ||
if (alive) { | ||
switch (aliveNeighbors) { | ||
// A live cell with fewer than 2 live neighbors dies, as if caused by underpopulation. | ||
// A live cell with more than 3 live neighbors dies, as if by overpopulation. | ||
default: { | ||
store<u8>(size + row * width + column, 0); | ||
break; | ||
} | ||
// A live cell with 2 or 3 live neighbors lives on to the next generation. | ||
case 2: | ||
case 3: | ||
} | ||
} else { | ||
switch (aliveNeighbors) { | ||
// A dead cell with exactly 3 live neighbors becomes a live cell, as if by reproduction. | ||
case 3: { | ||
store<u8>(size + row * width + column, 1); | ||
break; | ||
} | ||
default: | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Performing a step uses bytes [0, size - 1] as the input | ||
// and writes the output to [size, 2 * size - 1]. | ||
|
||
// Note that the code above wastes a lot of space by using one byte per cell. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"extends": "../node_modules/assemblyscript/std/assembly.json", | ||
"include": [ | ||
"./**/*.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
const gulp = require("gulp"); | ||
/* | ||
Runtime variants: | ||
"--runtime", "full" (default) | ||
A proper memory manager and reference-counting based garbage collector, with runtime interfaces | ||
being exported to the host for being able to create managed objects externally. | ||
"--runtime", "half" | ||
The same as full but without any exports, i.e. where creating objects externally is not required. | ||
This allows the optimizer to eliminate parts of the runtime that are not needed. | ||
"--runtime", "stub" | ||
A minimalist arena memory manager without any means of freeing up memory again, but the same external | ||
interface as full. Useful for very short-lived programs or programs with hardly any memory footprint, | ||
while keeping the option to switch to full without any further changes. No garbage collection. | ||
"--runtime", "none" | ||
The same as stub but without any exports, for the same reasons as explained in half. Essentially | ||
evaporates entirely after optimizations. | ||
For more information see: https://docs.assemblyscript.org/details/runtime | ||
*/ | ||
gulp.task("build", callback => { | ||
const asc = require("assemblyscript/bin/asc"); | ||
asc.main([ | ||
"main.ts", | ||
"--baseDir", "assembly", | ||
"--binaryFile", "../out/main.wasm", | ||
"--sourceMap", | ||
"--measure", | ||
"--runtime", "half", | ||
"--optimize", | ||
"--importMemory" | ||
], callback); | ||
}); | ||
|
||
gulp.task("default", ["build"]); | ||
|
||
// This task is not required when running the project locally. Its purpose is to set up the | ||
// AssemblyScript compiler when a new project has been loaded in WebAssembly Studio. | ||
gulp.task("project:load", () => { | ||
const utils = require("@wasm/studio-utils"); | ||
utils.eval(utils.project.getFile("setup.js").getData(), { | ||
logLn, | ||
project, | ||
monaco, | ||
fileTypeForExtension, | ||
}); | ||
}); |
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "@wasm/empty_ts", | ||
"description": "", | ||
"version": "1.0.0", | ||
"scripts": { | ||
"build": "gulp" | ||
}, | ||
"devDependencies": { | ||
"assemblyscript": "AssemblyScript/assemblyscript", | ||
"gulp": "^3" | ||
}, | ||
"wasmStudio": { | ||
"name": "Empty AssemblyScript Project", | ||
"description": "# Empty AssemblyScript Project\n\n[AssemblyScript](https://github.com/AssemblyScript/assemblyscript) compiles strictly typed TypeScript to WebAssembly using Binaryen.\n\nSee the [AssemblyScript wiki](https://github.com/AssemblyScript/assemblyscript/wiki) for further instructions and documentation.", | ||
"icon": "typescript-lang-file-icon" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// This file is not required when running the project locally. Its purpose is to set up the | ||
// AssemblyScript compiler when a new project has been loaded in WebAssembly Studio. | ||
require.config({ | ||
paths: { | ||
"binaryen": "https://cdn.jsdelivr.net/npm/binaryen@latest/index", | ||
"assemblyscript": "https://cdn.jsdelivr.net/npm/assemblyscript@latest/dist/assemblyscript", | ||
"assemblyscript/bin/asc": "https://cdn.jsdelivr.net/npm/assemblyscript@latest/dist/asc", | ||
} | ||
}); | ||
logLn("Loading AssemblyScript compiler ..."); | ||
require(["assemblyscript/bin/asc"], asc => { | ||
monaco.languages.typescript.typescriptDefaults.addExtraLib(asc.definitionFiles.assembly); | ||
asc.main = (main => (args, options, fn) => { | ||
if (typeof options === "function") { | ||
fn = options; | ||
options = undefined; | ||
} | ||
return main(args, options || { | ||
stdout: asc.createMemoryStream(), | ||
stderr: asc.createMemoryStream(logLn), | ||
readFile: (filename, baseDir) => { | ||
const file = project.getFile(baseDir + "/" + filename.replace(/^\//, "")); | ||
return file ? file.data : null; | ||
}, | ||
writeFile: (filename, contents) => { | ||
const name = filename.startsWith("../") ? filename.substring(3) : filename; | ||
const type = fileTypeForExtension(name.substring(name.lastIndexOf(".") + 1)); | ||
project.newFile(name, type, true).setData(contents); | ||
}, | ||
listFiles: () => [] | ||
}, fn); | ||
})(asc.main); | ||
logLn("AssemblyScript compiler is ready!"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> | ||
<title>JUG SummerCamp 2020 WebAssembly Codelab - Game of Life</title> | ||
<style> | ||
html, | ||
body { | ||
height: 100%; | ||
margin: 0; | ||
overflow: hidden; | ||
} | ||
canvas { | ||
width: 100%; | ||
height: 100%; | ||
} | ||
</style> | ||
</head> | ||
<body style="background: #fff"> | ||
<canvas id="canvas"></canvas> | ||
<script src="./main.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Set up the canvas with a 2D rendering context | ||
const canvas = document.getElementById('canvas'); | ||
const context = canvas.getContext('2d'); | ||
const boundingClientRect = canvas.getBoundingClientRect(); | ||
canvas.width = boundingClientRect.width | 0; | ||
canvas.height = boundingClientRect.height | 0; | ||
|
||
const width = boundingClientRect.width >>> 1; // == boundingClientRect.width / 2 | ||
const height = boundingClientRect.height >>> 1; // == boundingClientRect.height /2 | ||
const size = width * height; // memory required to store either input or output | ||
const totalMemoryRequired = size + size; // total memory required to store input and output | ||
|
||
// Compute the size of and instantiate the module's memory | ||
const numberPages = ((totalMemoryRequired + 0xffff) & ~0xffff) >>> 16; // aligned up in 64k units | ||
const wasmMemory = new WebAssembly.Memory({ initial: numberPages }); | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// Executed when the WASM module is instantiated | ||
function initGame(module) { | ||
const exports = module.instance.exports; | ||
|
||
// Tell the module about the universe's width and height | ||
exports.init(width, height); | ||
|
||
// Fill input at [0, s-1] with random live cells | ||
const memory = new Uint8Array(wasmMemory.buffer); | ||
for (let y = 0; y < height; ++y) | ||
for (let x = 0; x < width; ++x) | ||
memory[y * width + x] = Math.random() > 0.1 ? 0 : 1; | ||
|
||
// Update about 30 times a second | ||
const desiredFps = 30; | ||
const frameDuration = 1000 / 30; | ||
function update() { | ||
// To be done | ||
} | ||
// Poorly optimised render function | ||
// Easily bigger bottleneck than the actual module | ||
function render() { | ||
// To be done | ||
} | ||
update(); | ||
render(); | ||
} | ||
|
||
function update() { | ||
setTimeout(update, frameDuration); | ||
exports.step(); | ||
// copy output at [size, totalMemoryRequired] to input at [0, size] | ||
memory.copyWithin(0, size, totalMemoryRequired); | ||
} | ||
|
||
function render() { | ||
requestAnimationFrame(render); | ||
|
||
context.fillStyle = 'rgba(238,238,238,0.67)'; | ||
context.fillRect(0, 0, width << 1, height << 1); | ||
context.fillStyle = '#333'; | ||
|
||
for (var y = 0; y < height; ++y) | ||
for (var x = 0; x < width; ++x) | ||
if (memory[size + y * width + x]) | ||
context.fillRect(x << 1, y << 1, 2, 2); | ||
} | ||
|
||
// Fetch and instantiate the module | ||
async function loadAndInstantiate() { | ||
let response = await fetch('../out/main.wasm'); | ||
let arrayBuffer = await response.arrayBuffer(); | ||
let wasmModule = await WebAssembly.instantiate(arrayBuffer, | ||
{ env: { memory: wasmMemory } }); | ||
initGame(wasmModule); | ||
} | ||
loadAndInstantiate(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>JUG SummerCamp 2020 WebAssembly Codelab - Hello WebAssembly</title> | ||
</head> | ||
<body> | ||
<h1>JUG SummerCamp 2020 WebAssembly Codelab</h1> | ||
<h2>Hello WebAssembly</h2> | ||
|
||
<p> | ||
We are using a `helloWebAssembly()` | ||
function written in C, compiled into WASM | ||
and loaded and instantiated via JS. | ||
</p> | ||
|
||
<p> | ||
Look at the console, it it works you should see | ||
a `Hello WebAssembly` message. | ||
</p> | ||
</body> | ||
|
||
<script src='./HelloWebAssembly.js'></script> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
let configurationObject = { | ||
} | ||
|
||
async function loadWASM() { | ||
let response = await fetch('./HelloWebAssembly.wasm'); | ||
let arrayBuffer = await response.arrayBuffer(); | ||
let wasmModule = await WebAssembly.instantiate(arrayBuffer, configurationObject); | ||
let helloWebAssembly = await wasmModule.instance.exports.helloWebAssembly; | ||
|
||
let str = readWASMbuffer(wasmModule.instance, helloWebAssembly()); | ||
console.log(str); | ||
} | ||
|
||
function readWASMbuffer(wasmInstance, pointer) { | ||
let buffer = new Int8Array(wasmInstance.exports.memory.buffer); | ||
let str = ""; | ||
for (i = pointer; buffer[i]; i++) { | ||
str += String.fromCharCode(buffer[i]); | ||
} | ||
return str; | ||
} | ||
|
||
loadWASM(); |
Binary file not shown.
Oops, something went wrong.