import * as Three from 'three'; import { RESOLUTION_X, RESOLUTION_Y } from '../consts'; import Stats from 'stats.js'; import { Point } from '../physics/common'; import Selector from './selector.class'; import Asset from '../assets/asset.class'; export enum CursorType { default = "default", pointer = "pointer", move = "move", updown = "ns-resize", leftright = "ew-resize", nesw = "nesw-resize", nwse = "nwse-resize", //rotate = "url(public/rotate.png)" rotate = "crosshair" //tmp } export default class Renderer { static scene: Three.Scene; static aspect: number; static renderer: Three.WebGLRenderer; static camera: Three.OrthographicCamera; static #zoom: number; static #pos: Point = { x: 0, y: 0 }; static #stats: Stats; static init(): Boolean { try { this.renderer = new Three.WebGLRenderer({ antialias: true }); this.renderer.setPixelRatio( window.devicePixelRatio ); document.body.appendChild(this.renderer.domElement); this.scene = new Three.Scene(); this.camera = new Three.OrthographicCamera(); this.camera.position.z = 500; this.#zoom = 5; const stats = this.#stats = new Stats(); stats.showPanel(0); document.body.appendChild(stats.dom); this.#resize(); window.addEventListener("resize", this.#resize.bind(this)); return true; } catch(e) { console.error(e); return false; } } static get canvas(): HTMLCanvasElement { return this.renderer.domElement; } static get zoom(): number { return this.#zoom; } static set zoom(v: number) { this.#zoom = v; this.#resize(); } static move(x: number, y: number): void { this.#pos.x += x; this.#pos.y += y; this.camera.position.x += x; this.camera.position.y += y; } static screenSpaceToCameraSpace(x: number, y: number, omit: boolean = false): Point { return { x: ((x / window.innerWidth - 0.5) * RESOLUTION_X * this.aspect) / this.#zoom + (omit ? 0 : this.#pos.x), y: (- (y / window.innerHeight - 0.5) * RESOLUTION_Y) / this.zoom + (omit ? 0 : this.#pos.y) }; } static #resize(): void { const aspect = this.aspect = window.innerWidth / window.innerHeight; this.renderer.setSize( window.innerWidth, window.innerHeight ); this.camera.left = RESOLUTION_X * aspect / - 2 / this.#zoom; this.camera.right = RESOLUTION_X * aspect / 2 / this.#zoom; this.camera.top = RESOLUTION_Y / 2 / this.#zoom; this.camera.bottom = RESOLUTION_Y / - 2 / this.#zoom; this.camera.updateProjectionMatrix(); this.render(); } static render(delta?: number): void { this.#stats.begin(); Selector.update(); this.renderer.render(this.scene, this.camera); Asset.quadtree.cleanup(); this.#stats.end(); } static startRendering(): void { this.renderer.setAnimationLoop(Renderer.render.bind(Renderer)); } static stopRendering(): void { this.renderer.setAnimationLoop(null); } static cursor(type?: CursorType): void { Renderer.canvas.style.setProperty("cursor", type ?? CursorType.default); } }