diff --git a/src/js/stendhal/SingletonRepo.ts b/src/js/stendhal/SingletonRepo.ts index 441afdd50b3..e10cc04f386 100644 --- a/src/js/stendhal/SingletonRepo.ts +++ b/src/js/stendhal/SingletonRepo.ts @@ -16,6 +16,7 @@ import { SlashActionRepo } from "./SlashActionRepo"; import { Zone } from "./entity/Zone"; import { ConfigManager } from "./util/ConfigManager"; +import { DrawingStage } from "./util/DrawingStage"; import { FacingHandler } from "./util/FacingHandler"; import { KeyHandler } from "./util/KeyHandler"; import { SessionManager } from "./util/SessionManager"; @@ -74,6 +75,10 @@ export class SingletonRepo { return DirectionPad.get(); } + static getDrawingStage(): DrawingStage { + return DrawingStage.get(); + } + static getEmojiStore(): EmojiStore { return EmojiStore.get(); } diff --git a/src/js/stendhal/util/DrawingStage.ts b/src/js/stendhal/util/DrawingStage.ts new file mode 100644 index 00000000000..90a4ab4040b --- /dev/null +++ b/src/js/stendhal/util/DrawingStage.ts @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright © 2024 - Faiumoni e. V. * + *************************************************************************** + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + ***************************************************************************/ + +import { Color } from "./Color"; + + +export class DrawingStage { + + private canvas: HTMLCanvasElement; + private ctx: any; + private gl: boolean; + + private static instance: DrawingStage; + + + static get(): DrawingStage { + if (!DrawingStage.instance) { + DrawingStage.instance = new DrawingStage(); + } + return DrawingStage.instance; + } + + private constructor() { + this.canvas = document.getElementById("drawing-stage")! as HTMLCanvasElement; + this.gl = false; + this.ctx = this.canvas.getContext("2d")!; + /* + this.ctx = this.canvas.getContext("webgl"); + if (!this.ctx) { + console.warn("WebGL not supported, falling back to standard 2d context"); + this.gl = false; + this.ctx = this.canvas.getContext("2d")!; + } else { + // DEBUG: + console.log("Using WebGL"); + + this.gl = true; + } + */ + this.reset(); + } + + setSize(width: number, height: number) { + this.canvas.width = width; + this.canvas.height = height; + } + + reset() { + if (this.gl) { + // TODO: + } else { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } + this.setSize(0, 0); + } + + createSpeechBubble(width: number, height: number): HTMLImageElement { + this.reset(); + + this.gl ? this.drawWebGLSpeechBubble(width, height) : this.draw2DSpeechBubble(width, height); + + const img = new Image(); + img.src = this.canvas.toDataURL("image/png"); + return img; + } + + private draw2DSpeechBubble(width: number, height: number) { + this.ctx.save(); + + // DEBUG: + console.log("width: " + width + "\nheight: " + height); + + const arc = 3; + const lineWidth = 1; // width of line on single edge + this.ctx.lineWidth = lineWidth * 2; + const tail = 8; + const x = tail + this.ctx.lineWidth, y = lineWidth; + width += x; // compensate for tail + // adjust canvas dimensions to compensate for stroke & tail + const canvasWidth = width + (lineWidth * 2) + tail + lineWidth; + const canvasHeight = height + (lineWidth * 2); + this.setSize(canvasWidth, canvasHeight); + + // DEBUG: + this.ctx.fillStyle = Color.GREEN; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // DEBUG: + console.log("width: " + width + "\nheight: " + height + "\nline width: " + lineWidth + "\nctx line width: " + this.ctx.lineWidth); + + const fontsize = 14; + //~ const lheight = fontsize + 6; + this.ctx.font = fontsize + "px Arial"; + this.ctx.fillStyle = Color.WHITE; + this.ctx.strokeStyle = Color.BLACK; + + this.ctx.beginPath(); + this.ctx.moveTo(x + arc, y); + this.ctx.lineTo(x + width - arc, y); + this.ctx.quadraticCurveTo(x + width, y, x + width, y + arc); + this.ctx.lineTo(x + width, y + height - arc); + this.ctx.quadraticCurveTo(x + width, y + height, x + width - arc, y + height); + this.ctx.lineTo(x + arc, y + height); + this.ctx.quadraticCurveTo(x, y + height, x, y + height - arc); + this.ctx.lineTo(x, y + 8); + + // tail + this.ctx.lineTo(x - 8, y + 11); + this.ctx.lineTo(x, y + 3); + + this.ctx.lineTo(x, y + arc); + this.ctx.quadraticCurveTo(x, y, x + arc, y); + this.ctx.stroke(); + this.ctx.closePath(); + this.ctx.fill(); + + this.ctx.restore(); + } + + private drawWebGLSpeechBubble(width: number, height: number) { + // DEBUG: + console.log("drawing WebGL"); + + // TODO: + } +}