soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
15.8 kB
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;