UNPKG

@awayjs/stage

Version:
192 lines (191 loc) 7.33 kB
/** * Implement Turbulence for noise * Port from Ruffle/Rust * @see https://github.com/ruffle-rs/ruffle/blob/04d80e5e4e5a3023117e0410378fc623a8bfbbf5/core/src/bitmap/turbulence.rs */ var RAND_M = 2147483647; // 2**31 - 1 var RAND_A = 16807; // 7**5; primitive root of m var RAND_Q = 127773; // m / a var RAND_R = 2836; // m % a var B_SIZE = 0x100; var BM = 0xff; var PERLIN_N = 0x1000; var SeededRandom = /** @class */ (function () { function SeededRandom(seed) { this.seed = 0; if (seed <= 0) { seed = -(seed % (RAND_M - 1)) + 1; } if (seed > RAND_M - 1) { seed = RAND_M - 1; } this.seed = seed; } SeededRandom.prototype.next = function () { var result = RAND_A * (this.seed % RAND_Q) - RAND_R * (this.seed / RAND_Q | 0); if (result <= 0) { result += RAND_M; } return result; }; return SeededRandom; }()); function curve(t) { return t * t * (3. - 2. * t); } function lerp(t, a, b) { return a + t * (b - a); } var Turbulence = /** @class */ (function () { function Turbulence(gradient, lattice_selector) { this.gradient = gradient; this.lattice_selector = lattice_selector; } Turbulence.prototype.noise2 = function (color_channel, vec, stitch_info) { var t = vec[0] + PERLIN_N; var bx0 = t | 0; var bx1 = bx0 + 1; var rx0 = t - (t | 0); var rx1 = rx0 - 1.0; var t2 = vec[1] + PERLIN_N; var by0 = t2 | 0; var by1 = by0 + 1; var ry0 = t2 - (t2 | 0); var ry1 = ry0 - 1.0; // If stitching, adjust lattice points accordingly. if (stitch_info) { if (bx0 >= stitch_info.wrap_x) { bx0 -= stitch_info.width; } if (bx1 >= stitch_info.wrap_x) { bx1 -= stitch_info.width; } if (by0 >= stitch_info.wrap_y) { by0 -= stitch_info.height; } if (by1 >= stitch_info.wrap_y) { by1 -= stitch_info.height; } } bx0 &= BM; bx1 &= BM; by0 &= BM; by1 &= BM; var i = this.lattice_selector[bx0]; var j = this.lattice_selector[bx1]; var b00 = this.lattice_selector[(i + by0)]; var b10 = this.lattice_selector[(j + by0)]; var b01 = this.lattice_selector[(i + by1)]; var b11 = this.lattice_selector[(j + by1)]; var sx = curve(rx0); var sy = curve(ry0); var q = this.gradient[color_channel][b00]; var u = rx0 * q[0] + ry0 * q[1]; var q2 = this.gradient[color_channel][b10]; var v = rx1 * q2[0] + ry0 * q2[1]; var a = lerp(sx, u, v); var q3 = this.gradient[color_channel][b01]; var u2 = rx0 * q3[0] + ry1 * q3[1]; var q4 = this.gradient[color_channel][b11]; var v2 = rx1 * q4[0] + ry1 * q4[1]; var b = lerp(sx, u2, v2); return lerp(sy, a, b); }; Turbulence.prototype.turbulence = function (color_channel, point, base_freq, num_octaves, fractal_sum, do_stitching, tile_pos, tile_size, octave_offsets) { if (octave_offsets === void 0) { octave_offsets = null; } var stitch_info = null; // Not stitching when None. // Adjust the base frequencies if necessary for stitching. if (do_stitching) { // When stitching tiled turbulence, the frequencies must be adjusted // so that the tile borders will be continuous. if (base_freq[0] !== 0.0) { var lo_freq = Math.floor(tile_size[0] * base_freq[0]) / tile_size[0]; var hi_freq = Math.ceil(tile_size[0] * base_freq[0]) / tile_size[0]; if (base_freq[0] / lo_freq < hi_freq / base_freq[0]) { base_freq[0] = lo_freq; } else { base_freq[0] = hi_freq; } } if (base_freq[1] !== 0.0) { var lo_freq = Math.floor(tile_size[1] * base_freq[1]) / tile_size[1]; var hi_freq = Math.ceil(tile_size[1] * base_freq[1]) / tile_size[1]; if (base_freq[1] / lo_freq < hi_freq / base_freq[1]) { base_freq[1] = lo_freq; } else { base_freq[1] = hi_freq; } } // Set up initial stitch values. var w = (tile_size[0] * base_freq[0] + 0.5) | 0; var h = (tile_size[1] * base_freq[1] + 0.5) | 0; stitch_info = { width: w, height: h, wrap_x: (tile_pos[0] * base_freq[0]) | 0 + PERLIN_N + w, wrap_y: (tile_pos[1] * base_freq[1]) | 0 + PERLIN_N + h, }; } var sum = 0.0; var ratio = 1.0; var nullOffset = [0, 0]; for (var octave = 0; octave < num_octaves; octave++) { var offset = octave_offsets ? octave_offsets[octave] : nullOffset; var vec = [ (point[0] + offset[0]) * base_freq[0] * ratio, (point[1] + offset[1]) * base_freq[1] * ratio ]; var noise = this.noise2(color_channel, vec, stitch_info); sum += (fractal_sum ? noise : Math.abs(noise)) / ratio; ratio *= 2.0; if (stitch_info) { stitch_info.width *= 2; stitch_info.wrap_x = 2 * stitch_info.wrap_x - PERLIN_N; stitch_info.height *= 2; stitch_info.wrap_y = 2 * stitch_info.wrap_y - PERLIN_N; } } return sum; }; Turbulence.fromSeed = function (seed) { var s; var lattice_selector = Array.from({ length: B_SIZE * 2 + 2 }, function () { return 0; }); var gradient = []; var rnd = new SeededRandom(seed); for (var k = 0; k < 4; k++) { gradient[k] = Array.from({ length: B_SIZE * 2 + 2 }, function () { return [0, 0]; }); for (var i = 0; i < B_SIZE; i++) { lattice_selector[i] = i; for (var j = 0; j < 2; j++) { seed = rnd.next(); rnd.seed = seed; gradient[k][i][j] = (seed % (B_SIZE + B_SIZE) - B_SIZE) / B_SIZE; } s = Math.sqrt(gradient[k][i][0] * gradient[k][i][0] + gradient[k][i][1] * gradient[k][i][1]); gradient[k][i][0] /= s; gradient[k][i][1] /= s; } } for (var i = B_SIZE - 1; i >= 0; i--) { var k = lattice_selector[i]; seed = rnd.next(); rnd.seed = seed; var j = seed % B_SIZE; lattice_selector[i] = lattice_selector[j]; lattice_selector[j] = k; } for (var i = 0; i < B_SIZE + 2; i++) { lattice_selector[B_SIZE + i] = lattice_selector[i]; for (var k = 0; k < 4; k++) { for (var j = 0; j < 2; j++) { gradient[k][B_SIZE + i][j] = gradient[k][i][j]; } } } return new Turbulence(gradient, lattice_selector); }; return Turbulence; }()); export { Turbulence };