diff --git a/public/index.html b/public/index.html
index 8d6652f..5f3bdb9 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,16 +2,21 @@
+
+
+
+
Gray Scott Plus!
- Gray Scott Plus!
+
+
\ No newline at end of file
diff --git a/public/js/cell.js b/public/js/cell.js
new file mode 100644
index 0000000..c03805c
--- /dev/null
+++ b/public/js/cell.js
@@ -0,0 +1,87 @@
+//cell class
+class Cell {
+ constructor(x, y, a, b, noiseX, noiseY, noiseScalar)
+ {
+ this.x = x;
+ this.y = y;
+
+
+ this.setAB = (a, b) =>
+ {
+ this.a = constrain(a, 0, 1);
+ this.b = constrain(b, 0, 1);
+ }
+ this.setAB(a, b);
+
+ this.zeroWeights = () =>
+ {
+ this.weightLftUp = weightDiagonal;
+ this.weightCtrUp = weightOrtho;
+ this.weightRgtUp = weightDiagonal;
+ this.weightLftCr = weightOrtho;
+ this.weightCtrCr = weightReset;
+ this.weightRgtCr = weightOrtho;
+ this.weightLftDn = weightDiagonal;
+ this.weightCtrDn = weightOrtho;
+ this.weightRgtDn = weightDiagonal;
+ }
+ this.zeroWeights();
+
+ //calculate individual bias weight
+ this.calcBiasIndiv = (dir, biasX, biasY, baseWeight, scalar) =>
+ {
+ const sumX = dir.x + biasX;
+ const sumY = dir.y + biasY;
+
+ return sqrt((sumX * sumX) + (sumY * sumY)) * baseWeight * scalar;
+ }
+
+ //calculate new bias weights
+ this.calcWeights = (biasX, biasY, scalar) =>
+ {
+ let total = 0;
+ total += this.weightLftUp = weightDiagonal + this.calcBiasIndiv(dirLftUp, biasX, biasY, weightDiagonal, scalar);
+ total += this.weightCtrUp = weightOrtho + this.calcBiasIndiv(dirCtrUp, biasX, biasY, weightOrtho, scalar);
+ total += this.weightRgtUp = weightDiagonal + this.calcBiasIndiv(dirRgtUp, biasX, biasY, weightDiagonal, scalar);
+ total += this.weightLftCr = weightOrtho + this.calcBiasIndiv(dirLftCr, biasX, biasY, weightOrtho, scalar);
+ //total += weightCtrCr = weightReset;
+ total += this.weightRgtCr = weightOrtho + this.calcBiasIndiv(dirRgtCr, biasX, biasY, weightOrtho, scalar);
+ total += this.weightLftDn = weightDiagonal + this.calcBiasIndiv(dirLftDn, biasX, biasY, weightDiagonal, scalar);
+ total += this.weightCtrDn = weightOrtho + this.calcBiasIndiv(dirCtrDn, biasX, biasY, weightOrtho, scalar);
+ total += this.weightRgtDn = weightDiagonal + this.calcBiasIndiv(dirRgtDn, biasX, biasY, weightDiagonal, scalar);
+
+ this.weightLftUp /= total;
+ this.weightCtrUp /= total;
+ this.weightRgtUp /= total;
+ this.weightLftCr /= total;
+
+ this.weightRgtCr /= total;
+ this.weightLftDn /= total;
+ this.weightCtrDn /= total;
+ this.weightRgtDn /= total;
+
+ //console.log(weightLftUp);
+ }
+
+ this.setWeights = (noiseX, noiseY, scalar) =>
+ {
+ this.noiseX = noiseX;
+ this.noiseY = noiseY;
+
+ //set bias as unitized noise values
+ const mag = sqrt((noiseX * noiseX) + (noiseY * noiseY));
+ const biasX = noiseX / mag;
+ const biasY = noiseY / mag;
+
+ this.calcWeights(biasX, biasY, scalar);
+ }
+ this.setWeights(noiseX, noiseY, noiseScalar);
+
+ this.setWeightScalar = (scalar) =>
+ {
+ this.setWeights(this.noiseX, this.noiseY, scalar);
+ }
+
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/public/js/global.js b/public/js/global.js
new file mode 100644
index 0000000..e06eb90
--- /dev/null
+++ b/public/js/global.js
@@ -0,0 +1,57 @@
+const uiWidth = 256; //width of the ui bar
+const w = 512; //totalWidth - uiWidth; //grid width. TODO: make this resolution adjustable and interpolate while drawing
+const totalWidth = w + uiWidth;//innerWidth; //total width of the p5 canvas. TODO: make this responsive to resizing
+const h = 512; //grid height. TODO: make this resolution scalable and interpolate while drawing
+const vecStep = 8;
+
+//let gridNoise = []; //grid current state noise
+let gridNow = []; //grid current state
+let gridNext = []; //grid future state
+let gridVec = []; //grid vector state
+
+const weightReset = -1; //reset weight for cell self
+const weightOrtho = 0.2; //base weight for cell ortho neighbors
+const weightDiagonal = 0.05; //base weight for cell diagonal neighbors
+const deltaA = 1.0; //base speed for A
+const deltaB = 0.5; //base speed for B
+let feedRate = 0.029; //0.025; //0.0w55;
+let killRate = 0.057; //0.06; //0.062;
+let timeScalar = 1.0; //speed dampener
+let paintRangeScalar = 0.1; //paint brush radius
+let noiseScalar = 0.005;
+let vecScalar = 0.03;
+
+feedKillPresets = {
+ "mazes": {feed: 0.029, kill: 0.057},
+ "solitions": {feed: 0.03, kill: 0.062},
+ "pulsating solitions": {feed: 0.025, kill: 0.062},
+ "worms": {feed: 0.078, kill: 0.061},
+ "holes": {feed: 0.039, kill: 0.058},
+ "chaos": {feed: 0.026, kill: 0.051},
+ "chaos and holes (by clem)": {feed: 0.034, kill: 0.056},
+ "moving spots": {feed: 0.014, kill: 0.054},
+ "spots and loops": {feed: 0.018, kill: 0.051},
+ "waves": {feed: 0.014, kill: 0.045},
+ "the u-skate world": {feed: 0.062, kill: 0.06093}
+};
+
+let dirLftUp = null; //left up vector
+let dirCtrUp = null; //center up vector
+let dirRgtUp = null; //right up vector
+let dirLftCr = null; //left center vector
+let dirCtrCr = null; //center vector (0, 0)
+let dirRgtCr = null; //right center vector
+let dirLftDn = null; //left down vector
+let dirCtrDn = null; //center down vector
+let dirRgtDn = null; //right down vector
+
+//let biasVec = null; //bias vector
+let weightLftUp = weightDiagonal; //left up result weight
+let weightCtrUp = weightOrtho; //center up result weight
+let weightRgtUp = weightDiagonal; //right up result weight
+let weightLftCr = weightOrtho; //left center result weight
+let weightCtrCr = weightReset; //center reset weight (-1)
+let weightRgtCr = weightOrtho; //right center result weight
+let weightLftDn = weightDiagonal; //left down result weight
+let weightCtrDn = weightOrtho; //center down result weight
+let weightRgtDn = weightDiagonal; //right down result weight
\ No newline at end of file
diff --git a/public/js/main.js b/public/js/main.js
index efe9fbf..4a00859 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -1,51 +1,82 @@
-const uiWidth = 256; //width of the ui bar
-const totalWidth = innerWidth; //total width of the p5 canvas. TODO: make this responsive to resizing
-const w = totalWidth - uiWidth; //grid width. TODO: make this resolution adjustable and interpolate while drawing
-const h = 512; //grid height. TODO: make this resolution scalable and interpolate while drawing
-
-let gridNow = []; //grid current state
-let gridNext = []; //grid future state
-
-const weightReset = -1; //reset weight for cell self
-const weightOrtho = 0.2; //base weight for cell ortho neighbors
-const weightDiagonal = 0.05; //base weight for cell diagonal neighbors
-const deltaA = 1.0; //base speed for A
-const deltaB = 0.5; //base speed for B
-let feedRate = 0.025; //0.0w55;
-let killRate = 0.06; //0.062;
-let timeScalar = 1.0; //speed dampener
-let paintRangeScalar = 0.1; //paint brush radius
-
-let dirLftUp = null; //left up vector
-let dirCtrUp = null; //center up vector
-let dirRgtUp = null; //right up vector
-let dirLftCr = null; //left center vector
-let dirCtrCr = null; //center vector (0, 0)
-let dirRgtCr = null; //right center vector
-let dirLftDn = null; //left down vector
-let dirCtrDn = null; //center down vector
-let dirRgtDn = null; //right down vector
-
-let biasVec = null; //bias vector
-let weightLftUp = weightDiagonal; //left up result weight
-let weightCtrUp = weightOrtho; //center up result weight
-let weightRgtUp = weightDiagonal; //right up result weight
-let weightLftCr = weightOrtho; //left center result weight
-let weightCtrCr = weightReset; //center reset weight (-1)
-let weightRgtCr = weightOrtho; //right center result weight
-let weightLftDn = weightDiagonal; //left down result weight
-let weightCtrDn = weightOrtho; //center down result weight
-let weightRgtDn = weightDiagonal; //right down result weight
+//const { text } = require("express");
+
+const sliderWidth = uiWidth * 0.8;
+const sliderOffsetX = uiWidth * 0.1;
+const titleOffsetY = h * 0.17;
+const sliderStepY = h * 0.1;
+const sliderStep = 0.001;
+
+let canvas = null;
+let sliderFeedRate = null;
+let sliderKillRate = null;
+let sliderTimeScalar = null;
+let sliderPaintRangeScalar = null;
+let sliderNoiseScalar = null;
+let sliderVecScalar = null;
+let dropDownFeedKill = null;
+let buttonReset = null;
//p5 setup. This is called once at the beginning of runtime
setup = () => {
//console.log("setup!");
+ //setAttributes('willReadFrequently', true);
+
+ const e = createCanvas(totalWidth, h);
+ canvas = e.canvas;
+
+ drawingContext.willReadFrequently = true;
+ setAttributes('2d', 'willReadFrequently', true);
+
+ // e.canvas.willReadFrequently = true;
+ // e.drawingContext.willReadFrequently = true;
+ // //e.drawingContext.getContext('2d', { willReadFrequently: true });
+ // e.canvas.getContext('2d', { willReadFrequently: true });
+ //console.log(drawingContext);
+ // setAttributes('willReadFrequently', true);
- createCanvas(innerWidth, h);
pixelDensity(1);
+
+ //bias = createVector(biasStep, biasStep);
+ initDir();
+
initGrids(w, h);
- bias = createVector(biasStep, biasStep);
+ initUI();
+
+ setGridCircle(0.5);
+
+ // const halfW = round(w * 0.5);
+ // const halfH = round(h * 0.5);
+ // const offset = round(w * 0.1);
+
+ // //temp - make this interactive!
+ // for(let x = halfW - offset; x < halfW + offset; x++)
+ // {
+ // for(let y = halfH - offset; y < halfH + offset; y++)
+ // {
+ // gridNow[x][y].b = 1;
+ // }
+ // }
+}
+
+//p5 draw loop. This is called every frame
+draw = () => {
+
+ background(255);
+ //background(0,0,0,0);
+
+ paintCheck();
+
+ updateGrid();
+ drawPixels();
+ step();
+
+ drawUILabels();
+ drawVecGrid();
+ drawPaintRadius();
+}
+
+initDir = () => {
dirLftUp = createVector(-1, -1);
dirCtrUp = createVector(0, -1);
dirRgtUp = createVector(1, -1);
@@ -55,51 +86,240 @@ setup = () => {
dirLftDn = createVector(-1, 1);
dirCtrDn = createVector(0, 1);
dirRgtDn = createVector(1, 1);
+}
- resetBias();
- updateBias(bias);
+//initialize grids
+initGrids = (w, h) => {
+
+ initCellGrids(w, h);
+ initVecGrid(w, h);
+}
- const halfW = round(w * 0.5);
- const halfH = round(h * 0.5);
- const offset = round(w * 0.1);
+initCellGrids = (w, h) => {
- //temp - make this interactive!
- for(let x = halfW - offset; x < halfW + offset; x++)
+ //const gridWidth = w - uiWidth;
+ for(let x = 0; x < w; x++)
{
- for(let y = halfH - offset; y < halfH + offset; y++)
+ //gridNoise[x] = [];
+ gridNow[x] = [];
+ gridNext[x] = [];
+
+ for(let y = 0; y < h; y++)
{
- gridNow[x][y].b = 1;
+ //const noiseY = noise(map(y, 0, h, 0, noiseScalar));
+
+ const mNX = gen2dUnitNoise((w + x) * noiseScalar, y * noiseScalar);
+ const mNY = gen2dUnitNoise(x * noiseScalar, (h + y) * noiseScalar);
+
+ gridNow[x][y] = new Cell(x, y, 1.0, 0.0, mNX, mNY, vecScalar);
+ gridNext[x][y] = new Cell(x, y, 1.0, 0.0, mNX, mNY, vecScalar);
}
}
}
-//p5 draw loop. This is called every frame
-draw = () => {
+initVecGrid = (w, h) => {
+// const vecGridDimX = w / vecStep;
+ // const vecGridDimY = h / vecStep;
+ for(let x = 0; x < w; x += vecStep)
+ {
+ const vecX = x / vecStep;
+ //const avgX = getAvg(noiseX, vecX, vecX + vecStep);
+ gridVec[vecX] = [];
+
+ for(let y = 0; y < h; y += vecStep)
+ {
+ const vecY = y / vecStep;
+ gridVec[vecX][vecY] = getCellAvg(x, x + vecStep, y, y + vecStep);
+ }
+ }
+}
- background(200);
+initUI = () => {
+
+ sliderNoiseScalar = createSlider(0.001, 0.01, noiseScalar, sliderStep);
+ sliderVecScalar = createSlider(0, 0.05, vecScalar, sliderStep);
+ sliderFeedRate = createSlider(0.01, 0.08, feedRate, sliderStep);
+ sliderKillRate = createSlider(0.01, 0.08, killRate, sliderStep);
+ sliderTimeScalar = createSlider(0.1, 1.1, timeScalar, sliderStep);
+ sliderPaintRangeScalar = createSlider(0.01, 0.25, paintRangeScalar, sliderStep);
+ dropDownFeedKill = createSelect();
+ dropDownFeedKill.option("mazes");
+ dropDownFeedKill.option("solitions");
+ dropDownFeedKill.option("pulsating solitions");
+ dropDownFeedKill.option("worms");
+ dropDownFeedKill.option("holes");
+ dropDownFeedKill.option("chaos");
+ dropDownFeedKill.option("chaos and holes (by clem)");
+ dropDownFeedKill.option("moving spots");
+ dropDownFeedKill.option("spots and loops");
+ dropDownFeedKill.option("waves");
+ dropDownFeedKill.option("the u-skate world");
+ buttonReset = createButton('reset');
+
+
+ // sliderNoiseScalar.parent(document.getElementsByTagName('main')[0]);
+ // sliderNoiseScalar.addClass('mySlider');
+ // console.log(sliderNoiseScalar);
+
+ sliderNoiseScalar.mouseReleased(() => {
+ noiseScalar = sliderNoiseScalar.value();
+ updateCellNoise(w, h);
+ });
+ sliderVecScalar.mouseReleased(() => {
+ vecScalar = sliderVecScalar.value();
+ updateCellNoiseVecScalar(vecScalar);
+ });
+ sliderFeedRate.mouseReleased(() => {feedRate = sliderFeedRate.value();});
+ sliderKillRate.mouseReleased(() => {killRate = sliderKillRate.value();});
+ sliderTimeScalar.mouseReleased(() => {timeScalar = sliderTimeScalar.value();});
+ sliderPaintRangeScalar.mouseReleased(() => {paintRangeScalar = sliderPaintRangeScalar.value();});
+ dropDownFeedKill.changed(() => {
+ const presetName = dropDownFeedKill.value();
+ const preset = feedKillPresets[presetName];
+ feedRate = preset.feed;
+ killRate = preset.kill;
+ sliderFeedRate.value(feedRate);
+ sliderKillRate.value(killRate);
+
+ //TODO: clear and reset grid
+ });
+ buttonReset.mouseReleased(() => {resetGrid();});
+
+ // sliderNoiseScalar.parent(canvas);
+ // sliderNoiseScalar.position(sliderOffsetX, sliderStepY, 'relative');
+
+ sliderNoiseScalar.position(sliderOffsetX, titleOffsetY + sliderStepY);
+ sliderVecScalar.position(sliderOffsetX, titleOffsetY + sliderStepY * 2);
+ sliderFeedRate.position(sliderOffsetX, titleOffsetY + sliderStepY * 3);
+ sliderKillRate.position(sliderOffsetX, titleOffsetY + sliderStepY * 4);
+ sliderTimeScalar.position(sliderOffsetX, titleOffsetY + sliderStepY * 5);
+ sliderPaintRangeScalar.position(sliderOffsetX, titleOffsetY + sliderStepY * 6);
+ dropDownFeedKill.position(sliderOffsetX, titleOffsetY + sliderStepY * 7.15);
+ buttonReset.position(sliderOffsetX, titleOffsetY + sliderStepY * 8);
+
+ sliderNoiseScalar.size(sliderWidth);
+ sliderVecScalar.size(sliderWidth);
+ sliderFeedRate.size(sliderWidth);
+ sliderKillRate.size(sliderWidth);
+ sliderTimeScalar.size(sliderWidth);
+ sliderPaintRangeScalar.size(sliderWidth);
+ dropDownFeedKill.size(sliderWidth);
+ buttonReset.size(sliderWidth);
+}
- paintCheck();
+getCellAvg = (startX, endX, startY, endY) =>
+{
+ let avgX = 0;
+ let avgY = 0
+ const divX = endX - startX;
+ const divY = endY - startY;
- updateGrid();
- drawPixels();
- step();
+ for(let x = startX; x < endX && x < gridNow.length; x++)
+ {
+ for(let y = startY; y < endY && y < gridNow[x].length; y++)
+ {
+ const cell = gridNow[x][y];
+ avgX += cell.noiseX;
+ avgY += cell.noiseY;
+ }
+ }
+
+ avgX /= divX;
+ avgY /= divY;
+
+ const vec = createVector(avgX , avgY);
+ vec.normalize();
+
+ return vec;
}
-//initialize grids
-initGrids = (w, h) => {
+getAvg = (arr, start, end) =>
+{
+ let avg = 0;
+ const divisor = end - start;
+
+ for(let i = start; i < end && i < arr.length; i++)
+ {
+ avg += arr[i];
+ }
- //const gridWidth = w - uiWidth;
+ return avg / divisor;
+}
+
+gen2dUnitNoise = (x, y) => {
+ return map(noise(x, y), 0, 1, -1, 1);
+}
+
+updateCellNoise = (w, h) => {
+
for(let x = 0; x < w; x++)
{
- gridNow[x] = [];
- gridNext[x] = [];
+ for(let y = 0; y < h; y++)
+ {
+ //const noiseY = noise(map(y, 0, h, 0, noiseScalar));
+
+ const mNX = gen2dUnitNoise((w + x) * noiseScalar, y * noiseScalar);
+ const mNY = gen2dUnitNoise(x * noiseScalar, (h + y) * noiseScalar);
+
+ gridNow[x][y].setWeights(mNX, mNY, vecScalar);
+ gridNext[x][y].setWeights(mNX, mNY, vecScalar);
+ }
+ }
+
+ initVecGrid(w, h);
+}
+
+updateCellNoiseVecScalar = (w, h) => {
+
+ for(let x = 0; x < w; x++)
+ {
+ for(let y = 0; y < h; y++)
+ {
+ gridNow[x][y].setWeightScalar(vecScalar);
+ gridNext[x][y].setWeightScalar(vecScalar);
+ }
+ }
+}
+
+resetGrid = () => {
+ clearGrid();
+ setGridCircle(0.5);
+}
+clearGrid = () => {
+ for(let x = 0; x < w; x++)
+ {
for(let y = 0; y < h; y++)
{
- gridNow[x][y] = new Cell(x, y, 1.0, 0.0);
- gridNext[x][y] = new Cell(x, y, 1.0, 0.0);
+ gridNow[x][y].setAB(1, 0);
+ gridNext[x][y].setAB(1, 0);
+ }
+ }
+}
+
+setGridCircle = (sizeRatio) => {
+
+ const xStart = round((w * 0.5) - (w * sizeRatio * 0.5));
+ const xEnd = w - xStart;
+ const xCenter = round(w * 0.5);
+ const yCenter = round(h * 0.5);
+ const pi = Math.PI;
+
+ for(let x = xStart; x < xEnd; x++)
+ {
+ const xUnit = (x - xStart) / (xEnd - xStart);
+ const xOffset = round(Math.cos(xUnit * pi) * w * sizeRatio * 0.5);
+ const yOffset = round(Math.sin(xUnit * pi) * h * sizeRatio * 0.5);
+ const xPos = xCenter + xOffset;
+
+ for(let y = yCenter - yOffset; y < yCenter + yOffset; y++)
+ {
+ const yPos = y;
+
+ gridNow[xPos][yPos].b = 1;
}
}
+
}
//update future grid
@@ -111,132 +331,77 @@ updateGrid = () => {
{
const cellNow = gridNow[x][y];
const cellNext = gridNext[x][y];
- const aNext = grayScott(cellNow, deltaA, laplaceA, getA, reactionA, feed);
- const bNext = grayScott(cellNow, deltaB, laplaceB, getB, reactionB, kill);
+ const aNext = grayScott(cellNow, cellNow.a, deltaA, laplaceA, reactionA, feed);
+ const bNext = grayScott(cellNow, cellNow.b, deltaB, laplaceB, reactionB, kill);
- cellNext.set(aNext, bNext);
+ cellNext.setAB(aNext, bNext);
}
}
}
-//ye olde gray scot model
-grayScott = (cell, delta, laplace, getAB, reaction, feedKill) => {
-
- const v = getAB(cell);
+//ye olde gray scott model
+grayScott = (cell, value, delta, laplace, reaction, feedKill) => {
- const stepOne = (delta * laplace(cell.x, cell.y, getAB)) +
+ const stepOne = (delta * laplace(cell)) +
reaction(cell.a, cell.b) +
- feedKill(v);
+ feedKill(value);
const stepScale = stepOne * timeScalar;
- return v + stepScale;
+ return value + stepScale;
}
//laplace function for feed values
-laplaceA = (x, y, f) => {
+laplaceA = (cell) => {
- left = (x + w - 1) % w;
- right = (x + 1) % w;
- up = (y + h - 1) % h;
- down = (y + 1) % h;
+ const x = cell.x;
+ const y = cell.y;
+ const left = (x + w - 1) % w;
+ const right = (x + 1) % w;
+ const up = (y + h - 1) % h;
+ const down = (y + 1) % h;
let v = 0;
- v += f(gridNow[x][y]) * weightReset;
- v += f(gridNow[left][y]) * weightLftCr;
- v += f(gridNow[right][y]) * weightRgtCr;
- v += f(gridNow[x][down]) * weightCtrDn;
- v += f(gridNow[x][up]) * weightCtrUp;
- v += f(gridNow[left][up]) * weightLftUp;
- v += f(gridNow[right][up]) * weightRgtUp;
- v += f(gridNow[right][down]) * weightRgtDn;
- v += f(gridNow[left][down]) * weightLftDn;
+ v += gridNow[x][y].a * weightReset;
+ v += gridNow[left][y].a * cell.weightLftCr;
+ v += gridNow[right][y].a * cell.weightRgtCr;
+ v += gridNow[x][down].a * cell.weightCtrDn;
+ v += gridNow[x][up].a * cell.weightCtrUp;
+ v += gridNow[left][up].a * cell.weightLftUp;
+ v += gridNow[right][up].a * cell.weightRgtUp;
+ v += gridNow[right][down].a * cell.weightRgtDn;
+ v += gridNow[left][down].a * cell.weightLftDn;
return v;
}
//laplace function for kill values
//laplaceB weights should be mirrored to laplaceA
-laplaceB = (x, y, f) => {
+laplaceB = (cell) => {
- left = (x + w - 1) % w;
- right = (x + 1) % w;
- up = (y + h - 1) % h;
- down = (y + 1) % h;
+ const x = cell.x;
+ const y = cell.y;
+ const left = (x + w - 1) % w;
+ const right = (x + 1) % w;
+ const up = (y + h - 1) % h;
+ const down = (y + 1) % h;
let v = 0;
- v += f(gridNow[x][y]) * weightReset;
- v += f(gridNow[left][y]) * weightRgtCr;
- v += f(gridNow[right][y]) * weightLftCr;
- v += f(gridNow[x][down]) * weightCtrUp;
- v += f(gridNow[x][up]) * weightCtrDn;
- v += f(gridNow[left][up]) * weightRgtDn;
- v += f(gridNow[right][up]) * weightLftDn;
- v += f(gridNow[right][down]) * weightLftUp;
- v += f(gridNow[left][down]) * weightRgtUp;
+ v += gridNow[x][y].b * weightReset;
+ v += gridNow[left][y].b * cell.weightRgtCr;
+ v += gridNow[right][y].b * cell.weightLftCr;
+ v += gridNow[x][down].b * cell.weightCtrUp;
+ v += gridNow[x][up].b * cell.weightCtrDn;
+ v += gridNow[left][up].b * cell.weightRgtDn;
+ v += gridNow[right][up].b * cell.weightLftDn;
+ v += gridNow[right][down].b * cell.weightLftUp;
+ v += gridNow[left][down].b * cell.weightRgtUp;
return v;
}
-//update bias vector and calculate new bias weights
-updateBias = (delta) => {
-
- bias = p5.Vector.add(bias, delta);
-
- calcBias(bias);
-}
-
-//reset bias weights
-resetBias = () => {
- weightLftUp = weightDiagonal;
- weightCtrUp = weightOrtho;
- weightRgtUp = weightDiagonal;
- weightLftCr = weightOrtho;
- weightCtrCr = weightReset;
- weightRgtCr = weightOrtho;
- weightLftDn = weightDiagonal;
- weightCtrDn = weightOrtho;
- weightRgtDn = weightDiagonal;
-}
-
-//calculate new bias weights
-calcBias = (bias) => {
-
- resetBias();
-
- let total = 0;
- total += weightLftUp = weightDiagonal + calcBiasIndiv(dirLftUp, bias, weightDiagonal);
- total += weightCtrUp = weightOrtho + calcBiasIndiv(dirCtrUp, bias, weightOrtho);
- total += weightRgtUp = weightDiagonal + calcBiasIndiv(dirRgtUp, bias, weightDiagonal);
- total += weightLftCr = weightOrtho + calcBiasIndiv(dirLftCr, bias, weightOrtho);
- //total += weightCtrCr = weightReset;
- total += weightRgtCr = weightOrtho + calcBiasIndiv(dirRgtCr, bias, weightOrtho);
- total += weightLftDn = weightDiagonal + calcBiasIndiv(dirLftDn, bias, weightDiagonal);
- total += weightCtrDn = weightOrtho + calcBiasIndiv(dirCtrDn, bias, weightOrtho);
- total += weightRgtDn = weightDiagonal + calcBiasIndiv(dirRgtDn, bias, weightDiagonal);
-
- weightLftUp /= total;
- weightCtrUp /= total;
- weightRgtUp /= total;
- weightLftCr /= total;
-
- weightRgtCr /= total;
- weightLftDn /= total;
- weightCtrDn /= total;
- weightRgtDn /= total;
-}
-
-//calculate individual bias weight
-calcBiasIndiv = (dir, bias, baseWeight) =>
-{
- const sumX = dir.x + bias.x;
- const sumY = dir.y + bias.y;
-
- return sqrt((sumX * sumX) + (sumY * sumY)) * baseWeight * 0.25;
-}
-
-getA = (c) => { return c.a; } //return cell a value
-getB = (c) => { return c.b; } //return cell b value
+// getA = (c) => { return c.a; } //return cell a value
+// getB = (c) => { return c.b; } //return cell b value
reactionA = (a, b) => { return a * b * b * -1;} //reaction function for cell a value
reactionB = (a, b) => { return a * b * b;} //reaction function for cell b value
feed = (a) => { return feedRate * (1.0 - a); } //feed function
@@ -253,7 +418,7 @@ drawPixels = () => {
const index = (uiWidth + x + y * totalWidth) * 4;
//const index = (uiWidth + x + y * w) * 4;
const cell = gridNext[x][y];
- const value = constrain(floor((cell.a - cell.b) * 255.0), 0, 200);
+ const value = constrain(floor((cell.a - cell.b) * 255.0), 0, 255);
pixels[index + 0] = value; //r
pixels[index + 1] = value; //g
@@ -265,6 +430,66 @@ drawPixels = () => {
updatePixels();
}
+drawUILabels = () => {
+
+ const textYOffset = sliderStepY * 0.25;
+
+ noStroke();
+ fill(0);
+ textSize(12);
+ textFont('consolas');
+
+ textWrap(WORD);
+ text("Gray Scott vs. Perlin Noise \n\n What happens when reaction diffusion is subjected to external forces?", sliderOffsetX, sliderOffsetX, sliderWidth);
+
+ text("noise scale: " + noiseScalar, sliderOffsetX, titleOffsetY + sliderStepY - textYOffset);
+ text("noise magnitude: " + vecScalar, sliderOffsetX, titleOffsetY + sliderStepY * 2 - textYOffset);
+ text("feed rate: " + feedRate, sliderOffsetX, titleOffsetY + sliderStepY * 3 - textYOffset);
+ text("kill rate: " + killRate, sliderOffsetX, titleOffsetY + sliderStepY * 4 - textYOffset);
+ text("speed: " + timeScalar, sliderOffsetX, titleOffsetY + sliderStepY * 5 - textYOffset);
+ text("brush diameter: " + paintRangeScalar, sliderOffsetX, titleOffsetY + sliderStepY * 6 - textYOffset);
+ text("feed/kill presets", sliderOffsetX, titleOffsetY + sliderStepY * 7 - textYOffset);
+}
+
+drawVecGrid = () => {
+
+ stroke(0);
+ //line(0, 0, mouseX, mouseY);
+
+ for(let xStep = 0; xStep < gridVec.length; xStep++)
+ {
+ const xCtr = uiWidth + (xStep * vecStep) + (vecStep * 0.5);
+
+ //console.log(xCtr);
+
+ for(let yStep = 0; yStep < gridVec[xStep].length; yStep++)
+ {
+ const yCtr = (yStep * vecStep) + (vecStep * 0.5);
+
+ //if(xStep == 0) console.log(xCtr + ", " + yCtr);
+
+ const vec = gridVec[xStep][yStep];
+ const dX = vec.x * vecStep * vecScalar * 10;
+ const dY = vec.y * vecStep * vecScalar * 10;
+
+ line(xCtr - dX, yCtr - dY, xCtr + dX, yCtr + dY);
+ }
+ }
+}
+
+drawPaintRadius = () =>{
+ if(mouseX > uiWidth && mouseX < totalWidth && mouseY > 0 && mouseY < h)
+ {
+ noFill();
+ stroke(0);
+
+ let dim = w;
+ if(dim > h) dim = h;
+
+ circle(mouseX, mouseY, paintRangeScalar * dim);
+ }
+}
+
//replace current grid with future grid
step = () => {
const toDrawOver = gridNow;
@@ -274,25 +499,30 @@ step = () => {
//checks for paint input
paintCheck = () => {
- if(mouseIsPressed) paint(mouseX, mouseY, paintRangeScalar);
+ if(mouseIsPressed) paint(mouseX, mouseY, paintRangeScalar, 1); //TODO: erase functionality
}
//applies paint input
-paint = (mX, mY, rangeScalar) => {
+paint = (mX, mY, rangeScalar, paintOrErase) => {
let dim = w;
if(dim > h) dim = h;
-
+
+ //console.log(mX + ", " + mY);
+
mX -= uiWidth;
+ //check if the mouse is completely off the canvas in terms of radius
+ if(mX < 0 || mX > w || mY < 0 || mY > h) return;
+
const radius = floor(dim * rangeScalar * 0.5);
let x0 = floor(mX - radius);
let x1 = floor(mX + radius);
let y0 = floor(mY - radius);
let y1 = floor(mY + radius);
- //check if the mouse is completely off the canvas in terms of radius
- if(x1 < 0 || x0 > w || y1 < 0 || y0 > h) return;
+ // //check if the mouse is completely off the canvas in terms of radius
+ // if(x1 < 0 || x0 > w || y1 < 0 || y0 > h) return;
if(x0 < 0) x0 = 0;
if(x1 > w) x1 = w;
@@ -308,43 +538,29 @@ paint = (mX, mY, rangeScalar) => {
const d = dist(x, y, mX, mY);
if(d > radius) continue;
-
- const vLinear = (radius - d) / radius;
- //const vPow = vLinear * vLinear * vLinear * 0.25;
- //const vGaussian = exp(vLinear * vLinear * -1);
- const vExp = map(exp(vLinear), 0, 15, 0, 1);
- const v = vExp;
-
- if( v > gridNow[x][y].b) gridNow[x][y].b = v;
+ //else if(d < radius * 0.1) gridNow[x][y].b = 1 * paintOrErase;
+ else
+ {
+ const vLinear = (radius - d) / radius;
+ //const vPow = vLinear * vLinear * vLinear * 0.25;
+ //const vGaussian = exp(vLinear * vLinear * -1);
+ const vExp = map(exp(vLinear), 0, 10, 0, 1);
+ const v = vExp;
+
+ if( v > gridNow[x][y].b) gridNow[x][y].b = v * paintOrErase;
+ }
}
}
}
-//cell class
-class Cell {
- constructor(x, y, a, b)
- {
- this.x = x;
- this.y = y;
- this.a = a;
- this.b = b;
-
- this.set = (a, b) =>
- {
- this.a = constrain(a, 0, 1);
- this.b = constrain(b, 0, 1);
- }
- }
-}
-
-//pick up here! Build out bias vector UI
+// //pick up here! Build out bias vector UI
-//TEMP: keyboard bias input for testing
-const biasStep = 0.1;
-function keyPressed() {
- if(key == 'w') updateBias(createVector(0, -biasStep));
- if(key == 'a') updateBias(createVector(-biasStep, 0));
- if(key == 's') updateBias(createVector(0, biasStep));
- if(key == 'd') updateBias(createVector(biasStep, 0));
-}
\ No newline at end of file
+// //TEMP: keyboard bias input for testing
+// const biasStep = 0.1;
+// function keyPressed() {
+// if(key == 'w') updateBias(createVector(0, -biasStep));
+// if(key == 'a') updateBias(createVector(-biasStep, 0));
+// if(key == 's') updateBias(createVector(0, biasStep));
+// if(key == 'd') updateBias(createVector(biasStep, 0));
+// }
\ No newline at end of file
diff --git a/public/style/style.css b/public/style/style.css
new file mode 100644
index 0000000..8b2c273
--- /dev/null
+++ b/public/style/style.css
@@ -0,0 +1,23 @@
+body {
+ font-family: 'consolas';
+ background-color: white;
+ color: black;
+ /* padding:25%; */
+}
+
+/* main {
+ margin: auto;
+} */
+
+/* #p5Canvas {
+ margin: auto;
+} */
+
+/* #mySlider {
+ position: relative;
+} */
+
+input {
+ background-color: white;
+ color:black
+}
\ No newline at end of file