@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
183 lines (136 loc) • 5.99 kB
JavaScript
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
);
}
}