mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-12 14:31:28 +00:00
Make the mandelbrot example a bit more fun as well
This commit is contained in:
@ -1,60 +1,99 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mandelbrot Set - AssemblyScript</title>
|
||||
<title>Mandelbrot set - AssemblyScript</title>
|
||||
<style>
|
||||
html, body { height: 100%; margin: 0; overflow: hidden; color: #111; background: #fff; font-family: sans-serif; }
|
||||
h1 { padding: 20px; font-size: 12pt; margin: 0; }
|
||||
a { color: #111; text-decoration: none; }
|
||||
a:hover { color: #0074C1; text-decoration: underline; }
|
||||
canvas { position: absolute; top: 60px; left: 20px; width: calc(100% - 40px); height: calc(100% - 80px); background: #eee; }
|
||||
canvas.gradient { left: 0; top: 0px; height: 2px; width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
<a href="https://en.wikipedia.org/wiki/Mandelbrot_set">Mandelbrot Set</a> in
|
||||
<a href="https://en.wikipedia.org/wiki/Mandelbrot_set">Mandelbrot set</a> in
|
||||
<a href="http://assemblyscript.org">AssemblyScript</a>
|
||||
( <a href="https://github.com/AssemblyScript/assemblyscript/blob/master/examples/mandelbrot/assembly/index.ts">source</a> )
|
||||
</h1>
|
||||
<canvas></canvas>
|
||||
<script>"use strict";
|
||||
|
||||
// Set up a 2D rendering context
|
||||
// Set this to false if you prefer a plain image instead.
|
||||
var animate = true;
|
||||
|
||||
// Set up the canvas with a 2D rendering context
|
||||
var cnv = document.getElementsByTagName("canvas")[0];
|
||||
var ctx = cnv.getContext("2d");
|
||||
var bcr = cnv.getBoundingClientRect();
|
||||
cnv.width = bcr.width | 0;
|
||||
cnv.height = bcr.height | 0;
|
||||
|
||||
// Compute the size of the viewport
|
||||
var width = bcr.width | 0;
|
||||
var height = bcr.height | 0;
|
||||
var size = width * height;
|
||||
var byteSize = size << 1; // discrete color indices in range [0, 2047] (here: 2b per pixel)
|
||||
|
||||
cnv.width = width;
|
||||
cnv.height = height;
|
||||
|
||||
// Compute the size of and instantiate the module's memory
|
||||
var memory = new WebAssembly.Memory({ initial: ((byteSize + 0xffff) & ~0xffff) >>> 16 });
|
||||
var mem = new Uint16Array(memory.buffer);
|
||||
var imageData = ctx.createImageData(width, height);
|
||||
var argb = new Uint32Array(imageData.data.buffer);
|
||||
|
||||
// Fetch and instantiate the module
|
||||
fetch("build/optimized.wasm")
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(buffer => WebAssembly.instantiate(buffer, { JSMath: Math }))
|
||||
.then(buffer => WebAssembly.instantiate(buffer, {
|
||||
env: { memory: memory },
|
||||
JSMath: Math
|
||||
}))
|
||||
.then(module => {
|
||||
var exports = module.instance.exports;
|
||||
var memory = exports.memory;
|
||||
var computeLine = exports.computeLine;
|
||||
var updateLine = function(y) {
|
||||
var yx = y * width;
|
||||
for (let x = 0; x < width; ++x) argb[yx + x] = colors[mem[yx + x]];
|
||||
};
|
||||
|
||||
// Determine required memory size and grow if necessary
|
||||
var width = cnv.width | 0;
|
||||
var height = cnv.height | 0;
|
||||
var byteSize = 2 * width * height; // 2b per pixel (0..2041)
|
||||
if (memory.buffer.byteLength < byteSize) {
|
||||
let pages = ((byteSize - memory.buffer.byteLength + 0xffff) & ~0xffff) >>> 16;
|
||||
memory.grow(pages);
|
||||
}
|
||||
|
||||
// Compute and render to the canvas
|
||||
exports.compute(width, height, 40);
|
||||
var mem = new Uint16Array(memory.buffer);
|
||||
var imageData = ctx.createImageData(width, height);
|
||||
var argb = new Uint32Array(imageData.data.buffer);
|
||||
// Compute an initial balanced version of the set.
|
||||
const limit = 40;
|
||||
for (let y = 0; y < height; ++y) {
|
||||
let yx = y * width;
|
||||
for (let x = 0; x < width; ++x) {
|
||||
argb[yx + x] = colors[mem[yx + x]];
|
||||
}
|
||||
computeLine(y, width, height, limit);
|
||||
updateLine(y);
|
||||
}
|
||||
|
||||
// Keep rendering the image buffer.
|
||||
(function render() {
|
||||
if (animate) requestAnimationFrame(render);
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
})();
|
||||
|
||||
if (animate) {
|
||||
|
||||
// Let it glow a bit by occasionally shifting the limit...
|
||||
var currentLimit = limit;
|
||||
var shiftRange = 10;
|
||||
(function updateShift() {
|
||||
currentLimit = limit + (2 * Math.random() * shiftRange - shiftRange) | 0
|
||||
setTimeout(updateShift, 1000 + (1500 * Math.random()) | 0);
|
||||
})();
|
||||
|
||||
// ...while continously recomputing a subset of it.
|
||||
var flickerRange = 3;
|
||||
(function updateFlicker() {
|
||||
for (let i = 0, k = (0.05 * height) | 0; i < k; ++i) {
|
||||
let ry = (Math.random() * height) | 0;
|
||||
let rl = (2 * Math.random() * flickerRange - flickerRange) | 0;
|
||||
computeLine(ry, width, height, currentLimit + rl);
|
||||
updateLine(ry);
|
||||
}
|
||||
setTimeout(updateFlicker, 1000 / 30);
|
||||
})();
|
||||
|
||||
}
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
}).catch(err => {
|
||||
alert("Failed to load WASM: " + err.message + " (ad blocker, maybe?)");
|
||||
console.log(err.stack);
|
||||
@ -67,13 +106,15 @@ var colors = (() => {
|
||||
cnv.height = 1;
|
||||
var ctx = cnv.getContext("2d");
|
||||
var grd = ctx.createLinearGradient(0, 0, 2048, 0);
|
||||
grd.addColorStop(0, "#000764");
|
||||
grd.addColorStop(0.25, "#2068CB");
|
||||
grd.addColorStop(0.50, "#EDFFFF");
|
||||
grd.addColorStop(0.65, "#FFAA00");
|
||||
grd.addColorStop(0.85, "#000200");
|
||||
grd.addColorStop(0.00, "#000764");
|
||||
grd.addColorStop(0.16, "#2068CB");
|
||||
grd.addColorStop(0.42, "#EDFFFF");
|
||||
grd.addColorStop(0.6425, "#FFAA00");
|
||||
grd.addColorStop(0.8575, "#000200");
|
||||
ctx.fillStyle = grd;
|
||||
ctx.fillRect(0, 0, 2048, 1);
|
||||
cnv.className = "gradient";
|
||||
setTimeout(() => document.body.appendChild(cnv));
|
||||
return new Uint32Array(ctx.getImageData(0, 0, 2048, 1).data.buffer);
|
||||
})();
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user