Last active
July 8, 2021 19:53
-
-
Save tbfleming/e4c2cc66a6606aa92ff099c27ee2bd02 to your computer and use it in GitHub Desktop.
cib demo: canvas: bouncing lines
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
#include <math.h> | |
#include <stdio.h> | |
#include <string> | |
#include <vector> | |
using namespace std; | |
extern "C" double width(); | |
extern "C" double height(); | |
extern "C" void fillStyle(const char *); | |
extern "C" void strokeStyle(const char *); | |
extern "C" void clearRect(double x, double y, double width, double height); | |
extern "C" void fillRect(double x, double y, double width, double height); | |
extern "C" void beginPath(); | |
extern "C" void stroke(); | |
extern "C" void moveTo(double x, double y); | |
extern "C" void lineTo(double x, double y); | |
struct Point { | |
double x; | |
double y; | |
}; | |
struct Line { | |
Point p1; | |
Point p2; | |
}; | |
struct Color { | |
double r; | |
double g; | |
double b; | |
}; | |
void bounce(double &val, double &delta, double max) { | |
val += delta; | |
if (val < 0) { | |
val = 0; | |
delta = abs(delta); | |
} else if (val > max) { | |
val = max; | |
delta = -abs(delta); | |
} | |
} | |
void bounce(Point &p, Point &delta, double maxX, double maxY) { | |
bounce(p.x, delta.x, maxX); | |
bounce(p.y, delta.y, maxY); | |
} | |
void bounce(Line &l, Line &delta, double maxX, double maxY) { | |
bounce(l.p1, delta.p1, maxX, maxY); | |
bounce(l.p2, delta.p2, maxX, maxY); | |
} | |
void bounce(Color &c, Color &delta) { | |
bounce(c.r, delta.r, 1); | |
bounce(c.g, delta.g, 1); | |
bounce(c.b, delta.b, 1); | |
} | |
void drawLine(const Line &l) { | |
moveTo(l.p1.x, l.p1.y); | |
lineTo(l.p2.x, l.p2.y); | |
} | |
std::string colorStr(const Color &c) { | |
char result[10]; | |
snprintf(result, sizeof(result), "#%02x%02x%02x", int(c.r * 255), | |
int(c.g * 255), int(c.b * 255)); | |
return result; | |
} | |
Line line{Point{100, 300}, Point{300, 10}}; | |
Line lineDelta{Point{4, 3}, Point{-2, 5}}; | |
Color color{.2, .8, 0}; | |
Color colorDelta{.04, -.01, .02}; | |
std::vector<Line> lines; | |
extern "C" void drawFrame() { | |
auto w = width(); | |
auto h = height(); | |
clearRect(0, 0, w, h); | |
fillStyle("blue"); | |
fillRect(0, 0, 10, 10); | |
fillRect(w - 10, 0, 10, 10); | |
fillRect(0, h - 10, 10, 10); | |
fillRect(w - 10, h - 10, 10, 10); | |
auto c = color; | |
auto cd = colorDelta; | |
for (auto &line : lines) { | |
strokeStyle(colorStr(c).c_str()); | |
beginPath(); | |
drawLine(line); | |
stroke(); | |
bounce(c, cd); | |
} | |
bounce(line, lineDelta, w, h); | |
lines.push_back(line); | |
bounce(color, colorDelta); | |
if (lines.size() > 300) { | |
lines.erase(lines.begin()); | |
bounce(color, colorDelta); | |
} | |
} | |
void moveToward(Point &p, Point &delta, double x, double y) { | |
auto dist = sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y)); | |
if (dist) { | |
delta.x = (x - p.x) / dist * 6; | |
delta.y = (y - p.y) / dist * 6; | |
} | |
} | |
extern "C" void mousemove(double x, double y) { | |
moveToward(line.p2, lineDelta.p2, x, y); | |
} | |
int main() {} |
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
%init-scripts% | |
<style> | |
html, | |
body { | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
} | |
canvas { | |
position: absolute; | |
left: 0px; | |
top: 0px; | |
width: 100%; | |
height: 100%; | |
} | |
</style> | |
<canvas id="c" width="400" height="400"></canvas> | |
<script> | |
'use strict'; | |
let canvas = document.getElementById('c'); | |
let ctx = canvas.getContext('2d'); | |
wasmImports = { | |
width() { return canvas.width }, | |
height() { return canvas.height }, | |
fillStyle(s) { ctx.fillStyle = emModule.UTF8ToString(s) }, | |
strokeStyle(s) { ctx.strokeStyle = emModule.UTF8ToString(s) }, | |
clearRect: ctx.clearRect.bind(ctx), | |
fillRect: ctx.fillRect.bind(ctx), | |
beginPath: ctx.beginPath.bind(ctx), | |
stroke: ctx.stroke.bind(ctx), | |
moveTo: ctx.moveTo.bind(ctx), | |
lineTo: ctx.lineTo.bind(ctx), | |
} | |
function update() { | |
let bounds = canvas.getBoundingClientRect(); | |
canvas.width = bounds.width * devicePixelRatio; | |
canvas.height = bounds.height * devicePixelRatio; | |
if (wasmExports.drawFrame) | |
wasmExports.drawFrame(); | |
requestAnimationFrame(update); | |
} | |
update(); | |
canvas.addEventListener("mousemove", e => { | |
if (wasmExports.mousemove) | |
wasmExports.mousemove( | |
e.clientX * devicePixelRatio, | |
e.clientY * devicePixelRatio); | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment