final int meshElementSpacing = 5*mult;
final int nBezSamples = 75*mult;
final float diamondScale = 0.003625f * mult;
final int nResamples = 75;
final int nFadeoutFrames = 80;
boolean prevMouseDownState;
float splineStrength = 10.0F;
ArrayList pathBezArray[];
boolean showInfo = false;
fonty = loadFont("EBGaramond12-Italic.ttf");
mouseIsDown = prevMouseDownState = false;
pathArray = new ArrayList[nActual];
pathBezArray = new ArrayList[nActual];
drawArray = new PVector[nActual][nResamples];
precomputeBezierArrays();
for(int i = 0; i < nActual; i++){
pathArray[i] = new ArrayList();
pathBezArray[i] = new ArrayList();
for(int p =0; p<nResamples; p++)
drawArray[i][p] = new PVector();
void precomputeBezierArrays(){
bt = new float[nBezSamples];
bt2 = new float[nBezSamples];
bt3 = new float[nBezSamples];
onemt = new float[nBezSamples];
onemt2 = new float[nBezSamples];
onemt3 = new float[nBezSamples];
bto2 = new float[nBezSamples];
bt2o = new float[nBezSamples];
for(int p = 0; p<nBezSamples; p++){
bt[p] = (float)p / (float)(nBezSamples-1);
onemt2[p] = onemt[p] * onemt[p];
onemt3[p] = onemt[p] * onemt2[p];
bto2[p] = 3.0F * bt[p] * onemt2[p];
bt2o[p] = 3.0F * bt2[p] * onemt[p];
prevMouseDownState = mouseIsDown;
ArrayList path = pathArray[currentPathIndex];
for (int i=1; i<psm1; i++){
PVector v0 = (PVector) path.get(i-1);
PVector v1 = (PVector) path.get(i );
PVector v2 = (PVector) path.get(i+1);
float px = A*v0.x + B*v1.x + A*v2.x;
float py = A*v0.y + B*v1.y + A*v2.y;
float pz = A*v0.z + B*v1.z + A*v2.z;
((PVector)path.get(i)).set(px,py,pz);
ArrayList bPath = pathBezArray[currentPathIndex];
PVector resamplePath[] = drawArray[currentPathIndex];
calculateBezierPath(currentPathIndex);
resampleVector(bPath, resamplePath);
fromIndex = ((currentPathIndex - 1) + offset + nPaths) % nPaths;
toIndex = (currentPathIndex + offset + nPaths) % nPaths;
drawStem(pathBezArray[toIndex]);
drawStem(pathBezArray[fromIndex]);
if(nFilledPaths != 1 || currentPathIndex != 1) {
if(nFilledPaths < nPaths){
for(int i=0; i<=num; i++) {
fromIndex = ((i - 1) + offset + nPaths) % nPaths;
toIndex = (i + offset + nPaths) % nPaths;
PVector fromArray[] = drawArray[fromIndex];
PVector toArray[] = drawArray[toIndex];
if(nPaths == 2 || currentPathIndex != (fromIndex - offset) % nPaths) {
drawMesh(fromArray, toArray);
for (int p = 0; p <= nFilledPaths; p++) {
drawStem(pathBezArray[p]);
float py = height*(1-0.618);
text("Meshy by Golan Levin, 1998-2006", width/2, height/2 );
text("Meshy by Golan Levin, 1998-2006", width/2, py - 30);
text("Draw two marks to begin", width/2, py);
float dif = (float)(millis() - begunTime);
text("Meshy by Golan Levin, 1998-2006", width/2, height/2);
text("Meshy by Golan Levin, 1998-2006", width/2, py - 30);
text("Draw two marks to begin", width/2, py);
ArrayList path = pathArray[currentPathIndex];
ArrayList bPath = pathBezArray[currentPathIndex];
addPointToVector(path, mouseX, mouseY);
PVector resamplePath[] = drawArray[currentPathIndex];
calculateBezierPath(currentPathIndex);
resampleVector(bPath, resamplePath);
currentPathIndex = nFilledPaths % nPaths;
ArrayList path = pathArray[currentPathIndex];
ArrayList bPath = pathBezArray[currentPathIndex];
float cy = height * 0.618;
float r = height * rads[c];
float fullRound = TWO_PI * (float)(nResamples+1)/(float)nResamples;
for (int i=0; i<nResamples; i++){
float t = (float)i/(float)(nResamples-1) * fullRound;
float x = (cx + r * cos(t + rotang));
float y = (cy + r * sin(t + rotang));
addPointToVector(path, x, y);
PVector resamplePath[] = drawArray[currentPathIndex];
calculateBezierPath(currentPathIndex);
resampleVector(bPath, resamplePath);
currentPathIndex = nFilledPaths % nPaths;
framesSinceMouseUp = nFadeoutFrames;
ArrayList path = pathArray[currentPathIndex];
ArrayList bPath = pathBezArray[currentPathIndex];
addPointToVector(path, mouseX, mouseY);
PVector resamplePath[] = drawArray[currentPathIndex];
calculateBezierPath(currentPathIndex);
resampleVector(bPath, resamplePath);
currentPathIndex = nFilledPaths % nPaths;
ArrayList path = pathArray[currentPathIndex];
ArrayList bPath = pathBezArray[currentPathIndex];
addPointToVector(path, mouseX, mouseY);
addPointToVector(path, mouseX + 1, mouseY + 1);
calculateBezierPath(currentPathIndex);
PVector resamplePath[] = drawArray[currentPathIndex];
resampleVector(bPath, resamplePath);
float getPathLength(ArrayList path){
int nPathPoints = path.size();
for(int i = 0; i < nPathPoints - 1; i++){
PVector lower = (PVector)path.get(i);
PVector upper = (PVector)path.get(i + 1);
float Dx = upper.x - lower.x;
float Dy = upper.y - lower.y;
float segLength = (float)Math.sqrt(Dx * Dx + Dy * Dy);
void calculateBezierPath(int pathIndex){
ArrayList path = pathArray[currentPathIndex];
ArrayList bPath = pathBezArray[currentPathIndex];
int nSourcePts = path.size();
int nspm1 = nSourcePts - 1;
PVector p0 = new PVector();
PVector p1 = new PVector();
PVector p2 = new PVector();
PVector p3 = new PVector();
PVector last_pt = new PVector();
PVector next_pt = new PVector();
for(int g = 0; g < nSourcePts; g++) {
PVector pt = new PVector();
PVector src = (PVector)path.get(g);
for(int i = 0; i < nSourcePts; i++) {
p3 = (PVector)path.get(1);
p0 = (PVector)path.get(0);
next_pt = (PVector)path.get(2);
last_pt.set(p0.x - (p3.x - p0.x) / 4.0F, p0.y - (p3.y - p0.y) / 4.0F, 0.0F);
next_pt = (PVector)path.get(1);
p3 = (PVector)path.get(0);
p0.set(p3.x - (next_pt.x - p3.x) / 4.0F, p3.y - (next_pt.y - p3.y) / 4.0F, 0.0F);
last_pt.set(p3.x - (next_pt.x - p3.x) / 2.0F, p3.y - (next_pt.y - p3.y) / 2.0F, 0.0F);
p3 = (PVector)path.get(i);
p0 = (PVector)path.get(i - 1);
last_pt = (PVector)path.get(i - 2);
p3 = (PVector)path.get(i);
p0 = (PVector)path.get(i - 1);
last_pt = (PVector)path.get(i - 2);
next_pt = (PVector)path.get(i + 1);
float dx0 = p0.x - last_pt.x;
float dy0 = p0.y - last_pt.y;
float d0 = (float)Math.sqrt(dx0 * dx0 + dy0 * dy0);
float d1 = (float)Math.sqrt(dx1 * dx1 + dy1 * dy1);
float dx2 = next_pt.x - p3.x;
float dy2 = next_pt.y - p3.y;
float d2 = (float)Math.sqrt(dx2 * dx2 + dy2 * dy2);
float dAtp0 = (d0 + d1) / 2.0F;
float dAtp3 = (d1 + d2) / 2.0F;
p0.set(p0.x, p0.y, dAtp0);
p3.set(p3.x, p3.y, dAtp3);
float tan_inx = (p3.x - last_pt.x) / bias;
float tan_iny = (p3.y - last_pt.y) / bias;
float tan_inz = (p3.z - d0) / bias;
float tan_outx = (next_pt.x - p0.x) / bias;
float tan_outy = (next_pt.y - p0.y) / bias;
float tan_outz = (d2 - p0.z) / bias;
float p1x = p0.x + tan_inx;
float p1y = p0.y + tan_iny;
float p1z = p0.z + tan_inz;
float p2x = p3.x - tan_outx;
float p2y = p3.y - tan_outy;
float p2z = p3.z - tan_outz;
for(int j = 0; j < nBez; j++){
float t = (float)j / (float)nBez;
PVector pt = calculatePureBezierVec3f(t, p0, p1, p2, p3);
void addPointToVector(ArrayList path, float x, float y){
PVector pt = mouseToGeometry(x, y);
void resampleVector(ArrayList path, PVector resampledPath[]) {
int nResampledPoints = nResamples;
int nPathPoints = path.size();
float totalPathLength = getPathLength(path);
float RSL = totalPathLength / (float)nResampledPoints;
float prevRemainder = RSL;
for(p = 0; p < nResampledPoints; p++){
PVector lower = (PVector)path.get(0);
float px = lower.x + (float)p * 0.0001F;
float py = lower.y + (float)p * 0.0001F;
float pz = lower.z + (float)p * 0.0001F;
resampledPath[p].set(px, py, pz);
for(int i = 0; i < nPathPoints - 1; i++){
PVector lower = (PVector)path.get(i);
PVector upper = (PVector)path.get(i + 1);
float Dx = upper.x - lower.x;
float Dy = upper.y - lower.y;
float Dz = upper.z - lower.z;
float segLength = (float)Math.sqrt(Dx * Dx + Dy * Dy);
float dx = Dx / segLength;
float dy = Dy / segLength;
float neededSpace = RSL - prevRemainder;
float px = lower.x + neededSpace * dx;
float py = lower.y + neededSpace * dy;
float pz = lower.z + Dz / 2.0F;
if(p < nResampledPoints) {
resampledPath[p].set(px, py, pz);
remainder -= neededSpace;
int nPtsToDo = (int)(remainder / RSL);
for(int d = 0; d < nPtsToDo; d++) {
if(p < nResampledPoints) {
resampledPath[p].set(px, py, pz);
prevRemainder = remainder;
void drawStem(ArrayList path) {
if(framesSinceMouseUp < nFadeoutFrames) {
float col = (float)Math.max(0, nFadeoutFrames - framesSinceMouseUp) / (float)nFadeoutFrames;
for(int i = 0; i < (nSegs = path.size()); i++) {
PVector pt = (PVector)path.get(i);
float c = ((float)i / (float)nSegs) * col;
void drawMesh(PVector fromArray[], PVector toArray[]){
int spacing = meshElementSpacing;
int nbsm1 = nBezSamples-1;
int nrsm1 = nResamples-1;
int roundSamp = round(currentSample);
pulse = 0.05 + 0.85*(0.5*(1.0 + cos(PI + millis()/1800.0)));
float nrsm1f = (float)nrsm1;
float splBreath = 2.5*sin(millis()/6000.0);
for(int i=0; i<nrsm1; i++) {
float splNoise = 1.0*(noise(i/nrsm1f + millis()/4000.0) - 0.5);
splineStrength = 10.0 + splNoise + splBreath;
PVector p1a = fromArray[i];
PVector p1b = fromArray[i + 1];
PVector p4a = toArray[i];
PVector p4b = toArray[i + 1];
float p1x = (p1a.x + p1b.x) * 0.5F;
float p1y = (p1a.y + p1b.y) * 0.5F;
float p1z = (p1a.z + p1b.z) * 0.5F;
float p4x = (p4a.x + p4b.x) * 0.5F;
float p4y = (p4a.y + p4b.y) * 0.5F;
float p4z = (p4a.z + p4b.z) * 0.5F;
float p2x = p1x + (p1a.y - p1b.y) * splineStrength;
float p2y = p1y + (p1b.x - p1a.x) * splineStrength;
float p2z = p1z + (p1b.z - p1a.z) * splineStrength;
float p3x = p4x - (p4a.y - p4b.y) * splineStrength;
float p3y = p4y - (p4b.x - p4a.x) * splineStrength;
float p3z = p4y - (p4b.z - p4a.z) * splineStrength;
for(int s = 0; s <nbsm1; s++) {
if(s % spacing == 0 && ((s + roundSamp + 1) % nBezSamples) != 0){
int sa = (s + roundSamp) % nBezSamples;
int sb = (s + roundSamp + 1) % nBezSamples;
float onemt3sa = onemt3[sa];
float onemt3sb = onemt3[sb];
float pax = onemt3sa * p1x + bto2sa * p2x + bt2osa * p3x + bt3sa * p4x;
float pay = onemt3sa * p1y + bto2sa * p2y + bt2osa * p3y + bt3sa * p4y;
float paz = onemt3sa * p1z + bto2sa * p2z + bt2osa * p3z + bt3sa * p4z;
float pbx = onemt3sb * p1x + bto2sb * p2x + bt2osb * p3x + bt3sb * p4x;
float pby = onemt3sb * p1y + bto2sb * p2y + bt2osb * p3y + bt3sb * p4y;
float pbz = onemt3sb * p1z + bto2sb * p2z + bt2osb * p3z + bt3sb * p4z;
sizef = (paz + pbz) * diamondScale;
float pbmax = (pbx - pax) * sizef;
float pbmay = (pby - pay) * sizef;
float pamby = (pay - pby) * sizef;
float b1x = (pax - pbmax * 2.0F);
float b1y = (pay - pbmay * 2.0F);
float b2x = (pbx + pbmax * 2.0F);
float b2y = (pby + pbmay * 2.0F);
c = (float)(1.0 - cos(((float)sa / (float)nBezSamples) * TWO_PI)) * 0.5F;
stroke(255,255,255, c*255.0f*pulse);
float avx = (pax + pbx) * 0.5F;
float avy = (pay + pby) * 0.5F;
float b4x = (avx + pamby);
float b4y = (avy + pbmax);
float b3x = (avx - pamby);
float b3y = (avy - pbmax);
PVector mouseToGeometry(float x, float y){
PVector pt = new PVector();
PVector calculatePureBezierVec3f(float t, PVector p1, PVector p2, PVector p3, PVector p4){
float onemt2 = onemt * onemt;
float onemt3 = onemt * onemt2;
PVector pt = new PVector();
float ptx = onemt3 * p1.x + 3.0F * t * onemt2 * p2.x + 3.0F * t2 * onemt * p3.x + t3 * p4.x;
float pty = onemt3 * p1.y + 3.0F * t * onemt2 * p2.y + 3.0F * t2 * onemt * p3.y + t3 * p4.y;
float ptz = onemt3 * p1.z + 3.0F * t * onemt2 * p2.z + 3.0F * t2 * onemt * p3.z + t3 * p4.z;