const getCoordinateValue = function (coord, dimension) {
if (coord.substring) {
const val = parseFloat(coord);
if (_isFinite(val)) return (val / 100) * dimension;
return 0.5 * dimension;
}
return _isFinite(coord) ? coord : 0.5 * dimension;
};
const getWaveOperation = function (op) {
const params = op.parameters || {};
const axis = (params.axis === Y || params.axis === BOTH) ? params.axis : X,
amplitude = _isFinite(params.amplitude) ? params.amplitude : 10,
frequency = _isFinite(params.frequency) ? params.frequency : 0.05,
phase = _isFinite(params.phase) ? params.phase : 0;
return function (coord) {
const x = coord[0],
y = coord[1];
if (axis === X) coord[0] = x + (_sin((y * frequency) + phase) * amplitude);
else if (axis === Y) coord[1] = y + (_sin((x * frequency) + phase) * amplitude);
else {
coord[0] = x + (_sin((y * frequency) + phase) * amplitude);
coord[1] = y + (_sin((x * frequency) + phase) * amplitude);
}
return coord;
};
};
const getRippleOperation = function (op, workData, entity, lock) {
const params = op.parameters || {};
let width = workData.width,
height = workData.height;
if (lock && entity) {
const [w, h] = entity.get('dimensions');
width = w;
height = h;
}
const amplitude = _isFinite(params.amplitude) ? params.amplitude : 10,
frequency = _isFinite(params.frequency) ? params.frequency : 0.05,
phase = _isFinite(params.phase) ? params.phase : 0;
const originX = getCoordinateValue(params.originX, width),
originY = getCoordinateValue(params.originY, height);
return function (coord) {
const x = coord[0],
y = coord[1],
dx = x - originX,
dy = y - originY,
dist = _sqrt((dx * dx) + (dy * dy));
if (dist) {
const offset = _sin((dist * frequency) + phase) * amplitude,
ratio = offset / dist;
coord[0] = x + (dx * ratio);
coord[1] = y + (dy * ratio);
}
return coord;
};
};
const getMapDisplaceOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
axis = (params.axis === Y || params.axis === BOTH) ? params.axis : X,
strength = _isFinite(params.strength) ? params.strength : 20,
offset = _isFinite(params.offset) ? params.offset : 0.5,
linked = params.linked === true;
if (!strength) return λfirstArg;
if (axis === X) {
const map = getNoiseMap(mapParams, width, height);
return function (coord, p) {
coord[0] += (map[p] - offset) * strength;
return coord;
};
}
if (axis === Y) {
const map = getNoiseMap(mapParams, width, height);
return function (coord, p) {
coord[1] += (map[p] - offset) * strength;
return coord;
};
}
const xMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-x`,
}, width, height),
yMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-y`,
}, width, height);
return function (coord, p) {
coord[0] += (xMap[p] - offset) * strength;
coord[1] += (yMap[p] - offset) * strength;
return coord;
};
};
const getMapRotateOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
strength = _isFinite(params.strength) ? params.strength : 45,
offset = _isFinite(params.offset) ? params.offset : 0.5,
originX = getCoordinateValue(params.originX, width),
originY = getCoordinateValue(params.originY, height);
if (!strength) return λfirstArg;
const map = getNoiseMap(mapParams, width, height),
angleMultiplier = strength * _radian;
return function (coord, p) {
const angle = (map[p] - offset) * angleMultiplier,
cos = _cos(angle),
sin = _sin(angle),
x = coord[0] - originX,
y = coord[1] - originY;
coord[0] = originX + ((x * cos) - (y * sin));
coord[1] = originY + ((x * sin) + (y * cos));
return coord;
};
};
const getMapFlowOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
strength = _isFinite(params.strength) ? params.strength : 20,
offset = _isFinite(params.offset) ? params.offset : 0.5,
linked = params.linked === true,
normalize = params.normalize !== false;
if (!strength) return λfirstArg;
const xMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-x`,
}, width, height),
yMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-y`,
}, width, height);
return function (coord, p) {
let dx = xMap[p] - offset,
dy = yMap[p] - offset;
if (normalize) {
const mag = _sqrt((dx * dx) + (dy * dy));
if (mag) {
dx /= mag;
dy /= mag;
}
}
coord[0] += dx * strength;
coord[1] += dy * strength;
return coord;
};
};
const getMapThresholdOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
threshold = _isFinite(params.threshold) ? params.threshold : 0.5,
low = _isFinite(params.low) ? params.low : 0,
high = _isFinite(params.high) ? params.high : 1,
bandModulate = params.bandModulate === true,
bands = _isFinite(params.bands) ? _max(2, _floor(params.bands)) : 8,
influence = _isFinite(params.influence) ? params.influence : 0.25;
const map = getNoiseMap(mapParams, width, height);
if (bandModulate) {
return function (val, p) {
return _floor(
(val + ((map[p] - threshold) * influence)) * bands
) / bands;
};
}
return function (val, p) {
return (map[p] >= threshold) ? high : low;
};
};
const getMapContourOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
influence = _isFinite(params.influence) ? params.influence : 0.5,
bands = _isFinite(params.bands) ? _max(2, _floor(params.bands)) : 8;
const map = getNoiseMap(mapParams, width, height);
return function (val, p) {
const target = _floor(map[p] * bands) / bands;
return val + ((target - val) * influence);
};
};
const getMapEaseOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
strength = _isFinite(params.strength) ? params.strength : 0.25,
offset = _isFinite(params.offset) ? params.offset : 0.5;
if (!strength) return λfirstArg;
const map = getNoiseMap(mapParams, width, height);
return function (val, p) {
return val + ((map[p] - offset) * strength);
};
};
const getMapWarpOperation = function (op, workData) {
const params = op.parameters || {},
mapParams = params.map || {},
width = workData.width,
height = workData.height,
strength = _isFinite(params.strength) ? params.strength : 12,
offset = _isFinite(params.offset) ? params.offset : 0.5,
iterations = _isFinite(params.iterations) ? _max(1, _floor(params.iterations)) : 3,
linked = params.linked === true,
normalize = params.normalize === true;
if (!strength) return λfirstArg;
const xMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-x`,
}, width, height),
yMap = getNoiseMap(linked ? mapParams : {
...mapParams,
seed: `${mapParams.seed || DEFAULT_SEED}-y`,
}, width, height),
sampleMap = function (map, x, y) {
x = _floor(x);
y = _floor(y);
if (x < 0) x = 0;
else if (x >= width) x = width - 1;
if (y < 0) y = 0;
else if (y >= height) y = height - 1;
return map[(y * width) + x];
},
step = strength / iterations;
return function (coord) {
let x = coord[0],
y = coord[1],
dx, dy, mag;
for (let i = 0; i < iterations; i++) {
dx = sampleMap(xMap, x, y) - offset;
dy = sampleMap(yMap, x, y) - offset;
if (normalize) {
mag = _sqrt((dx * dx) + (dy * dy));
if (mag) {
dx /= mag;
dy /= mag;
}
}
x += dx * step;
y += dy * step;
}
coord[0] = x;
coord[1] = y;
return coord;
};
};
const getNoiseMap = function (noiseParams, width, height) {
const params = {
...noiseDefs,
width,
height,
...noiseParams,
};
const name = buildNoiseMapId(params),
cached = getWorkstoreItem(name);
if (cached) return cached;
noiseAsset.set(noiseDefs);
noiseAsset.set({
width,
height,
});
noiseAsset.set(noiseParams);
noiseAsset.cleanOutput();
const source = noiseAsset.noiseValues;
if (!source || source.length !== width * height) return new Float32Array(width * height);
const out = new Float32Array(source);
setWorkstoreItem(name, out);
return out;
};
const buildNoiseMapId = function (p) {
return [
'gradient-engine-noise-map',
p.width,
p.height,
p.seed,
p.noiseEngine,
p.size,
p.scale,
p.octaves,
p.octaveFunction,
p.persistence,
p.lacunarity,
p.smoothing,
p.sumFunction,
p.sineFrequencyCoeff,
p.sumAmplitude,
p.worleyOutput,
p.worleyDepth,
].join('-');
};