@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
96 lines (67 loc) • 2.94 kB
JavaScript
import { v3_grid_apply_diffusion } from "./solver/v3_grid_apply_diffusion.js";
import { v3_grid_apply_advection_forward } from "./solver/v3_grid_apply_advection_forward.js";
export class FluidSimulator {
/**
*
* @type {ArrayBuffer|null}
*/
buffer = null;
ensure_buffer(size) {
if (this.buffer === null || this.buffer.byteLength < size) {
this.buffer = new ArrayBuffer(size);
}
}
/**
*
* @param {FluidField} field
* @param {number} time_delta_in_seconds
*/
step(field, time_delta_in_seconds) {
// create buffer big enough to store all attribute twice
const resolution = field.resolution;
const attribute_cell_count = resolution[0] * resolution[1] * resolution[2];
const attribute_byte_size = attribute_cell_count * 4;
const field_byte_size = field.getAttributeCount() * attribute_byte_size;
this.ensure_buffer(field_byte_size * 2);
const sim_buffer = this.buffer;
// remember current data
new Uint8Array(sim_buffer, 0, field_byte_size).set(new Uint8Array(field.buffer, 0, field_byte_size))
let ping_pong_index = 0;
const DIFFUSE_STEPS = 2;
for (let i = 0; i < 3; i++) {
// perform diffusion
let source = new Float32Array(sim_buffer, attribute_byte_size * i, attribute_cell_count)
let target = new Float32Array(sim_buffer, field_byte_size + attribute_byte_size * i, attribute_cell_count);
const ping_pong = [source, target];
ping_pong_index = 0;
for (let j = 0; j < DIFFUSE_STEPS; j++) {
source = ping_pong[ping_pong_index % 2];
target = ping_pong[(ping_pong_index + 1) % 2];
v3_grid_apply_diffusion(target, source, resolution);
ping_pong_index++;
}
}
ping_pong_index = DIFFUSE_STEPS;
const inputs = [];
const outputs = [];
for (let i = 0; i < 3; i++) {
const source = ping_pong_index % 2
const target = (ping_pong_index + 1) % 2
inputs[i] = new Float32Array(
sim_buffer, source * field_byte_size + attribute_byte_size * i, attribute_cell_count
);
outputs[i] = new Float32Array(
sim_buffer, target * field_byte_size + attribute_byte_size * i, attribute_cell_count
);
}
ping_pong_index++;
// advection
v3_grid_apply_advection_forward(outputs, inputs, resolution, time_delta_in_seconds);
if (ping_pong_index % 2 !== 0) {
// data is not at source
field.attachBuffer(sim_buffer, field_byte_size);
} else {
field.attachBuffer(sim_buffer, 0);
}
}
}