From 9ccb4a7bc728fd0e85c04fddb802fde02b73cfe2 Mon Sep 17 00:00:00 2001 From: sanine Date: Sun, 29 May 2022 20:44:11 -0500 Subject: add basic color brushing demo --- src/Canvas.js | 4 ++ src/Terrain.js | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.js | 30 ++++++++----- src/modules/Terrain.js | 111 ------------------------------------------------- 4 files changed, 135 insertions(+), 121 deletions(-) create mode 100644 src/Terrain.js delete mode 100644 src/modules/Terrain.js diff --git a/src/Canvas.js b/src/Canvas.js index 7f6404b..6dff7bd 100644 --- a/src/Canvas.js +++ b/src/Canvas.js @@ -22,6 +22,8 @@ class Canvas { /* callbacks */ this.onDraw = null; this.onMouseMove = null; + this.onMouseDown = null; + this.onMouseUp = null; /* register event listeners */ @@ -53,9 +55,11 @@ class Canvas { this.element.addEventListener('mousedown', e => { e.preventDefault(); if (e.button === 1) this.panning = true; + if (this.onMouseDown) this.onMouseDown(e); }); this.element.addEventListener('mouseup', e => { if (e.button === 1) this.panning = false; + if (this.onMouseUp) this.onMouseUp(e); }); /* mouse leave */ diff --git a/src/Terrain.js b/src/Terrain.js new file mode 100644 index 0000000..c287063 --- /dev/null +++ b/src/Terrain.js @@ -0,0 +1,111 @@ +'use strict'; + +import Voronoi from './3rdparty/rhill-voronoi-core.js'; + +import { useAverage } from './modules/Util.js'; +import { AABB, QuadTree } from './modules/Geometry.js'; + + +/* from here on up, we always assume that points live in the range [(0,0), (1,1)) */ + +function lloydRelax(point_set, density) { + /* setup quadtree and averages */ + let tree = new QuadTree(1,1); + let averages = {}; + for (let i=0; i ({x: Math.random(), y: Math.random()}); + + this.min_height = 0; + this.max_height = 0; + + let seed_points = []; + for (let i=0; i (a.x - b.x)**2 + (a.y - b.y)**2; + + const sigma = radius/3; + const beta = 1/(2*sigma*sigma); + const center = { x, y }; + const power = pt => Math.exp(-beta * dist2(pt, center)); + + for (let pt of points) f(pt, strength * power(pt)); + } + + + renderGrid(ct) { + ct.save(); + ct.lineWidth = 0.001; + for (let edge of this.graph.edges) { + ct.fillStyle = `hsl(${edge.va.hue}, 100%, 50%)`; + ct.beginPath(); + ct.arc(edge.va.x, edge.va.y, 0.005, 0, 2*Math.PI); + ct.closePath(); + ct.fill(); + + ct.beginPath(); + ct.moveTo(edge.va.x, edge.va.y); + ct.lineTo(edge.vb.x, edge.vb.y); + ct.closePath(); + ct.stroke(); + } + ct.restore(); + } +} + +export { lloydRelax }; +export default Terrain; diff --git a/src/main.js b/src/main.js index d618d05..4527a90 100644 --- a/src/main.js +++ b/src/main.js @@ -1,27 +1,37 @@ +import Terrain from './Terrain.js'; import Canvas from './Canvas.js'; const $ = id => document.getElementById(id) window.onload = () => { const canvas = new Canvas('root'); + const terrain = new Terrain(); + + const BRUSH_RADIUS = 80; + let brushing = false; + canvas.onMouseDown = e => { + if (e.button == 0) brushing = true; + }; + canvas.onMouseUp = e => { + if (e.button == 0) brushing = false; + }; const pos = canvas.mouse.drawingPos; - canvas.onMouseMove = () => canvas.draw(); + canvas.onMouseMove = () => { + if (brushing) + terrain.applyBrush(pos.x, pos.y, (pt, strength) => { + pt.hue += 10 * strength; + }, 1, canvas.pixelsToUnits(BRUSH_RADIUS)); + canvas.draw(); + }; canvas.onDraw = ct => { - ct.fillStyle = '#f00'; - ct.fillRect(0, 0, 1/3, 1/3); - ct.fillStyle = '#0f0'; - ct.fillRect(2/3, 0, 1/3, 1/3); - ct.fillStyle = '#ff0'; - ct.fillRect(0, 2/3, 1/3, 1/3); - ct.fillStyle = '#00f'; - ct.fillRect(2/3, 2/3, 1/3, 1/3); + terrain.renderGrid(ct); ct.strokeStyle = '#fff'; ct.lineWidth = canvas.pixelsToUnits(1); ct.beginPath(); - ct.arc(pos.x, pos.y, canvas.pixelsToUnits(30), 0, 2*Math.PI); + ct.arc(pos.x, pos.y, canvas.pixelsToUnits(BRUSH_RADIUS), 0, 2*Math.PI); ct.closePath(); ct.stroke(); }; diff --git a/src/modules/Terrain.js b/src/modules/Terrain.js deleted file mode 100644 index 21908ac..0000000 --- a/src/modules/Terrain.js +++ /dev/null @@ -1,111 +0,0 @@ -'use strict'; - -import Voronoi from './3rdparty/rhill-voronoi-core.js'; - -import { useAverage } from './Util.js'; -import { AABB, QuadTree } from './Geometry.js'; - - -/* from here on up, we always assume that points live in the range [(0,0), (1,1)) */ - -function lloydRelax(point_set, density) { - /* setup quadtree and averages */ - let tree = new QuadTree(1,1); - let averages = {}; - for (let i=0; i ({x: Math.random(), y: Math.random()}); - - this.min_height = 0; - this.max_height = 0; - - let seed_points = []; - for (let i=0; i (a.x - b.x)**2 + (a.y - b.y)**2; - - const sigma = radius/3; - const beta = 1/(2*sigma*sigma); - const center = { x, y }; - const power = pt => Math.exp(-beta * dist2(pt, center)); - - for (let pt of points) f(pt, strength * power(pt)); - } - - - renderGrid(ct) { - ct.save(); - ct.lineWidth = 0.001; - for (let edge of this.graph.edges) { - ct.fillStyle = `hsl(${edge.va.height}, 100%, 50%)`; - ct.beginPath(); - ct.arc(edge.va.x, edge.va.y, 0.005, 0, 2*Math.PI); - ct.closePath(); - ct.fill(); - - ct.beginPath(); - ct.moveTo(edge.va.x, edge.va.y); - ct.lineTo(edge.vb.x, edge.vb.y); - ct.closePath(); - ct.stroke(); - } - ct.restore(); - } -} - -export { lloydRelax }; -export default Terrain; -- cgit v1.2.1