UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

183 lines (136 loc) 5.99 kB
import { Action } from "../../../src/core/process/undo/Action.js"; import { assert } from "../../../src/core/assert.js"; import { texture_array_2d_copy } from "../../../src/engine/graphics/texture/texture_array_2d_copy.js"; import { clamp } from "../../../src/core/math/clamp.js"; export class ModifyPatchTextureArray2DAction extends Action { /** * * @param {number[]|Uint8Array|Uint32Array|Float32Array} data * @param {number[]} data_resolution * @param {number[]} bounds */ constructor(data, data_resolution, bounds) { super(); assert.isArrayLike(data, 'data'); this.__data = data; this.__data_resolution = data_resolution; this.__bounds = bounds; const width = this.__bounds[2] - this.__bounds[0]; const height = this.__bounds[3] - this.__bounds[1]; const depth = data_resolution[2]; const CTOR = Object.getPrototypeOf(data).constructor; /** * @type {ArrayLike<number>} * @private */ this.__patch_new = new CTOR(height * width * depth); /** * @type {ArrayLike<number>} * @private */ this.__patch_old = new CTOR(height * width * depth); } /** * * @param {number} center_x * @param {number} center_y * @param {Sampler2D} stamp * @param {number} layer_index * @param {number} weight * @param {number} clamp_min * @param {number} clamp_max */ applyWeightStampToLayer( center_x, center_y, stamp, layer_index, weight, clamp_min = Number.NEGATIVE_INFINITY, clamp_max = Number.POSITIVE_INFINITY ) { const bounds_x0 = this.__bounds[0]; const bounds_y0 = this.__bounds[1]; const bounds_x1 = this.__bounds[2]; const bounds_y1 = this.__bounds[3]; const width = bounds_x1 - bounds_x0; const height = bounds_y1 - bounds_y0; const center_offset_x = (bounds_x0 + bounds_x1) * 0.5 - center_x; const center_offset_y = (bounds_y0 + bounds_y1) * 0.5 - center_y; const source_data = this.__data; const source_width = this.__data_resolution[0]; const source_height = this.__data_resolution[1]; const depth = this.__data_resolution[2]; for (let y = 0; y < height; y++) { const marker_v = (y + center_offset_y) / (height - 1); for (let x = 0; x < width; x++) { const marker_u = (x + center_offset_x) / (width - 1); const stamp_value = stamp.sampleChannelBilinearUV(marker_u, marker_v, 3); if (Number.isNaN(stamp_value)) { continue; } const weighed_stamp_value = stamp_value * weight; const source_x = (x + bounds_x0); const source_y = (y + bounds_y0); const weight_reciprocal = weighed_stamp_value / (depth - 1); for (let i = 0; i < depth; i++) { const source_layer_address = source_width * source_height * i; const source_texel_address = source_layer_address + source_y * source_width + source_x; const destination_texel_address = width * height * i + y * width + x; const source_value = source_data[source_texel_address]; let destination_value; if (i === layer_index) { // the channel that we are stamping destination_value = source_value + weighed_stamp_value; } else { destination_value = source_value - weight_reciprocal; } this.__patch_new[destination_texel_address] = clamp(destination_value, clamp_min, clamp_max); } } } } get patch_data() { return this.__patch_new; } computeByteSize() { // TODO take size of array elements into account return this.__patch_new.length + this.__patch_old.length + 280; } async apply(context) { const data = this.__data; const depth = this.__data_resolution[2]; const bounds_x0 = this.__bounds[0]; const bounds_y0 = this.__bounds[1]; const bounds_x1 = this.__bounds[2]; const bounds_y1 = this.__bounds[3]; const width = bounds_x1 - bounds_x0; const height = bounds_y1 - bounds_y0; const source_resolution_x = this.__data_resolution[0]; const source_resolution_y = this.__data_resolution[1]; // store old data texture_array_2d_copy( data, bounds_x0, bounds_y0, source_resolution_x, source_resolution_y, this.__patch_old, 0, 0, width, height, width, height, depth ); texture_array_2d_copy( this.__patch_new, 0, 0, width, height, data, bounds_x0, bounds_y0, source_resolution_x, source_resolution_y, width, height, depth ); } async revert(context) { const data = this.__data; const depth = this.__data_resolution[2]; const bounds_x0 = this.__bounds[0]; const bounds_y0 = this.__bounds[1]; const bounds_x1 = this.__bounds[2]; const bounds_y1 = this.__bounds[3]; const width = bounds_x1 - bounds_x0; const height = bounds_y1 - bounds_y0; const source_resolution_x = this.__data_resolution[0]; const source_resolution_y = this.__data_resolution[1]; texture_array_2d_copy( this.__patch_old, 0, 0, width, height, data, bounds_x0, bounds_y0, source_resolution_x, source_resolution_y, width, height, depth ); } }