a whole load of work in progress
This commit is contained in:
parent
caec0b8ac9
commit
26ba098183
63 changed files with 3234 additions and 321 deletions
154
static/canvas-renderer.js
Normal file
154
static/canvas-renderer.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
import { listen } from "./framework.js";
|
||||
import { Viewport } from "./viewport.js";
|
||||
|
||||
class CanvasRenderer extends HTMLElement {
|
||||
viewport = new Viewport();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.canvas = this.appendChild(document.createElement("canvas"));
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
|
||||
let resizeObserver = new ResizeObserver(() => this.#updateSize());
|
||||
resizeObserver.observe(this);
|
||||
|
||||
this.#cursorReportingBehaviour();
|
||||
this.#draggingBehaviour();
|
||||
this.#zoomingBehaviour();
|
||||
this.#paintingBehaviour();
|
||||
}
|
||||
|
||||
initialize(wall, painter) {
|
||||
this.wall = wall;
|
||||
this.painter = painter;
|
||||
requestAnimationFrame(() => this.#render());
|
||||
}
|
||||
|
||||
#updateSize() {
|
||||
this.canvas.width = this.clientWidth;
|
||||
this.canvas.height = this.clientHeight;
|
||||
// Rerender immediately after the canvas is resized, as its contents have now been invalidated.
|
||||
this.#render();
|
||||
}
|
||||
|
||||
#render() {
|
||||
// NOTE: We should probably render on-demand only when it's needed.
|
||||
requestAnimationFrame(() => this.#render());
|
||||
|
||||
this.#renderWall();
|
||||
}
|
||||
|
||||
#renderWall() {
|
||||
if (this.wall == null) {
|
||||
console.debug("wall is not available, skipping rendering");
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctx.fillStyle = "white";
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.translate(Math.floor(this.clientWidth / 2), Math.floor(this.clientHeight / 2));
|
||||
this.ctx.scale(this.viewport.zoom, this.viewport.zoom);
|
||||
this.ctx.translate(-this.viewport.panX, -this.viewport.panY);
|
||||
|
||||
let visibleRect = this.viewport.getVisibleRect({
|
||||
width: this.clientWidth,
|
||||
height: this.clientHeight,
|
||||
});
|
||||
let left = Math.floor(visibleRect.x / this.wall.chunkSize);
|
||||
let top = Math.floor(visibleRect.y / this.wall.chunkSize);
|
||||
let right = Math.ceil((visibleRect.x + visibleRect.width) / this.wall.chunkSize);
|
||||
let bottom = Math.ceil((visibleRect.y + visibleRect.height) / this.wall.chunkSize);
|
||||
for (let chunkY = top; chunkY < bottom; ++chunkY) {
|
||||
for (let chunkX = left; chunkX < right; ++chunkX) {
|
||||
let x = chunkX * this.wall.chunkSize;
|
||||
let y = chunkY * this.wall.chunkSize;
|
||||
|
||||
let chunk = this.wall.getChunk(chunkX, chunkY);
|
||||
if (chunk != null) {
|
||||
this.ctx.drawImage(chunk.canvas, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.ctx.restore();
|
||||
|
||||
if (this.ctx.brushPreview != null) {
|
||||
this.ctx.drawImage(this.ctx.brushPreview, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async #cursorReportingBehaviour() {
|
||||
while (true) {
|
||||
let event = await listen([this, "mousemove"]);
|
||||
let [x, y] = this.viewport.toViewportSpace(
|
||||
event.clientX - this.clientLeft,
|
||||
event.offsetY - this.clientTop,
|
||||
{
|
||||
width: this.clientWidth,
|
||||
height: this.clientHeight,
|
||||
},
|
||||
);
|
||||
this.dispatchEvent(Object.assign(new Event(".cursor"), { x, y }));
|
||||
}
|
||||
}
|
||||
|
||||
async #draggingBehaviour() {
|
||||
while (true) {
|
||||
let mouseDown = await listen([this, "mousedown"]);
|
||||
if (mouseDown.button == 1) {
|
||||
mouseDown.preventDefault();
|
||||
while (true) {
|
||||
let event = await listen([window, "mousemove"], [window, "mouseup"]);
|
||||
if (event.type == "mousemove") {
|
||||
this.viewport.panAround(event.movementX, event.movementY);
|
||||
this.dispatchEvent(new Event(".viewportUpdate"));
|
||||
} else if (event.type == "mouseup") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #zoomingBehaviour() {
|
||||
while (true) {
|
||||
let event = await listen([this, "wheel"]);
|
||||
|
||||
// TODO: Touchpad zoom
|
||||
this.viewport.zoomIn(event.deltaY > 0 ? -1 : 1);
|
||||
this.dispatchEvent(new Event(".viewportUpdate"));
|
||||
}
|
||||
}
|
||||
|
||||
async #paintingBehaviour() {
|
||||
const paint = (x, y) => {
|
||||
let [wallX, wallY] = this.viewport.toViewportSpace(x, y, {
|
||||
width: this.clientWidth,
|
||||
height: this.clientHeight,
|
||||
});
|
||||
this.dispatchEvent(Object.assign(new Event(".paint"), { x: wallX, y: wallY }));
|
||||
};
|
||||
|
||||
while (true) {
|
||||
let mouseDown = await listen([this, "mousedown"]);
|
||||
if (mouseDown.button == 0) {
|
||||
paint(mouseDown.offsetX, mouseDown.offsetY);
|
||||
while (true) {
|
||||
let event = await listen([window, "mousemove"], [window, "mouseup"]);
|
||||
if (event.type == "mousemove") {
|
||||
paint(event.clientX - this.clientLeft, event.offsetY - this.clientTop);
|
||||
} else if (event.type == "mouseup") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("rkgk-canvas-renderer", CanvasRenderer);
|
Loading…
Add table
Add a link
Reference in a new issue