@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
199 lines (145 loc) • 4.98 kB
JavaScript
import { obtainTerrain } from "../../../src/engine/ecs/terrain/util/obtainTerrain.js";
import { sampler2d_to_data_url } from "../../../src/engine/graphics/texture/sampler/sampler2d_to_data_url.js";
import { ActionUpdateTexture } from "../../actions/concrete/ActionUpdateTexture.js";
import { ArrayCopyAction } from "../../actions/concrete/ArrayCopyAction.js";
import { ModifyPatchTextureArray2DAction } from "../../actions/concrete/ModifyPatchTextureArray2DAction.js";
import { TerrainPaintTool } from "./TerrainPaintTool.js";
export class TerrainTexturePaintTool extends TerrainPaintTool {
constructor() {
super();
this.name = "texture-paint-terrain";
/**
*
* @type {number}
*/
this.settings.splatIndex = 0;
/**
*
* @type {Float32Array}
* @private
*/
this.__splatMapScratch = new Float32Array(0);
this.__iconLayer = null;
}
updateIcon(editor) {
/**
*
* @type {Terrain}
*/
const terrain = obtainTerrain(editor.engine.entityManager.dataset);
if (terrain === null) {
// no terrain
return;
}
/**
*
* @type {TerrainLayer}
*/
const layer = terrain.layers.get(this.settings.splatIndex);
if (layer === this.__iconLayer) {
return;
}
this.__iconLayer = layer;
this.buildIcon(terrain);
}
/**
*
* @param {Terrain} terrain
*/
buildIcon(terrain) {
/**
*
* @type {TerrainLayer}
*/
const layer = terrain.layers.get(this.settings.splatIndex);
if (layer === undefined) {
return;
}
let url = layer.textureDiffuseURL;
if (url === null) {
// no URL, try to sample texture directly
url = sampler2d_to_data_url(layer.diffuse);
}
this.icon.set(url);
}
initialize() {
super.initialize();
}
finalize() {
super.finalize();
}
async paint(timeDelta) {
const power = this.settings.brushStrength * timeDelta;
/**
*
* @type {Terrain}
*/
const terrain = this.terrain;
const brushPosition = this.__brushPosition;
const brushSize = this.settings.brushSize;
const terrainSize = terrain.size;
const terrainHeight = terrainSize.y;
const terrainWidth = terrainSize.x;
const uv_x = brushPosition.x / terrainWidth;
const uv_y = brushPosition.y / terrainHeight;
const uv_w = brushSize / terrainWidth;
const uv_h = brushSize / terrainHeight;
const uv_x0 = uv_x - uv_w / 2;
const uv_x1 = uv_x + uv_w / 2;
const uv_y0 = uv_y - uv_h / 2;
const uv_y1 = uv_y + uv_h / 2;
const marker = this.settings.marker;
const direction = this.modifiers.shift ? -1 : 1;
const speed = power * direction;
/**
*
* @type {Float32Array}
*/
const weightData = this.__splatMapScratch;
/**
*
* @type {SplatMapping}
*/
const splat = terrain.splat;
const splatWidth = splat.size.x;
const splatHeight = splat.size.y;
const h_x0 = uv_x0 * splatWidth;
const h_x1 = uv_x1 * splatWidth;
const h_y0 = uv_y0 * splatHeight;
const h_y1 = uv_y1 * splatHeight;
const x0 = Math.ceil(h_x0);
const x1 = Math.floor(h_x1);
const y0 = Math.ceil(h_y0);
const y1 = Math.floor(h_y1);
const splatIndex = this.settings.splatIndex;
//create action
// const m_action = new ModifyPatchSampler2DAction(splat_layer_sampler, [x0, y0, x1, y1]);
const m_action = new ModifyPatchTextureArray2DAction(weightData, [splat.size.x, splat.size.y, splat.depth], [x0, y0, x1, y1]);
m_action.applyWeightStampToLayer(
uv_x * splat.size.x, uv_y * splat.size.y,
marker, splatIndex, speed,
0, 255
);
await this.editor.actions.doMany([
m_action,
new ArrayCopyAction(weightData, splat.weightData),
new ActionUpdateTexture(splat.weightTexture)
]);
}
start() {
super.start();
/**
*
* @type {Terrain}
*/
const terrain = this.terrain;
const splat = terrain.splat;
const weightData = splat.weightData;
/**
*
* @type {Float32Array}
*/
this.__splatMapScratch = new Float32Array(weightData);
this.editor.actions.mark('paint terrain texture');
}
}