Spaces:
Runtime error
Runtime error
| const formatMessage = require('format-message'); | |
| const BlockType = require('../../extension-support/block-type'); | |
| const ArgumentType = require('../../extension-support/argument-type'); | |
| const MersenneTwister = require('mersenne-twister'); | |
| const { createNoise3D } = require('simplex-noise'); | |
| /** | |
| * Class for perlin noise extension. | |
| * @constructor | |
| */ | |
| // noise generation code from p5.js | |
| class iygPerlin { | |
| constructor(runtime) { | |
| /** | |
| * The runtime instantiating this block package. | |
| * @type {Runtime} | |
| */ | |
| this.runtime = runtime; | |
| this.noise; | |
| this.seed = 123; | |
| this.size = 50; | |
| this.generator = new MersenneTwister(this.seed); | |
| } | |
| /** | |
| * @returns {object} metadata for this extension and its blocks. | |
| */ | |
| getInfo() { | |
| return { | |
| id: 'iygPerlin', | |
| name: 'Perlin Noise', | |
| color1: '#525252', | |
| color2: '#636363', | |
| blocks: [ | |
| // Hidden | |
| { | |
| opcode: 'GetNoise', | |
| blockType: BlockType.REPORTER, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GetNoise', | |
| default: 'Get perlin noise with seed [SEED] and octave [OCTAVE] at x [X], y [Y], and z [Z]', | |
| description: 'Get seeded perlin noise at a specified x and y and z.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| OCTAVE: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 4 | |
| }, | |
| X: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Y: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Z: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| } | |
| }, | |
| hideFromPalette: true | |
| }, | |
| // Hidden | |
| { | |
| opcode: 'GetRandomNoise', | |
| blockType: BlockType.REPORTER, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GetRandomNoise', | |
| default: 'Get noise with seed [SEED] at x [X], y [Y], and z [Z]', | |
| description: 'Get seeded noise with a specified seed at a specified x and y and z.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| X: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Y: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Z: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| } | |
| }, | |
| hideFromPalette: true | |
| }, | |
| // Hidden | |
| { | |
| opcode: 'GeneratePerlinNoise', | |
| blockType: BlockType.COMMAND, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GeneratePerlinNoise', | |
| default: 'Pre-generate perlin noise with seed [SEED] and octave [OCTAVE]', | |
| description: 'Pre-generate seeded perlin noise.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| OCTAVE: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 4 | |
| } | |
| }, | |
| hideFromPalette: true | |
| }, | |
| // Hidden | |
| { | |
| opcode: 'GenerateRandomNoise', | |
| blockType: BlockType.COMMAND, | |
| hideFromPalette: true, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GenerateRandomNoise', | |
| default: 'not needed [SEED] [SIZE]', | |
| description: 'Pre-generate seeded noise.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| SIZE: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 50 | |
| } | |
| }, | |
| }, | |
| // Hidden | |
| { | |
| opcode: 'getSimplexNoise', | |
| blockType: BlockType.REPORTER, | |
| hideFromPalette: true, | |
| text: formatMessage({ | |
| id: 'iygPerlin.getSimplexNoise', | |
| default: 'Get simplex noise with seed [SEED] at x [X], y [Y], and z [Z]', | |
| description: 'Get simplex noise with a specified seed at a specified x and y and z.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| X: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Y: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Z: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| } | |
| } | |
| }, | |
| // End of hidden stuff | |
| { | |
| opcode: 'GetNoiseV2', | |
| blockType: BlockType.REPORTER, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GetNoiseV2', | |
| default: 'Get perlin noise with seed [SEED] and octave [OCTAVE] at x [X], y [Y], and z [Z]', | |
| description: 'Get seeded perlin noise at a specified x and y and z.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| OCTAVE: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 4 | |
| }, | |
| X: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Y: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Z: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| } | |
| }, | |
| }, | |
| { | |
| opcode: 'GetRandomNoiseV2', | |
| blockType: BlockType.REPORTER, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GetRandomNoiseV2', | |
| default: 'Get random noise with seed [SEED] at x [X], y [Y], and z [Z]', | |
| description: 'Get seeded random noise with a specified seed at a specified x and y and z.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| X: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Y: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| }, | |
| Z: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 0 | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'GeneratePerlinNoiseV2', | |
| blockType: BlockType.COMMAND, | |
| text: formatMessage({ | |
| id: 'iygPerlin.GeneratePerlinNoiseV2', | |
| default: 'Pre-generate perlin noise with seed [SEED] and octave [OCTAVE]', | |
| description: 'Pre-generate seeded perlin noise.' | |
| }), | |
| arguments: { | |
| SEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 123 | |
| }, | |
| OCTAVE: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 4 | |
| } | |
| } | |
| }, | |
| ] | |
| }; | |
| } | |
| goodSeedRandom() { | |
| this.generator.init_seed(this.seed); | |
| let result = this.generator.random_incl(); | |
| this.seed = result * 4294967296; | |
| return result; | |
| } | |
| dumbSeedRandom() { | |
| this.generator.init_seed(this.seed); | |
| let result = this.generator.random_incl(); | |
| this.seed = (1664525*this.seed + 1013904223) % 4294967296; | |
| return result; | |
| } | |
| GeneratePerlinNoise(args, util) { | |
| args.X = 0; | |
| args.Y = 0; | |
| args.Z = 0; | |
| this.GetNoise(args, util); | |
| } | |
| GenerateRandomNoise(args, util) { | |
| let seed = args.SEED; | |
| let size = args.SIZE; | |
| if (this.noise == null || seed != this.seed) { | |
| this.noise = new Array(size); | |
| this.seed = seed; | |
| for (let i = 0; i < size; i++) { | |
| this.noise[i] = new Array(size); | |
| for (let j = 0; j < size; j++) { | |
| this.noise[i][j] = new Array(size); | |
| for (let k = 0; k < size; k++) { | |
| this.noise[i][j][k] = this.dumbSeedRandom(); | |
| } | |
| } | |
| } | |
| this.seed = seed; | |
| this.prev_seed = seed; | |
| this.size = size; | |
| } | |
| if (size > this.size && seed == this.seed) { | |
| this.seed = this.prev_seed; | |
| for (let i = this.size; i < size+1; i++) { | |
| this.noise[i] = new Array(size); | |
| for (let j = this.size; j < size+1; j++) { | |
| this.noise[i][j] = new Array(size); | |
| for (let k = this.size; k < size+1; k++) { | |
| this.noise[i][j][k] = this.dumbSeedRandom(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| GetRandomNoise(args, util) { | |
| let seed = args.SEED; | |
| let x = args.X; | |
| let y = args.Y; | |
| let z = args.Z; | |
| let pre_seed = this.seed; | |
| this.seed = seed+x+y*1000+z*10000; | |
| let result = this.dumbSeedRandom(); | |
| this.seed = pre_seed; | |
| return result; | |
| } | |
| generatePerlin(seed, perlin_octaves, rand, x, y, z) { | |
| let perlin_amp_falloff = 0.5; | |
| const scaled_cosine = i => 0.5 * (1.0 - Math.cos(i * Math.PI)); | |
| const PERLIN_SIZE = 4095; | |
| const PERLIN_YWRAPB = 4; | |
| const PERLIN_YWRAP = 1 << PERLIN_YWRAPB; | |
| const PERLIN_ZWRAPB = 8; | |
| const PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB; | |
| if (this.perlin == null || seed != this.seed) { | |
| this.perlin = new Array(PERLIN_SIZE + 1); | |
| this.seed = seed; | |
| for (let i = 0; i < PERLIN_SIZE + 1; i++) { | |
| this.perlin[i] = rand(); | |
| } | |
| this.seed = seed; | |
| } | |
| if (x < 0) { | |
| x = -x; | |
| } | |
| if (y < 0) { | |
| y = -y; | |
| } | |
| if (z < 0) { | |
| z = -z; | |
| } | |
| let xi = Math.floor(x), | |
| yi = Math.floor(y), | |
| zi = Math.floor(z); | |
| let xf = x - xi; | |
| let yf = y - yi; | |
| let zf = z - zi; | |
| let rxf, ryf; | |
| let r = 0; | |
| let ampl = 0.5; | |
| let n1, n2, n3; | |
| for (let o = 0; o < perlin_octaves; o++) { | |
| let of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB); | |
| rxf = scaled_cosine(xf); | |
| ryf = scaled_cosine(yf); | |
| n1 = this.perlin[of & PERLIN_SIZE]; | |
| n1 += rxf * (this.perlin[(of + 1) & PERLIN_SIZE] - n1); | |
| n2 = this.perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE]; | |
| n2 += rxf * (this.perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2); | |
| n1 += ryf * (n2 - n1); | |
| of += PERLIN_ZWRAP; | |
| n2 = this.perlin[of & PERLIN_SIZE]; | |
| n2 += rxf * (this.perlin[(of + 1) & PERLIN_SIZE] - n2); | |
| n3 = this.perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE]; | |
| n3 += rxf * (this.perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3); | |
| n2 += ryf * (n3 - n2); | |
| n1 += scaled_cosine(zf) * (n2 - n1); | |
| r += n1 * ampl; | |
| ampl *= perlin_amp_falloff; | |
| xi <<= 1; | |
| xf *= 2; | |
| yi <<= 1; | |
| yf *= 2; | |
| zi <<= 1; | |
| zf *= 2; | |
| if (xf >= 1.0) { | |
| xi++; | |
| xf--; | |
| } | |
| if (yf >= 1.0) { | |
| yi++; | |
| yf--; | |
| } | |
| if (zf >= 1.0) { | |
| zi++; | |
| zf--; | |
| } | |
| } | |
| return r % 1.0; | |
| } | |
| GetNoise(args, util) { | |
| let seed = args.SEED; | |
| let perlin_octaves = ((args.OCTAVE === Infinity) ? 4 : args.OCTAVE); | |
| let x = args.X + .5; | |
| let y = args.Y + .5; | |
| let z = args.Z + .5; | |
| return this.generatePerlin(seed, perlin_octaves, this.dumbSeedRandom.bind(this), x, y, z); | |
| } | |
| // ----- V2 ----- | |
| GetNoiseV2(args, util) { | |
| let seed = args.SEED; | |
| let perlin_octaves = ((args.OCTAVE === Infinity) ? 4 : args.OCTAVE); | |
| let x = args.X + .5; | |
| let y = args.Y + .5; | |
| let z = args.Z + .5; | |
| return this.generatePerlin(seed, perlin_octaves, this.goodSeedRandom.bind(this), x, y, z); | |
| } | |
| // ----- V2 ----- | |
| GetRandomNoiseV2(args, util) { | |
| let seed = args.SEED; | |
| let x = args.X; | |
| let y = args.Y; | |
| let z = args.Z; | |
| let pre_seed = this.seed; | |
| this.seed = seed + (x * 743) + (y * 942 ) + (z * 645); | |
| let result = this.goodSeedRandom.bind(this)(); | |
| this.seed = pre_seed; | |
| return result; | |
| } | |
| // ----- V2 ----- | |
| GeneratePerlinNoiseV2(args, util) { | |
| args.X = 0; | |
| args.Y = 0; | |
| args.Z = 0; | |
| this.GetNoiseV2(args, util); | |
| } | |
| getSimplexNoise(args) { | |
| const seed = args.SEED; | |
| const x = args.X; | |
| const y = args.Y; | |
| const z = args.Z; | |
| this.generator.init_seed(seed); | |
| const noise = createNoise3D(this.generator.random_incl.bind(this.generator)); | |
| return noise(x, y, z); | |
| } | |
| } | |
| module.exports = iygPerlin; | |