UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

212 lines (140 loc) 6.02 kB
import { Color } from "../../../src/core/color/Color.js"; import Vector1 from "../../../src/core/geom/Vector1.js"; import Vector2 from "../../../src/core/geom/Vector2.js"; import { max2 } from "../../../src/core/math/max2.js"; import ObservedString from "../../../src/core/model/ObservedString.js"; import { GameAssetType } from "../../../src/engine/asset/GameAssetType.js"; import { pick } from "../../../src/engine/ecs/grid/pick.js"; import { obtainTerrain } from "../../../src/engine/ecs/terrain/util/obtainTerrain.js"; import { Sampler2D } from "../../../src/engine/graphics/texture/sampler/Sampler2D.js"; import sampler2d_to_html_canvas from "../../../src/engine/graphics/texture/sampler/sampler2d_to_html_canvas.js"; import Tool from "../engine/Tool.js"; export class TerrainPaintTool extends Tool { constructor() { super(); this.name = 'paint-terrain'; const marker = Sampler2D.uint8(4, 1, 1); marker.data.fill(255); this.settings.markerColor = new Color(0, 1, 0.8); this.settings.markerOpacity = new Vector1(1); this.settings.marker = marker; this.settings.brushSize = 5; this.settings.brushStrength = 1; this.settings.brushURL = new ObservedString("data/textures/particle/UETools/x64/Circle_04.png"); this.__brushPosition = new Vector2(); this.__brushImage = document.createElement('canvas'); this.__paint_debt = 0; this.__paint_pending = false; } /** * * @param {number} timeDelta */ async paint(timeDelta) { } /** * * @param {number} timeDelta */ update(timeDelta) { this.updateBrushPosition(); this.updateOverlay(); if (this.isRunning()) { this.__paint_debt += timeDelta; if (this.__paint_pending) { return; } this.__paint_pending = true; const paint_promise = this.paint(timeDelta); this.__paint_debt = 0; paint_promise.finally(() => { this.__paint_pending = false; }); } } updateBrushImage() { /** * * @type {Sampler2D} */ const marker = this.settings.marker; const temp = new Sampler2D(new Uint8ClampedArray(marker.data), marker.itemSize, marker.width, marker.height); const markerColor = this.settings.markerColor; const markerAlpha = this.settings.markerOpacity.getValue(); const brushData = temp.data; //apply tint for (let y = 0; y < temp.height; y++) { const lineAddress = y * temp.itemSize * temp.width; for (let x = 0; x < temp.width; x++) { const address = lineAddress + x * temp.itemSize; brushData[address] = brushData[address] * markerColor.r; brushData[address + 1] = brushData[address + 1] * markerColor.g; brushData[address + 2] = brushData[address + 2] * markerColor.b; brushData[address + 3] = brushData[address + 3] * markerAlpha; } } const brushImage = this.__brushImage; sampler2d_to_html_canvas(temp, 1, 0, brushImage); } updateBrushPosition() { const p = new Vector2(0, 0); const engine = this.engine; engine.gameView.positionGlobalToLocal(engine.devices.pointer.position, p); pick(p.x, p.y, engine.graphics, this.terrain, (gridPosition) => { this.__brushPosition.set(gridPosition.x, gridPosition.y); }); } updateOverlay() { const terrain = this.terrain; const overlay = terrain.overlay; overlay.clear(); const dx = overlay.size.x / terrain.size.x; const dy = overlay.size.y / terrain.size.y; const overlayPositionX = this.__brushPosition.x * dx; const overlayPositionY = this.__brushPosition.y * dy; const brushSize = this.settings.brushSize; const brushRadius = brushSize / 2; const brushSizeX = brushRadius * dx; const brushSizeY = brushRadius * dy; overlay.paintImage(this.__brushImage, overlayPositionX - brushSizeX, overlayPositionY - brushSizeY, brushSize * dx, brushSize * dy); } /** * * @param {Vector3} delta * @private */ __handleMouseWheel(delta) { const settings = this.settings; const brushSize = settings.brushSize; settings.brushSize = max2(1, brushSize + delta.y); // this.updateBrushImage(); this.updateOverlay(); } initialize() { super.initialize(); const engine = this.engine; const editor = this.editor; this.__paint_debt = 0; this.terrain = obtainTerrain(engine.entityManager.dataset, (t, entity) => { this.terrainEntity = entity; }); const overlay = this.terrain.overlay; overlay.push(); overlay.size.set(this.terrain.size.x * 16, this.terrain.size.y * 16); overlay.borderWidth.set(0); overlay.tileImage.set("data/textures/utility/white_pixel.png"); engine.assetManager.promise('data/textures/particle/UETools/x64/Circle_04.png', GameAssetType.Image) .then(asset => { const image = asset.create(); this.settings.marker = new Sampler2D(image.data, 4, image.width, image.height); this.updateBrushImage(); }); this.updateBrushImage(); engine.devices.pointer.on.wheel.add(this.__handleMouseWheel, this); } finalize() { super.finalize(); this.terrain.overlay.pop(); engine.devices.pointer.on.wheel.remove(this.__handleMouseWheel, this); } }