Skip to content

Instantly share code, notes, and snippets.

@dribnet
Forked from uwcc/.block
Last active September 23, 2021 03:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dribnet/fadd7007eff40c7b24879840745bbddb to your computer and use it in GitHub Desktop.
Save dribnet/fadd7007eff40c7b24879840745bbddb to your computer and use it in GitHub Desktop.
MDDN 342 2021 Assignment 3: Data Mappings
license: mit

2021 MDDN342 Assignment 3: Face Mappings

Debugging Jamie's faces.

{
"commits": [
{
"sha": "0c6c3cfbf221d991635b1c1946ee777533194f47",
"name": "Face Logic"
},
{
"sha": "8973b99fa773cba2f2575f30c11cf5cff14cd51d",
"name": "Train Neighbors and Quiz"
},
{
"sha": "7adbeed1dabb00bc073f3a59144ca9d139875333",
"name": "first version of training"
},
{
"sha": "0e61ad32bbd42601bd25620421c35100ab813119",
"name": "added image to sample_images.json"
},
{
"sha": "21777e8da0a797bac8f042b3b509266012b28dc1",
"name": "using face positions"
},
{
"sha": "a683736618d1513f1c2477cfe0eade4a202dac8d",
"name": "mickey mouse example"
}
]
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script>
<script src="https://d3js.org/d3-random.v1.min.js"></script>
<script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="z_focused_random.js"></script>
<script language="javascript" type="text/javascript" src="p5.func.js"></script>
<script type="text/javascript" src="LZWEncoder.js"></script>
<script type="text/javascript" src="NeuQuant.js"></script>
<script type="text/javascript" src="GIFEncoder.js"></script>
<script type="text/javascript" src="b64.js"></script>
<script type="text/javascript" src="z_recorder.js"></script>
<script language="javascript" type="text/javascript" src="simplex-noise.js"></script>
<script language="javascript" type="text/javascript" src="canvas_size.js"></script>
<script language="javascript" type="text/javascript" src="draw_one_frame.js"></script>
<script language="javascript" type="text/javascript" src="anim_runner.js"></script>
<style> body {padding: 0; margin: 0;} </style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
</div>
</table>
<br>
<pre>
keys:
spacebar => toggle debugZoom
d => toggle debug view
r => start recording
1,2,3 => change framerate
! = screen grab files
</pre>
<a href="sketch.html">sketch</a><br>
<a href="draw_one_frame.js">source code</a><br>
<a href="preview.jpg">preview image</a><br>
<a href="index.html">(anim [this one])</a><br>
</body>
// these can be customized
const debugViewText = "#ff0000";
const debugZoomBackground = "#555588"
const debugZoomScale = 0.5;
// this can be modified after we discuss in lecture
const buffersPerFrame = 1;
// probably best not to modify anything below this line
const frameMax = 96;
let recording = false;
let gifRecorder = null;
let debugZoom = false;
let debugView = false;
let stickFrame = 0;
// *note: canvasWidth and canvasHeight will be defined before this script runs)
function setup () {
let main_canvas = createCanvas(canvasWidth,canvasHeight);
let r = random(100);
main_canvas.parent('canvasContainer');
frameRate(24 * buffersPerFrame);
}
function mousePressed(){
}
function draw () {
let animation_max_frames = frameMax * buffersPerFrame;
let sticky_max_frames = animation_max_frames + stickFrame;
let cur_frame = frameCount % sticky_max_frames;
if (cur_frame >= animation_max_frames) {
cur_frame = 0;
}
let cur_frac = map(cur_frame, 0, animation_max_frames, 0, 1);
background(debugZoomBackground);
push();
if(debugZoom) {
translate(0.5 * width, 0.5 * height);
scale(debugZoomScale);
translate(0.5 * -width, 0.5 * -height);
}
draw_one_frame(cur_frac);
pop();
if(debugView) {
textSize(28);
fill(debugViewText);
text("" + (cur_frame/buffersPerFrame).toFixed(2) + " / " +
(animation_max_frames/buffersPerFrame).toFixed(2) + " = " +
cur_frac.toFixed(2), 50, 50);
}
if(recording) {
textSize(24);
gifRecorder.addBuffer();
}
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
if (key == ' ') {
debugZoom = !debugZoom;
}
if (key == 'd') {
debugView = !debugView;
}
if (key == '1') {
frameRate(1);
stickFrame = 0;
}
if (key == '2') {
frameRate(5);
stickFrame = 5;
}
if (key == '3') {
frameRate(30);
stickFrame = 0;
}
if (key == 'r') {
if (recording==false){
recording = true;
gifRecorder = new p5recorder (frameMax, 'wallpaper.gif', buffersPerFrame);
}
}
}
function encode64(input) {
var output = "", i = 0, l = input.length,
key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
chr1, chr2, chr3, enc1, enc2, enc3, enc4;
while (i < l) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) enc3 = enc4 = 64;
else if (isNaN(chr3)) enc4 = 64;
output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4);
}
return output;
}
var canvasWidth = 960;
var canvasHeight = 540;
const ease = new p5.Ease();
function draw_one_frame(cur_frac) {
var addXSingle = width / 960;
var addYSingle = height / 520;
fill(255);
rect(0, 0, width, height);
//drawing the background gradient
c1 = color(240, 254, 254); //very light blue
c2 = color(154, 242, 245); //darker blue
for (let yBG = 0; yBG < height + 1; yBG++) {
n = map(yBG, 0, height, 0, 1);
let newc = lerpColor(c1, c2, n);
stroke(newc);
line(0, yBG, width, yBG);
}
let cur_x = map(cur_frac, 0, 1, 0, width) //- half_width;
//all of my colours to use when I call a leaf function!
var longLeafFill1 = color(167, 212, 138);
var longLeafFill2 = color(134, 181, 103);
var longLeafStroke1 = color(108, 148, 99);
var longLeafFill3 = color(92, 145, 84); //saturated dark green
var longLeafStroke3 = color(92, 145, 84);
var longLeafFill4 = color(49, 94, 89); //darkest green
var longLeafStroke4 = color(49, 94, 89);
var longLeafFill5 = color(83, 144, 111);
var fatLeafFill = color(200, 231, 128);
var darkBlueGreen = color(71, 125, 99);
var teal = color(87, 141, 122);
var slate_green = color(91, 151, 110);
var dull_greren = color(109, 171, 94);
var muted_green = color(102, 159, 90);
var pale_olive_green = color(160, 213, 148);
var pale_olive = color(173, 202, 151);
var flower_fill = color(230, 251, 150);
var medium_spring_bud = color(191, 225, 129);
var oxley = color(105, 159, 132);
var limed_spruce = color(57, 69, 83);
var skinnyLongLeafCol = color(103, 142, 149);
var secondFlowerLeaf = color(115, 166, 137);
let randRoat = getNoiseValue(0, 0, cur_frac, "randRoat", -.3, .3, .1); //random jitter on the long leaf using noise
push(); //fat leaf right at the back on the right
translate(width / 1.23, height / 1);
drawFatLeaf(70, 0.6, -1, darkBlueGreen);
pop();
push(); //fat leaf right at the back on the left
translate(width * .16, height * 1.07);
drawFatLeaf(-43, .8, -1, darkBlueGreen);
pop();
//leaves on the right behind the flowers
push();
translate(width / 1.4, height * 1.04);
drawLongLeaf(0, 0, 1.2, 20, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width / 1.28, height * 1.1);
drawLongLeaf(0, 0, 1.05, 23, longLeafFill3, longLeafStroke3);
pop();
push();
translate(width / 1.45, height * 1.02);
drawLongLeaf(0, 0, 1.05, 0, longLeafFill5, longLeafFill5);
pop();
//setting up the flowers to move back and forth
let going_right = true;
let amount_across = 0;
if (cur_frac < 0.5) {
going_right = true;
amount_across = cur_frac * 2;
} else {
going_right = false;
amount_across = (cur_frac - 0.5) * 2;
}
const ease_amount_across = ease.doubleQuadraticSigmoid(amount_across);
const ease_amount_across_fatLeaf = ease.circularFillet(amount_across);
const ease_amount_acrosslongLeaf = ease.normalizedLogitSigmoid(amount_across);
if (going_right) {
flowerSway = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * 2)
flower2Sway = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * .9)
fLSway = map(ease_amount_across_fatLeaf, 0, 0.5, addXSingle * 0, addXSingle * 0.3)
longLeafSway = map(ease_amount_acrosslongLeaf, 0, 0.5, addXSingle * 0, addXSingle * 0.2)
} else {
flowerSway = map(ease_amount_across, 0.5, 1, addXSingle * 2, addXSingle * 0)
flower2Sway = map(ease_amount_across, 0.5, 1, addXSingle * .9, addXSingle * 0)
fLSway = map(ease_amount_across_fatLeaf, 0.5, 1, addXSingle * 0.3, addXSingle * 0)
longLeafSway = map(ease_amount_acrosslongLeaf, 0.5, 1, addXSingle * 0.2, addXSingle * 0)
}
//drawing long leaf with the jitter
push();
translate(width / 1.6, height / 1.02);
rotate(0);
drawLongLeaf(0, 0, 1.2, (randRoat / 3) + longLeafSway, longLeafFill1, longLeafStroke1);
pop();
//setting up the flowers
var flower1StartX = width / 1.2 + flowerSway; //flower sway makes the flower bud AND the stalk move
var flower1StartY = height / 4.9;
var flower2StartX = width *.92 + flower2Sway;
var flower2StartY = height *.33974;
strokeWeight(width / 960 * 2);
stroke(93, 107, 54);
noFill();
beginShape(); //flower 1 stalk
curveVertex(flower1StartX, flower1StartY);
curveVertex(flower1StartX, flower1StartY);
curveVertex(width / 1.2, height *.6);
curveVertex(width / 1.3, height*.89);
curveVertex(width / 1.3, height*.89);
endShape();
//draw the actual flower (biggest one)
push();
translate(flower1StartX, flower1StartY);
rotate(-25);
scale(1.4);
drawFlower(0, 0, flower_fill); //bigger top flower
pop();
//drawing leaves on the biggest flowerr
push();
translate(width / 1.196 + (flowerSway / 2), height / 2.3); //top down
drawSkinnyLongLeaf(-40, .9, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.2), height / 2.15);
drawSkinnyLongLeaf(35, 1, skinnyLongLeafCol);
pop();
push();
translate(width / 1.196 + (flowerSway / 2.6), height / 2.05);
drawSkinnyLongLeaf(-60, 1.1, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.8), height / 1.9);
drawSkinnyLongLeaf(55, 1.08, skinnyLongLeafCol);
pop();
push();
translate(width / 1.196 + (flowerSway / 2.9), height / 1.7);
drawSkinnyLongLeaf(-57, 1.25, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.8), height / 1.65);
drawSkinnyLongLeaf(59, 1.25, skinnyLongLeafCol);
pop();
push();
translate(width / 1.215, height / 1.55);
drawSkinnyLongLeaf(-50, 1.3, skinnyLongLeafCol);
pop();
push();
translate(width / 1.223, height / 1.4);
drawSkinnyLongLeaf(-69, 1.5, skinnyLongLeafCol);
pop();
push();
translate(width / 1.27, height / 1.21);
drawSkinnyLongLeaf(-62, 1.5, skinnyLongLeafCol);
pop();
push(); ////////leaves in the middle of the screen///////
translate(width * .49, height * 1.19);
drawShortWavyLeaf(longLeafFill3, longLeafFill3, 13, 3);
pop();
push();
translate(width * .604, height * 1.047);
drawShortWavyLeaf(teal, oxley, -17, 2.7);
pop();
push();
translate(width * .2, height * 1.1);
drawShortWavyLeaf(longLeafFill2, longLeafFill2, -20, 3);
pop();
//second flower stalk
strokeWeight(width / 960 * 2);
stroke(93, 107, 54);
noFill();
beginShape(); //flower 2 stalk
curveVertex(flower2StartX, flower2StartY);
curveVertex(flower2StartX, flower2StartY);
curveVertex(width *.896, height *.52);
curveVertex(width / 1.3, height *.89);
curveVertex(width / 1.3, height *.89);
endShape();
//second flower
push();
translate(flower2StartX, flower2StartY);
rotate(25);
scale(1);
drawFlower(0, 0, flower_fill); //lower smaller flower
pop();
//ssecond flower leaves
push();
translate(width*.908 + (flower2Sway / 4), height / 2.18);
drawSkinnyLongLeaf(-28, .84, secondFlowerLeaf);
pop();
push();
translate(width *.906 + (flower2Sway / 2.8), height / 2.1);
drawSkinnyLongLeaf(48, .87, secondFlowerLeaf);
pop();
push();
translate(width / 1.13, height / 1.84);
drawSkinnyLongLeaf(-21, 1, secondFlowerLeaf);
pop();
push();
translate(width / 1.15, height / 1.69);
drawSkinnyLongLeaf(70, 1.07, secondFlowerLeaf);
pop();
push();
translate(width / 1.17, height / 1.55);
drawSkinnyLongLeaf(-33, 1.2, secondFlowerLeaf);
pop();
push();
translate(width / 1.2, height / 1.4);
drawSkinnyLongLeaf(63, 1.3, secondFlowerLeaf);
pop();
//draw the two fat leaves in front of the flowers on the RIGHT
push();
translate(width / 1.29, height * 1.03);
drawFatLeaf(45 + fLSway, 0.9, 1, fatLeafFill);
pop();
push();
translate(width / 1.43, height * 1.1);
drawFatLeaf(-15 + (fLSway * 4), 0.9, -1, fatLeafFill);
pop();
const ease_amount_across_fatLeaf2 = ease.circularArcThroughAPoint(amount_across);
const ease_amount_up_down = ease.doubleQuadraticSigmoid(amount_across);
if (going_right) {
flowerSway3 = map(ease_amount_across, 0, 0.5, addXSingle * .5, addXSingle * 0);
fatLeaf2Sway = map(ease_amount_across_fatLeaf2, 0, 0.5, addXSingle * 0.6, addXSingle * 0);
branchupdown = map(ease_amount_up_down, 0, 0.5, addXSingle * 0.6, addXSingle * 0)
} else {
flowerSway3 = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * .5);
fatLeaf2Sway = map(ease_amount_across_fatLeaf2, 0, 0.5, addXSingle * 0, addXSingle * 0.6);
branchupdown = map(ease_amount_up_down, 0.5, 1, addXSingle * 0, addXSingle * 0.6);
}
/////////behind shrt wavy leaves
push();
translate(width * .43, height * 1.04);
drawLongLeaf(0, 0, 1.18, -23, limed_spruce, limed_spruce);
pop();
push();
translate(width * .42, height * 1.03);
drawLongLeaf(0, 0, 1.1, 1, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width * .30, height * 1.03);
drawLongLeaf(0, 0, 1.2, -30 + longLeafSway / 2, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width * .37, height);
drawLongLeaf(0, 0, 1, -30, longLeafFill2, longLeafStroke1);
pop();
//fly on the left
let flyScale = 0.55;
let flyX;
//setting it up off-beat, so it grows starting at 0.3 cur frac and loops back to then (instead of 0-1)
if (cur_frac >= 0.3) {
flyScale = map(cur_frac, 0.3, 0.5, 0, 0.55);
}
if (cur_frac >= 0.5) {
flyScale = map(cur_frac, 0.5, 1, 0.55, 0.55);
}
if (cur_frac <= 0.3) {
flyScale = map(cur_frac, 0, 0.3, 0.55, 0);
}
if (cur_frac <= 0.3) { //this is for the flies movement
flyX = map(cur_frac, 0, 0.3, addXSingle * 200, addXSingle * 250)
} else if (cur_frac >= 0.3) {
flyX = map(cur_frac, 0.3, 1, addXSingle * 100, addXSingle * 200)
}
push(); //draw the actual fly
translate(width / 1.9 + flyX, height / 1.5); //centre of the screen
drawFly(0, 0, cur_frac, flyScale,1);
pop();
//////////short wavy leaves stalk////////////
stroke(52, 93, 88);
strokeWeight(addXSingle * 3);
noFill();
var endOfBranchX = width * .12;
var endOfBranchY = height / 3.9;
var strokeColWavy1 = color(42, 86, 79);
//main branch (going left)
beginShape();
curveVertex(width / 3, height / 1.7);
curveVertex(width / 3, height / 1.7);
curveVertex(width / 3.8, height / 4.4);
curveVertex(endOfBranchX, endOfBranchY + branchupdown);
curveVertex(endOfBranchX, endOfBranchY + branchupdown);
endShape();
//second branch going right
beginShape();
curveVertex(width * .31, height * .419);
curveVertex(width * .31, height * .419);
curveVertex(width * .34, height * .16);
curveVertex(width * .41, height * .1);
curveVertex(width * .41, height * .1);
endShape();
////first brranch leaves
push();
translate(endOfBranchX, endOfBranchY + branchupdown);
drawShortWavyLeaf(teal, strokeColWavy1, -80 - (branchupdown / 1.5), 1);
pop();
push();
translate(endOfBranchX + addXSingle * 6, endOfBranchY + addYSingle * -1 + branchupdown);
drawShortWavyLeaf(slate_green, slate_green, -120 + (branchupdown / 1.3), .8);
pop();
push();
translate(endOfBranchX + addXSingle * 20, endOfBranchY + addYSingle * -3 + (branchupdown / 1.2));
drawShortWavyLeaf(teal, strokeColWavy1, -170, .8);
pop();
push(); //////behind the other leaves
translate(endOfBranchX + addXSingle * 167, endOfBranchY + addYSingle * 40);
drawShortWavyLeaf(slate_green, slate_green, -80, 0.93);
pop();
push(); //////behind the other leaves on other branch
translate(endOfBranchX + addXSingle * 157, endOfBranchY + addYSingle * 10);
drawShortWavyLeaf(slate_green, slate_green, 19, 0.8);
pop();
push();
translate(endOfBranchX + addXSingle * 100, endOfBranchY + addYSingle * -25 + (branchupdown / 1.9));
drawShortWavyLeaf(teal, strokeColWavy1, -20 - (branchupdown / 2), .75);
pop();
push();
translate(endOfBranchX + addXSingle * 48, endOfBranchY + addYSingle * -20 + (branchupdown / 1.5));
drawShortWavyLeaf(teal, strokeColWavy1, -50 + (branchupdown / 1.8), .82);
pop();
push();
translate(endOfBranchX + addXSingle * 68, endOfBranchY + addYSingle * -20 + (branchupdown / 1.6));
drawShortWavyLeaf(teal, strokeColWavy1, -200 + (branchupdown / 2), .93);
pop();
push();
translate(endOfBranchX + addXSingle * 118, endOfBranchY + addYSingle * -25);
drawShortWavyLeaf(teal, strokeColWavy1, -180, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 180, endOfBranchY + addYSingle * 90);
drawShortWavyLeaf(teal, strokeColWavy1, -100, .94);
pop();
push();
translate(endOfBranchX + addXSingle * 190, endOfBranchY + addYSingle * 120);
drawShortWavyLeaf(teal, strokeColWavy1, 40, 1.06);
pop();
push();
translate(endOfBranchX + addXSingle * 196, endOfBranchY + addYSingle * 150);
drawShortWavyLeaf(teal, strokeColWavy1, -87, 1.1);
pop();
///////////second branch (going right)
push();
translate(endOfBranchX + addXSingle * 187, endOfBranchY + addYSingle * 80);
drawShortWavyLeaf(teal, strokeColWavy1, 60, .9);
pop();
push();
translate(endOfBranchX + addXSingle * 191, endOfBranchY + addYSingle * 40);
drawShortWavyLeaf(teal, strokeColWavy1, 50, 1);
pop();
push();
translate(endOfBranchX + addXSingle * 201, endOfBranchY + addYSingle * -20);
drawShortWavyLeaf(teal, strokeColWavy1, 70, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 191, endOfBranchY + addYSingle * 20);
drawShortWavyLeaf(teal, strokeColWavy1, -35, .86);
pop();
push();
translate(endOfBranchX + addXSingle * 207, endOfBranchY + addYSingle * -45);
drawShortWavyLeaf(teal, strokeColWavy1, -45, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 230, endOfBranchY + addYSingle * -71);
drawShortWavyLeaf(teal, strokeColWavy1, -25, .70);
pop();
push();
translate(endOfBranchX + addXSingle * 260, endOfBranchY + addYSingle * -81);
drawShortWavyLeaf(teal, strokeColWavy1, 5, .55);
pop();
push();
translate(endOfBranchX + addXSingle * 280, endOfBranchY + addYSingle * -84);
drawShortWavyLeaf(teal, strokeColWavy1, 28, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 280, endOfBranchY + addYSingle * -84);
drawShortWavyLeaf(teal, strokeColWavy1, 80, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 271, endOfBranchY + addYSingle * -80);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 271, endOfBranchY + addYSingle * -80);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 238, endOfBranchY + addYSingle * -73);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .59);
pop();
//fly 1 (LEFT faster fly)///
//this fly is moving 0-1
flyScale = 0.6;
if (cur_frac <= 0.3) {
flyScale = map(cur_frac, 0, 0.3, 0, 0.6);
} else if (cur_frac >= 0.7) {
flyScale = map(cur_frac, 0.7, 1, 0.6, 0);
}
flyX = map(cur_frac, 0, 1, addXSingle * 300, addXSingle * 0)
push();
translate(width / 5 + flyX, height / 3.4);
drawFly(0, 0, cur_frac, flyScale,-1);
pop();
//////in front of branches on the left
push();
translate(width * .45, height * 1.1);
drawLongLeaf(0, 0, 1, -24, dull_greren, muted_green);
pop();
//short leaves in front on the LEFT //////////////////////////
push();
translate(width * .41, height * 1.1);
drawFatLeaf(-20 + (fatLeaf2Sway / -10), 1, -1, pale_olive);
pop();
push();
translate(width * .43, height * 1.1);
drawFatLeaf(10 + (fatLeaf2Sway / 1.2), 0.9, 1, fatLeafFill);
pop();
push();
translate(width * .37, height * 1.1);
drawFatLeaf(-56 + (fatLeaf2Sway / 1.8), 0.9, -1, fatLeafFill);
pop();
////////bottom left flowers
let backFloStartX = width * .19 + (flowerSway3 / 2.6);
let backFloStartY = height * .75;
//stalk 4 back flower
strokeWeight(addXSingle * 1.5);
stroke(longLeafFill3);
noFill();
beginShape();
curveVertex(backFloStartX - addXSingle * 16, backFloStartY);
curveVertex(backFloStartX - addXSingle * 16, backFloStartY);
curveVertex(width * .15, height * .88);
curveVertex(width * .16, height);
curveVertex(width * .16, height);
endShape();
push();
translate(backFloStartX, backFloStartY);
rotate(30);
scale(1.3);
drawFlower(0, 0, medium_spring_bud);
pop();
let bigFloStartX = width * .1 + flower2Sway;
let bigFloStartY = height * .8;
beginShape();
curveVertex(bigFloStartX, bigFloStartY);
curveVertex(bigFloStartX, bigFloStartY);
curveVertex(width * .135, height * .91);
curveVertex(width * .15, height);
curveVertex(width * .15, height);
endShape();
push();
translate(bigFloStartX, height * .8);
rotate(-40);
scale(1.3);
drawFlower(0, 0, flower_fill);
pop();
var smolFloX = width * .2 + flowerSway / 4;
var smolFloY = height * .85;
beginShape();
curveVertex(smolFloX, smolFloY);
curveVertex(smolFloX, smolFloY);
curveVertex(width * .17, height * .95);
curveVertex(width * .172, height);
curveVertex(width * .172, height);
endShape();
push();
translate(smolFloX, smolFloY);
rotate(10);
scale(1);
drawFlower(0, 0, flower_fill);
pop();
}
function drawShortWavyLeaf(fillCol, strokeColWavy, shortWavyRot, shortWavyScale) {
//drawn on the upper left
var addXSingle = width / 960;
var addYSingle = height / 540;
var shortWavyLeafX = 0;
var shortWavyLeafY = 0;
//
fill(fillCol);
push();
scale(shortWavyScale);
rotate(shortWavyRot);
noStroke();
beginShape();
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX + addXSingle * -9, shortWavyLeafY + addYSingle * -10);
curveVertex(shortWavyLeafX + addXSingle * -11, shortWavyLeafY + addYSingle * -18);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * -10, shortWavyLeafY + addYSingle * -40);
curveVertex(shortWavyLeafX + addXSingle * -12, shortWavyLeafY + addYSingle * -47);
curveVertex(shortWavyLeafX + addXSingle * -13, shortWavyLeafY + addYSingle * -55);
curveVertex(shortWavyLeafX + addXSingle * -11.5, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -65);
curveVertex(shortWavyLeafX + addXSingle * -9.5, shortWavyLeafY + addYSingle * -73);
curveVertex(shortWavyLeafX + addXSingle * -10, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -83);
curveVertex(shortWavyLeafX + addXSingle * -3, shortWavyLeafY + addYSingle * -88);
curveVertex(shortWavyLeafX, shortWavyLeafY + addYSingle * -95);
curveVertex(shortWavyLeafX + addXSingle * 2, shortWavyLeafY + addYSingle * -100);
curveVertex(shortWavyLeafX + addXSingle * 5, shortWavyLeafY + addYSingle * -92);
curveVertex(shortWavyLeafX + addXSingle * 10, shortWavyLeafY + addYSingle * -86);
curveVertex(shortWavyLeafX + addXSingle * 16, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 17.5, shortWavyLeafY + addYSingle * -73);
curveVertex(shortWavyLeafX + addXSingle * 16.5, shortWavyLeafY + addYSingle * -67);
curveVertex(shortWavyLeafX + addXSingle * 15, shortWavyLeafY + addYSingle * -59);
curveVertex(shortWavyLeafX + addXSingle * 18, shortWavyLeafY + addYSingle * -48);
curveVertex(shortWavyLeafX + addXSingle * 16, shortWavyLeafY + addYSingle * -40);
curveVertex(shortWavyLeafX + addXSingle * 13, shortWavyLeafY + addYSingle * -33);
curveVertex(shortWavyLeafX + addXSingle * 15, shortWavyLeafY + addYSingle * -20);
curveVertex(shortWavyLeafX + addXSingle * 13, shortWavyLeafY + addYSingle * -13);
curveVertex(shortWavyLeafX + addXSingle * 5.5, shortWavyLeafY + addYSingle * -6);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
endShape();
fill(strokeColWavy);
stroke(strokeColWavy);
strokeWeight(addXSingle);
beginShape();
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX + addXSingle * -2, shortWavyLeafY + addYSingle * -17);
curveVertex(shortWavyLeafX + addXSingle * 0, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * -1.3, shortWavyLeafY + addYSingle * -39);
curveVertex(shortWavyLeafX + addXSingle * .4, shortWavyLeafY + addYSingle * -50);
curveVertex(shortWavyLeafX + addXSingle * -.7, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * 1.7, shortWavyLeafY + addYSingle * -68);
curveVertex(shortWavyLeafX + addXSingle * 1, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 1.6, shortWavyLeafY + addYSingle * -87);
curveVertex(shortWavyLeafX + addXSingle * 3, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 4.5, shortWavyLeafY + addYSingle * -68);
curveVertex(shortWavyLeafX + addXSingle * 3.5, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * 5, shortWavyLeafY + addYSingle * -50);
curveVertex(shortWavyLeafX + addXSingle * 2.3, shortWavyLeafY + addYSingle * -39);
curveVertex(shortWavyLeafX + addXSingle * 3.5, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * 1, shortWavyLeafY + addYSingle * -17);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
endShape();
pop();
}
function drawFatLeaf(fatLeafRot, fatLeafYScal, negative, fatLeafFill) {
//drawn at the front of the screen normally, bright
push();
var addXSingle = width / 960 * negative;
var addYSingle = height / 540;
var fatLeafX = 0;
var fatLeafY = 0;
fill(fatLeafFill);
noStroke();
rotate(fatLeafRot);
scale(fatLeafYScal)
beginShape();
curveVertex(fatLeafY, fatLeafY);
curveVertex(fatLeafY, fatLeafY);
curveVertex(fatLeafX + addXSingle * -70, fatLeafY + addYSingle * -50);
curveVertex(fatLeafX + addXSingle * -80, fatLeafY + addYSingle * -90);
curveVertex(fatLeafX + addXSingle * -70, fatLeafY + addYSingle * -120);
curveVertex(fatLeafX + addXSingle * -60, fatLeafY + addYSingle * -140);
curveVertex(fatLeafX + addXSingle * -50, fatLeafY + addYSingle * -170);
curveVertex(fatLeafX + addXSingle * -57, fatLeafY + addYSingle * -200);
curveVertex(fatLeafX + addXSingle * -45, fatLeafY + addYSingle * -230);
curveVertex(fatLeafX + addXSingle * -4, fatLeafY + addYSingle * -260);
curveVertex(fatLeafX, fatLeafY + addYSingle * -262);
curveVertex(fatLeafX + addXSingle * 4, fatLeafY + addYSingle * -260);
curveVertex(fatLeafX + addXSingle * 45, fatLeafY + addYSingle * -230);
curveVertex(fatLeafX + addXSingle * 54, fatLeafY + addYSingle * -210);
curveVertex(fatLeafX + addXSingle * 45, fatLeafY + addYSingle * -190);
curveVertex(fatLeafX + addXSingle * 50, fatLeafY + addYSingle * -170);
curveVertex(fatLeafX + addXSingle * 65, fatLeafY + addYSingle * -150);
curveVertex(fatLeafX + addXSingle * 70, fatLeafY + addYSingle * -135);
curveVertex(fatLeafX + addXSingle * 60, fatLeafY + addYSingle * -105);
curveVertex(fatLeafX + addXSingle * 70, fatLeafY + addYSingle * -85);
curveVertex(fatLeafX + addXSingle * 78, fatLeafY + addYSingle * -65);
curveVertex(fatLeafX + addXSingle * 65, fatLeafY + addYSingle * -40);
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX, fatLeafY);
endShape();
stroke(118, 154, 87);
strokeWeight(height / 520 * 3);
noFill();
beginShape();
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX + addXSingle * -1, fatLeafY + addYSingle * -35);
curveVertex(fatLeafX + addXSingle * 4, fatLeafY + addYSingle * -75);
curveVertex(fatLeafX + addXSingle * -5, fatLeafY + addYSingle * -115);
curveVertex(fatLeafX + addXSingle * 3, fatLeafY + addYSingle * -150);
curveVertex(fatLeafX + addXSingle * -4, fatLeafY + addYSingle * -175);
curveVertex(fatLeafX + addXSingle * 3, fatLeafY + addYSingle * -195);
curveVertex(fatLeafX + addXSingle * -2, fatLeafY + addYSingle * -210);
curveVertex(fatLeafX + addXSingle * 1, fatLeafY + addYSingle * -225);
//curveVertex(fatLeafX+addXSingle*1,fatLeafY+addYSingle*-225);
curveVertex(fatLeafX + addXSingle * -1, fatLeafY + addYSingle * -240);
curveVertex(fatLeafX + addXSingle, fatLeafY + addYSingle * -250);
curveVertex(fatLeafX + addXSingle, fatLeafY + addYSingle * -250);
endShape();
pop();
}
function drawSkinnyLongLeaf(skinnyLongLeafRot, skinnyLongLeafScale, skinnyLongLeafCol) {
//leaves on the rose branches
var addXSingle = width / 960;
var addYSingle = height / 540;
var skinnyLongLeafX = 0;
var skinnyLongLeafY = 0;
push();
rotate(skinnyLongLeafRot);
scale(skinnyLongLeafScale);
fill(skinnyLongLeafCol);
noStroke();
beginShape();
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX - addXSingle * 7, skinnyLongLeafY - addYSingle * 51);
curveVertex(skinnyLongLeafX - addXSingle * 1, skinnyLongLeafY - addYSingle * 100);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 105);
curveVertex(skinnyLongLeafX + addXSingle * 1, skinnyLongLeafY - addYSingle * 100);
curveVertex(skinnyLongLeafX + addXSingle * 8, skinnyLongLeafY - addYSingle * 49);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
endShape();
stroke(45, 78, 109);
noFill();
strokeWeight(addXSingle * .7);
beginShape();
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 21);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 21);
curveVertex(skinnyLongLeafX + addXSingle * 1, skinnyLongLeafY - addYSingle * 49);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 80);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 80);
endShape();
pop();
}
function drawFly(flyX, flyY, cur_frac, flyScale,negative) {
let wingMove; //set up animated wing variable
var addXSingle = width / 960 * negative;
var addYSingle = height / 540;
var flyBodyCol = color(74, 77, 76);
var flyWingCol = color(166, 237, 234, 180);
//setting it up so the flies wings can flap more tha once a second
var wingFlapNum = 360 * 5 //how many times the wing flaps per second , multiples of 360
var flapAmmount = round(sin(map(cur_frac, 0, 1, 1, wingFlapNum)));
var flapAmmountSmooth = sin(map(cur_frac, 0, 1, 1, wingFlapNum));
if (flapAmmount == 0) {
wingMove = map(flapAmmountSmooth, 0, -1, 0, 10);
} else if (flapAmmount == -1) {
wingMove = map(flapAmmountSmooth, -1, 0, 10, 0);
}
noStroke();
fill(flyBodyCol);
scale(flyScale);
ellipse(flyX + addXSingle * 15, flyY, addXSingle * 17, addYSingle * 17); //head
ellipse(flyX, flyY, addXSingle * 30, addYSingle * 22); //body
rect(flyX + addXSingle * 21, flyY + addYSingle * 1, addXSingle * 8, -addYSingle * 4); //snout
ellipse(flyX + addXSingle * 30, flyY - addYSingle * 1, addXSingle * 4, addYSingle * 7) //end of snout
//wings!
fill(flyWingCol);
push();
rotate(35*negative + wingMove);
ellipse(flyX - addXSingle * 6, flyY - addYSingle * 1, addXSingle * 20, addYSingle * 10);
rotate(40*negative + wingMove);
ellipse(flyX - addXSingle * 11, flyY - addYSingle * 3, addXSingle * 30, addYSingle * 15);
pop();
}
function drawFlower(flowerBaseX, flowerBaseY, flowerFill) {
noStroke();
var addXSingle = width / 960; //1
var addYSingle = height / 540;
fill(flowerFill);
arc(flowerBaseX, flowerBaseY, addXSingle * 80, addYSingle * 70, 0, 180);
stroke(144, 179, 118);
strokeWeight(addXSingle);
beginShape();
curveVertex(flowerBaseX - addXSingle * 35, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 35, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 28, flowerBaseY - addYSingle * 18);
curveVertex(flowerBaseX - addXSingle * 24, flowerBaseY - addYSingle * 20);
curveVertex(flowerBaseX - addXSingle * 21, flowerBaseY - addYSingle * 19);
curveVertex(flowerBaseX - addXSingle * 17, flowerBaseY - addYSingle * 23);
curveVertex(flowerBaseX - addXSingle * 12, flowerBaseY - addYSingle * 25);
curveVertex(flowerBaseX - addXSingle * 6, flowerBaseY - addYSingle * 22);
curveVertex(flowerBaseX - addXSingle * 1, flowerBaseY - addYSingle * 27);
curveVertex(flowerBaseX + addXSingle * 2, flowerBaseY - addYSingle * 28);
curveVertex(flowerBaseX + addXSingle * 5, flowerBaseY - addYSingle * 27);
curveVertex(flowerBaseX + addXSingle * 10, flowerBaseY - addYSingle * 21);
curveVertex(flowerBaseX + addXSingle * 17, flowerBaseY - addYSingle * 23);
curveVertex(flowerBaseX + addXSingle * 20, flowerBaseY - addYSingle * 20);
curveVertex(flowerBaseX + addXSingle * 26, flowerBaseY - addYSingle * 21);
curveVertex(flowerBaseX + addXSingle * 30, flowerBaseY - addYSingle * 18);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY);
endShape();
beginShape();
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 3, flowerBaseY - addYSingle * 12);
curveVertex(flowerBaseX + addXSingle * 9, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX + addXSingle * 15, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX + addXSingle * 20, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX + addXSingle * 24, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX + addXSingle * 29, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX + addXSingle * 38, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 40, flowerBaseY);
endShape();
beginShape();
curveVertex(flowerBaseX - addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 38, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX - addXSingle * 32, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX - addXSingle * 27, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX - addXSingle * 20, flowerBaseY - addYSingle * 16);
curveVertex(flowerBaseX - addXSingle * 14, flowerBaseY - addYSingle * 12);
curveVertex(flowerBaseX - addXSingle * 10, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX - addXSingle * 2, flowerBaseY - addYSingle * 6);
curveVertex(flowerBaseX + addXSingle * 1, flowerBaseY - addYSingle * 7.5)
curveVertex(flowerBaseX + addXSingle * 6, flowerBaseY - addYSingle * 8);
curveVertex(flowerBaseX + addXSingle * 9, flowerBaseY - addYSingle * 6)
curveVertex(flowerBaseX + addXSingle * 11, flowerBaseY - addYSingle * 1);
curveVertex(flowerBaseX + addXSingle * 17, flowerBaseY - addYSingle * 2);
curveVertex(flowerBaseX + addXSingle * 22, flowerBaseY + addYSingle * 3);
curveVertex(flowerBaseX + addXSingle * 28, flowerBaseY + addYSingle * 3);
curveVertex(flowerBaseX + addXSingle * 36, flowerBaseY + addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 36, flowerBaseY + addYSingle * 11);
endShape();
}
function drawLongLeaf(longLeafBaseX, longLeafBaseY, longLeafScale, longLLeafRotation, longLeafFill, longLeafStrokeCol) {
//kelp looking leaf
noStroke();
angleMode(DEGREES);
push();
rotate(longLLeafRotation);
var longLeafAddXSingle = width / 960; //1
var longLeafAddYSingle = height / 540; // 1
scale(longLeafScale);
fill(longLeafFill);
beginShape();
curveVertex(longLeafBaseX - (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 50), longLeafBaseY - longLeafAddYSingle * 45);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 36), longLeafBaseY - longLeafAddYSingle * 80);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 41), longLeafBaseY - longLeafAddYSingle * 125);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 27), longLeafBaseY - longLeafAddYSingle * 156);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 31), longLeafBaseY - longLeafAddYSingle * 200);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 18), longLeafBaseY - longLeafAddYSingle * 235);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 22), longLeafBaseY - longLeafAddYSingle * 270);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 13), longLeafBaseY - longLeafAddYSingle * 295);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 11), longLeafBaseY - longLeafAddYSingle * 325);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 2), longLeafBaseY - longLeafAddYSingle * 340);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 355);
vertex(longLeafBaseX + (longLeafAddXSingle * 14), longLeafBaseY - longLeafAddYSingle * 379);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 26), longLeafBaseY - longLeafAddYSingle * 365);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 24), longLeafBaseY - longLeafAddYSingle * 345);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 28), longLeafBaseY - longLeafAddYSingle * 330);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 25), longLeafBaseY - longLeafAddYSingle * 310);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 35), longLeafBaseY - longLeafAddYSingle * 285);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 30), longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 228);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 36), longLeafBaseY - longLeafAddYSingle * 200);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 45), longLeafBaseY - longLeafAddYSingle * 165);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 132);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 49), longLeafBaseY - longLeafAddYSingle * 95);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 41), longLeafBaseY - longLeafAddYSingle * 57);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 50), longLeafBaseY - longLeafAddYSingle * 25);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY + longLeafAddYSingle * 12);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY + longLeafAddYSingle * 12);
endShape();
stroke(longLeafStrokeCol);
noFill();
strokeWeight(longLeafAddXSingle * 4.5);
beginShape();
curveVertex(longLeafBaseX, longLeafBaseY + longLeafAddYSingle * 5);
curveVertex(longLeafBaseX, longLeafBaseY + longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 25);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 54);
curveVertex(longLeafBaseX + longLeafAddXSingle * 6, longLeafBaseY - longLeafAddYSingle * 85);
curveVertex(longLeafBaseX - longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 118);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 152);
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 211);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 238);
curveVertex(longLeafBaseX + longLeafAddXSingle * 11, longLeafBaseY - longLeafAddYSingle * 265);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 289);
curveVertex(longLeafBaseX + longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 313);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 335);
curveVertex(longLeafBaseX + longLeafAddXSingle * 12, longLeafBaseY - longLeafAddYSingle * 351);
curveVertex(longLeafBaseX + longLeafAddXSingle * 12, longLeafBaseY - longLeafAddYSingle * 351);
endShape();
noFill();
strokeWeight(longLeafAddXSingle * 3);
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 15);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 20);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 33);
curveVertex(longLeafBaseX - longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 40);
curveVertex(longLeafBaseX - longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 40);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 78);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 78);
curveVertex(longLeafBaseX + longLeafAddXSingle * 13, longLeafBaseY - longLeafAddYSingle * 85);
curveVertex(longLeafBaseX + longLeafAddXSingle * 33, longLeafBaseY - longLeafAddYSingle * 89);
curveVertex(longLeafBaseX + longLeafAddXSingle * 33, longLeafBaseY - longLeafAddYSingle * 89);
endShape();
beginShape();
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 105);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 105);
curveVertex(longLeafBaseX - longLeafAddXSingle * 13, longLeafBaseY - longLeafAddYSingle * 120);
curveVertex(longLeafBaseX - longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 122);
curveVertex(longLeafBaseX - longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 122);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 149);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 149);
curveVertex(longLeafBaseX + longLeafAddXSingle * 14, longLeafBaseY - longLeafAddYSingle * 155);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 158);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 158);
endShape();
beginShape();
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 192);
curveVertex(longLeafBaseX - longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 195);
curveVertex(longLeafBaseX - longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 195);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 210);
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 210);
curveVertex(longLeafBaseX + longLeafAddXSingle * 14, longLeafBaseY - longLeafAddYSingle * 219);
curveVertex(longLeafBaseX + longLeafAddXSingle * 26, longLeafBaseY - longLeafAddYSingle * 225);
curveVertex(longLeafBaseX + longLeafAddXSingle * 26, longLeafBaseY - longLeafAddYSingle * 225);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 8, longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX + longLeafAddXSingle * 8, longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 262);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 265);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 265);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 275);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 275);
curveVertex(longLeafBaseX + longLeafAddXSingle * 18, longLeafBaseY - longLeafAddYSingle * 280);
curveVertex(longLeafBaseX + longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 282);
curveVertex(longLeafBaseX + longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 282);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 311);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 311);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 317);
curveVertex(longLeafBaseX - longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 319);
curveVertex(longLeafBaseX - longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 319);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 327);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 327);
curveVertex(longLeafBaseX + longLeafAddXSingle * 15, longLeafBaseY - longLeafAddYSingle * 332);
curveVertex(longLeafBaseX + longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 334);
curveVertex(longLeafBaseX + longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 334);
endShape();
translate(width / 4, height / 4 * 3);
pop();
}
const ease = new p5.Ease();
function draw_one_frame(cur_frac) {
// note: to clear the screen draw a rectangle
// note: all shape sizes, line widths, etc. should be a function of width and height
// note: animation should progress depending on the value of cur_frac which goes from 0 to 1, and it should loop seamlessly
angleMode(DEGREES);
noStroke();
fill(255, 130, 155);
rect(0, 0, width, height); //the background
// let sunR = [228, 255, 255, 255, 255];
// let sunG = [153, 153, 153, 156, 202];
// let sunB = [255, 236, 177, 110, 87];
// let sunPulse = [width*1, width*1.1, width*1.15, width*1.2, width*1.2, width*1.15, width*1.1, width*1];
// let sunScale = [1, 0.95, 0.6, 0.4, 0.2];
//this is the gradient behind the sun
for (i=0; i<50; i++){
fill(255, 188, 64, 15);
push();
let sunScaleFac = i*0.02;
ellipse(width/2, height/1.5, (width*sunScaleFac));
pop();
}
//these are the sunrays
push();
noFill();
strokeWeight(height/20);
translate(width/2, height/1.5);
for(let i=0; i<10; i++){
stroke(254, 255, 166)
rotate(360/10);
sunRay(width/2, height/1.5, cur_frac);
}
pop();
//this is the actual sun
fill(255, 202, 87)
ellipse(width/2, height/1.5, (width*0.2));
//these are the hills I'm drawing, as well as the squiggle lines on top of them
push();
fill(105, 54, 0);
beginShape();
curveVertex(0, height);
curveVertex(-width/20, height/2.6);
curveVertex(width/8, height/2.1);
curveVertex(width/4.5, height/2.05);
curveVertex(width/3, height/1.6);
curveVertex(width/2.1, height/1.4);
curveVertex(width/1.75, height);
curveVertex(width/2, height);
curveVertex(0, height);
curveVertex(0, height);
endShape();
noFill();
stroke(122, 73, 18);
strokeWeight(width/500);
beginShape();
curveVertex(0, height);
curveVertex(-width/20, height/2.2);
curveVertex(width/8, height/1.85);
curveVertex(width/4.5, height/1.75);
curveVertex(width/3, height/1.5);
curveVertex(width/2.6, height/1.35);
curveVertex(width/4.75, height/1.35);
curveVertex(width/8, height/1.3);
curveVertex(0, height/1.5);
curveVertex(0, height/1.7);
endShape();
beginShape();
curveVertex(0, height);
curveVertex(-width/20, height/2.1);
curveVertex(width/8, height/1.75);
curveVertex(width/4.5, height/1.65);
curveVertex(width/3.5, height/1.5);
curveVertex(width/3, height/1.4);
curveVertex(width/4.75, height/1.4);
curveVertex(width/8, height/1.35);
curveVertex(0, height/1.6);
curveVertex(0, height/1.9);
endShape();
beginShape();
curveVertex(0, height);
curveVertex(-width/20, height/2);
curveVertex(width/8, height/1.65);
curveVertex(width/4.5, height/1.55);
curveVertex(width/3.6, height/1.475);
curveVertex(width/3.5, height/1.44);
curveVertex(width/4.75, height/1.475);
curveVertex(width/8, height/1.4);
curveVertex(0, height/1.7);
curveVertex(0, height/2);
endShape();
fill(117, 74, 29);
beginShape();
curveVertex(width/3, height);
curveVertex(width/2.25, height/1.3);
curveVertex(width/1.75, height/1.6);
curveVertex(width/1.3, height/1.7);
curveVertex(width/0.98, height/1.95);
curveVertex(width, height);
curveVertex(width/3, height);
curveVertex(width/3, height);
endShape();
noFill();
stroke(145, 104, 61);
strokeWeight(width/500);
beginShape();
curveVertex(width/0.98, height/1.7);
curveVertex(width/0.8, height/1.33);
curveVertex(width/1.2, height/1.43);
curveVertex(width/1.5, height/1.43);
curveVertex(width/1.6, height/1.43);
curveVertex(width/1.67, height/1.42);
curveVertex(width/1.56, height/1.47);
curveVertex(width/1.3, height/1.47);
curveVertex(width/1.1, height/1.65);
curveVertex(width/0.98, height/1.7);
curveVertex(width/0.98, height/1.7);
endShape();
beginShape();
curveVertex(width/0.98, height/1.75);
curveVertex(width/0.8, height/1.3);
curveVertex(width/1.2, height/1.4);
curveVertex(width/1.5, height/1.4);
curveVertex(width/1.7, height/1.38);
curveVertex(width/1.75, height/1.4);
curveVertex(width/1.56, height/1.5);
curveVertex(width/1.3, height/1.5);
curveVertex(width/1.1, height/1.7);
curveVertex(width/0.98, height/1.75);
curveVertex(width/0.98, height/1.75);
endShape();
beginShape();
curveVertex(width/0.98, height/1.8);
curveVertex(width/0.8, height/1.25);
curveVertex(width/1.2, height/1.35);
curveVertex(width/1.5, height/1.35);
curveVertex(width/1.75, height/1.33);
curveVertex(width/1.8, height/1.45);
curveVertex(width/1.56, height/1.55);
curveVertex(width/1.3, height/1.55);
curveVertex(width/1.1, height/1.75);
curveVertex(width/0.98, height/1.8);
curveVertex(width/0.98, height/1.8);
endShape();
beginShape();
curveVertex(width/0.98, height/1.8);
curveVertex(width/0.8, height/1.2);
curveVertex(width/1.2, height/1.3);
curveVertex(width/1.5, height/1.3);
curveVertex(width/1.75, height/1.28);
curveVertex(width/1.9, height/1.45);
curveVertex(width/1.56, height/1.6);
curveVertex(width/1.3, height/1.6);
curveVertex(width/1.1, height/1.8);
curveVertex(width/0.98, height/1.85);
curveVertex(width/0.98, height/1.85);
endShape();
pop();
//this is the lake
fill(166, 249, 255);
ellipse(width/2, height*1.3, width*2, height)
//these are the clouds
const ease_amount_cloud = ease.cubicInOut(cur_frac);
//this makes the clouds move accross the page
let cloudxPlace = [-width*0.25, 0, width*0.25, width*0.5, width*0.75, width, width*1.25];
let cloudyPlace = [height/8, height/200, height/10, height/12];
for(let i=0; i<cloudxPlace.length-1; i++) {
let cloudXpos1 = map(ease_amount_cloud, 0, 1, cloudxPlace[i], cloudxPlace[i+1])
let cloudYpos1 = map(ease_amount_cloud, 0, 1, cloudyPlace[i], cloudyPlace[i+1])
cloud(cloudXpos1, cloudYpos1);
}
//these are the waves
let waveXoffset = [0, width/20, -width/40];
let waveYoffset = [0, height/20, height/50];
waves(width/4+waveXoffset[0], height/1.1+waveYoffset[0], cur_frac);
waves(width/4+waveXoffset[1], height/1.1+waveYoffset[1], cur_frac);
waves(width/4+waveXoffset[2], height/1.1+waveYoffset[2], cur_frac);
let waveX2offset = [0, width/100];
waves(width/1.8+waveX2offset[0], height/1.17+waveX2offset[0], cur_frac);
waves(width/1.8+waveX2offset[1], height/1.17+waveX2offset[1], cur_frac);
//these are the flowers in the front left
flower2(width/10, height/1.4, cur_frac);
flower3(width/5.5, height/1.35, cur_frac)
flower1(width/100, height/1.3, cur_frac);
flower1(width/8, height/1.2, cur_frac);
flower2(width/4, height/1.18, cur_frac);
flower3(width/30, height/1.1, cur_frac)
//these are the flowers in the front right
flower1(width-width/55, height/1.1, cur_frac);
flower1(width-width/3, height/1.1, cur_frac);
flower1(width-width/10, height/1.4, cur_frac);
flower2(width-width/100, height/1.3, cur_frac);
flower3(width-width/100, height/1.6, cur_frac)
flower2(width-width/5.5, height/1.2, cur_frac);
flower3(width-width/3.75, height/1.13, cur_frac)
flower1(width-width/3, height/1.1, cur_frac);
flower3(width-width/10, height/1.17, cur_frac)
}
//from here down are just the different elements that I put in a function so it was easier to call on them mulitple times
//the names should make it pretty self explanatory
function cloud (x, y) {
fill(255, 227, 238);
push();
scale(2.25, 1.5);
ellipse(x+width/9.5, y+height/11, width/8, width/25);
ellipse(x+width/25, y+height/10, width/9, width/30);
ellipse(x+width/11, y+height/16, width/11, width/22);
ellipse(x+width/17, y+height/15, width/12, width/40);
ellipse(x+width/6.2, y+height/8.5, width/20, width/50);
pop();
}
function sunRay(x, y, cur_frac) {
push();
noFill();
translate(width*0.08, 0);
let squiggle_up = true;
if (cur_frac < 0.5) {
squiggle_up = true;
amount_squiggle = cur_frac * 2;
}
else {
squiggle_up = false;
amount_squiggle = (cur_frac-0.5) * 2;
}
const ease_amount_squiggle = ease.quadraticOut(amount_squiggle);
let strokeTransparencyArray = [225, 75, 125, 175, 200, 75, 125, 175, 200];
let rayOffsetArray = [0, height/12, height/15, height/20, height/30, -height/12, -height/15, -height/20, -height/30];
for(let j=0; j<4; j++){
let rayOffset = rayOffsetArray[j];
strokeWeight(j*height/10+height/50);
stroke(255, 246, 176, 100);
beginShape();
for (let i=0; i<360; i++){
var waveX = map(i, 0, 360, 0, width);
var waveY = sin(i*2.5) * height/10;
let rayYpos;
if(cur_frac<0.5){
rayYpos = map(ease_amount_squiggle, 0, 0.5, -waveY/4, waveY/4);
}
else{
rayYpos = map(ease_amount_squiggle, 0.5, 1, waveY/4, -waveY/4);
}
vertex(waveX, rayYpos);
}
endShape();
}
pop();
}
function flower1 (x, y, cur_frac){
let petalxOffset;
let petalyOffset;
petalxOffset = [0, width/30, width/20, width/30, 0, -width/30, -width/20, -width/30];
petalyOffset = [0, width/50, width/20, width/12.5, width/10, width/12.5, width/20, width/50];
push();
for (let i = 0; i < 8; i++) {
push();
translate(petalxOffset[i], petalyOffset[i]);
noStroke();
fill(99, 45, 93, 100);
ellipse(x+width/200, y+width/200, width/20)
fill(255, 179, 249);
ellipse(x, y, width/20)
pop();
}
let flowerCentre = true;
if (cur_frac < 0.5) {
flowerCentre = true;
amount_scale = cur_frac * 2;
}
else {
flowerCentre = false;
amount_scale = map(cur_frac, 0.5, 1, 1, 0);
}
const ease_amount_scale = ease.cubicInOut(amount_scale);
const ease_amount_alpha = ease.circularInOut(amount_scale);
let flowerSize = width/30
let flowerScale = map(ease_amount_scale, 0, 1, flowerSize/2, flowerSize);
let flowerAlpha = map(ease_amount_alpha, 0, 1, 0, 150);
fill(191, 164, 90, 100);
ellipse(x, y+(0.09*height), width/14);
fill(252, 214, 109);
ellipse(x, y+(0.09*height), width/15);
fill(252, 214, 109, flowerAlpha);
strokeWeight(width/1000);
stroke(237, 162, 0, flowerAlpha);
ellipse(x, y+(0.09*height), flowerScale*2);
stroke(237, 162, 0, flowerAlpha+25);
ellipse(x, y+(0.09*height), flowerScale*1.66);
stroke(237, 162, 0, flowerAlpha+50);
ellipse(x, y+(0.09*height), flowerScale*1.33);
stroke(237, 162, 0, flowerAlpha+100);
ellipse(x, y+(0.09*height), flowerScale);
stroke(237, 162, 0, flowerAlpha+150);
ellipse(x, y+(0.09*height), flowerScale*0.66);
stroke(237, 162, 0, flowerAlpha+200);
ellipse(x, y+(0.09*height), flowerScale*0.33);
ellipse(x, y+(0.09*height), flowerScale*0.1);
ellipse(x, y+(0.09*height), flowerScale*0.05);
pop();
pop();
}
function flower2 (x, y, cur_frac){
let petalxOffset;
let petalyOffset;
noStroke();
petalxOffset = [0, width/37.5, width/22.5, width/22.5, width/37.5, 0, -width/37.5, -width/22.5, -width/22.5, -width/37.5];
petalyOffset = [width/200, width/60, width/25, width/15, width/11, width/10, width/11, width/15, width/25, width/60];
for (let i = 0; i < 10; i++) {
push();
translate(petalxOffset[i], petalyOffset[i]);
noStroke();
fill(99, 45, 93, 100);
ellipse(x+width/200, y+width/200, width/20)
fill(245, 100, 120);
ellipse(x, y, width/25)
pop();
}
let flowerCentre = true;
if (cur_frac < 0.5) {
flowerCentre = true;
amount_scale = cur_frac * 2;
}
else {
flowerCentre = false;
amount_scale = map(cur_frac, 0.5, 1, 1, 0);
}
const ease_amount_scale = ease.circularIn(amount_scale);
const ease_amount_alpha = ease.circularInOut(amount_scale);
let flowerSize = width/30
let flowerScale = map(ease_amount_scale, 0, 1, flowerSize/2, flowerSize);
let flowerAlpha = map(ease_amount_alpha, 0, 1, 0, 150);
fill(74, 53, 27, 100);
ellipse(x, y+(0.09*height), width/14);
fill(138, 110, 77);
ellipse(x, y+(0.09*height), width/15);
fill(138, 110, 77, flowerAlpha);
strokeWeight(width/1000);
stroke(56, 31, 0, flowerAlpha);
ellipse(x, y+(0.09*height), flowerScale*2);
stroke(56, 31, 0, flowerAlpha+25);
ellipse(x, y+(0.09*height), flowerScale*1.66);
stroke(56, 31, 0, flowerAlpha+50);
ellipse(x, y+(0.09*height), flowerScale*1.33);
stroke(56, 31, 0, flowerAlpha+100);
ellipse(x, y+(0.09*height), flowerScale);
stroke(56, 31, 0, flowerAlpha+150);
ellipse(x, y+(0.09*height), flowerScale*0.66);
stroke(56, 31, 0, flowerAlpha+200);
ellipse(x, y+(0.09*height), flowerScale*0.33);
stroke(56, 31, 0, flowerAlpha+200);
ellipse(x, y+(0.09*height), flowerScale*0.1);
pop();
}
function flower3 (x, y, cur_frac){
let petalxOffset;
let petalyOffset;
petalxOffset = [0, width/55, width/35, width/55, 0, -width/55, -width/35, -width/55];
petalyOffset = [width/45, width/35, width/20, width/14, width/12.5, width/14, width/20, width/35];
noStroke();
push();
for (let i = 0; i < 8; i++) {
push();
translate(petalxOffset[i], petalyOffset[i]);
noStroke();
fill(99, 45, 93, 100);
ellipse(x+width/200, y+width/200, width/40)
fill(255);
ellipse(x, y, width/40)
pop();
}
let flowerCentre = true;
if (cur_frac < 0.5) {
flowerCentre = true;
amount_scale = cur_frac * 2;
}
else {
flowerCentre = false;
amount_scale = map(cur_frac, 0.5, 1, 1, 0);
}
const ease_amount_scale = ease.quadraticOut(amount_scale);
const ease_amount_alpha = ease.circularInOut(amount_scale);
let flowerSize = width/45
let flowerScale = map(ease_amount_scale, 0, 1, flowerSize/2, flowerSize);
let flowerAlpha = map(ease_amount_alpha, 0, 1, 0, 150);
fill(191, 164, 90, 100);
ellipse(x, y+(0.09*height), width/20);
fill(252, 214, 109);
ellipse(x, y+(0.09*height), width/22.5);
fill(252, 214, 109, flowerAlpha);
strokeWeight(width/1000);
stroke(237, 162, 0, flowerAlpha);
ellipse(x, y+(0.09*height), flowerScale*2);
stroke(237, 162, 0, flowerAlpha+25);
ellipse(x, y+(0.09*height), flowerScale*1.66);
stroke(237, 162, 0, flowerAlpha+50);
ellipse(x, y+(0.09*height), flowerScale*1.33);
stroke(237, 162, 0, flowerAlpha+100);
ellipse(x, y+(0.09*height), flowerScale);
stroke(237, 162, 0, flowerAlpha+150);
ellipse(x, y+(0.09*height), flowerScale*0.66);
stroke(237, 162, 0, flowerAlpha+200);
ellipse(x, y+(0.09*height), flowerScale*0.33);
ellipse(x, y+(0.09*height), flowerScale*0.1);
ellipse(x, y+(0.09*height), flowerScale*0.05);
pop();
}
function waves (x, y, cur_frac) {
push();
noFill();
let going_up = true;
strokeWeight(height/150);
translate(width*0.08, 0);
if (cur_frac < 0.5) {
going_up = true;
amount_down = cur_frac * 2;
}
else {
going_up = false;
amount_down = (cur_frac-0.5) * 2;
}
const ease_amount_up = ease.quadraticIn(amount_down);
let strokeAlpha = map(amount_down, 0, 1, 200, 100);
stroke(255, 255, 255, strokeAlpha);
beginShape();
var yoff = 0;
let nudgeScale = getNoiseValue(x, y, ease_amount_up, "nudgeScale", 0, height/500, 10);
for (let i=0; i<360; i++){
var waveX1 = map(i, 0, 360, -width/10, 0);
var waveNoiseY = map(noise(yoff), 0, 1, 0, height/50);
var waveSineY = sin(i*3) * height/300 + sin(i*2.5) * height/500;
var waveY = (waveSineY+waveNoiseY+nudgeScale)
let waveYpos;
let waveXpos;
if(cur_frac<0.5){
waveYpos = map(ease_amount_up, 0, 0.5, -waveY/4, waveY/4);
waveX2 = map(ease_amount_up, 0, 0.5, width/11, width/12);
}
else{
waveYpos = map(ease_amount_up, 0.5, 1, waveY/4, -waveY/4);
waveX2 = map(ease_amount_up, 0.5, 1, width/12, width/11);
}
waveXpos = waveX1+waveX2
vertex(waveXpos+x, waveYpos+y);
yoff += 0.01
}
endShape();
pop();
}
const ease = new p5.Ease();
function draw_one_frame(cur_frac) {
var addXSingle = width / 960;
var addYSingle = height / 520;
fill(255);
rect(0, 0, width, height);
//drawing the background gradient
c1 = color(240, 254, 254); //very light blue
c2 = color(154, 242, 245); //darker blue
for (let yBG = 0; yBG < height + 1; yBG++) {
n = map(yBG, 0, height, 0, 1);
let newc = lerpColor(c1, c2, n);
stroke(newc);
line(0, yBG, width, yBG);
}
let cur_x = map(cur_frac, 0, 1, 0, width) //- half_width;
//all of my colours to use when I call a leaf function!
var longLeafFill1 = color(167, 212, 138);
var longLeafFill2 = color(134, 181, 103);
var longLeafStroke1 = color(108, 148, 99);
var longLeafFill3 = color(92, 145, 84); //saturated dark green
var longLeafStroke3 = color(92, 145, 84);
var longLeafFill4 = color(49, 94, 89); //darkest green
var longLeafStroke4 = color(49, 94, 89);
var longLeafFill5 = color(83, 144, 111);
var fatLeafFill = color(200, 231, 128);
var darkBlueGreen = color(71, 125, 99);
var teal = color(87, 141, 122);
var slate_green = color(91, 151, 110);
var dull_greren = color(109, 171, 94);
var muted_green = color(102, 159, 90);
var pale_olive_green = color(160, 213, 148);
var pale_olive = color(173, 202, 151);
var flower_fill = color(230, 251, 150);
var medium_spring_bud = color(191, 225, 129);
var oxley = color(105, 159, 132);
var limed_spruce = color(57, 69, 83);
var skinnyLongLeafCol = color(103, 142, 149);
var secondFlowerLeaf = color(115, 166, 137);
let randRoat = getNoiseValue(0, 0, cur_frac, "randRoat", -.3, .3, .1); //random jitter on the long leaf using noise
push(); //fat leaf right at the back on the right
translate(width / 1.23, height / 1);
drawFatLeaf(70, 0.6, -1, darkBlueGreen);
pop();
push(); //fat leaf right at the back on the left
translate(width * .16, height * 1.07);
drawFatLeaf(-43, .8, -1, darkBlueGreen);
pop();
//leaves on the right behind the flowers
push();
translate(width / 1.4, height * 1.04);
drawLongLeaf(0, 0, 1.2, 20, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width / 1.28, height * 1.1);
drawLongLeaf(0, 0, 1.05, 23, longLeafFill3, longLeafStroke3);
pop();
push();
translate(width / 1.45, height * 1.02);
drawLongLeaf(0, 0, 1.05, 0, longLeafFill5, longLeafFill5);
pop();
//setting up the flowers to move back and forth
let going_right = true;
let amount_across = 0;
if (cur_frac < 0.5) {
going_right = true;
amount_across = cur_frac * 2;
} else {
going_right = false;
amount_across = (cur_frac - 0.5) * 2;
}
const ease_amount_across = ease.doubleQuadraticSigmoid(amount_across);
const ease_amount_across_fatLeaf = ease.circularFillet(amount_across);
const ease_amount_acrosslongLeaf = ease.normalizedLogitSigmoid(amount_across);
if (going_right) {
flowerSway = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * 2)
flower2Sway = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * .9)
fLSway = map(ease_amount_across_fatLeaf, 0, 0.5, addXSingle * 0, addXSingle * 0.3)
longLeafSway = map(ease_amount_acrosslongLeaf, 0, 0.5, addXSingle * 0, addXSingle * 0.2)
} else {
flowerSway = map(ease_amount_across, 0.5, 1, addXSingle * 2, addXSingle * 0)
flower2Sway = map(ease_amount_across, 0.5, 1, addXSingle * .9, addXSingle * 0)
fLSway = map(ease_amount_across_fatLeaf, 0.5, 1, addXSingle * 0.3, addXSingle * 0)
longLeafSway = map(ease_amount_acrosslongLeaf, 0.5, 1, addXSingle * 0.2, addXSingle * 0)
}
//drawing long leaf with the jitter
push();
translate(width / 1.6, height / 1.02);
rotate(0);
drawLongLeaf(0, 0, 1.2, (randRoat / 3) + longLeafSway, longLeafFill1, longLeafStroke1);
pop();
//setting up the flowers
var flower1StartX = width / 1.2 + flowerSway; //flower sway makes the flower bud AND the stalk move
var flower1StartY = height / 4.9;
var flower2StartX = width *.92 + flower2Sway;
var flower2StartY = height *.33974;
strokeWeight(width / 960 * 2);
stroke(93, 107, 54);
noFill();
beginShape(); //flower 1 stalk
curveVertex(flower1StartX, flower1StartY);
curveVertex(flower1StartX, flower1StartY);
curveVertex(width / 1.2, height *.6);
curveVertex(width / 1.3, height*.89);
curveVertex(width / 1.3, height*.89);
endShape();
//draw the actual flower (biggest one)
push();
translate(flower1StartX, flower1StartY);
rotate(-25);
scale(1.4);
drawFlower(0, 0, flower_fill); //bigger top flower
pop();
//drawing leaves on the biggest flowerr
push();
translate(width / 1.196 + (flowerSway / 2), height / 2.3); //top down
drawSkinnyLongLeaf(-40, .9, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.2), height / 2.15);
drawSkinnyLongLeaf(35, 1, skinnyLongLeafCol);
pop();
push();
translate(width / 1.196 + (flowerSway / 2.6), height / 2.05);
drawSkinnyLongLeaf(-60, 1.1, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.8), height / 1.9);
drawSkinnyLongLeaf(55, 1.08, skinnyLongLeafCol);
pop();
push();
translate(width / 1.196 + (flowerSway / 2.9), height / 1.7);
drawSkinnyLongLeaf(-57, 1.25, skinnyLongLeafCol);
pop();
push();
translate(width / 1.194 + (flowerSway / 2.8), height / 1.65);
drawSkinnyLongLeaf(59, 1.25, skinnyLongLeafCol);
pop();
push();
translate(width / 1.215, height / 1.55);
drawSkinnyLongLeaf(-50, 1.3, skinnyLongLeafCol);
pop();
push();
translate(width / 1.223, height / 1.4);
drawSkinnyLongLeaf(-69, 1.5, skinnyLongLeafCol);
pop();
push();
translate(width / 1.27, height / 1.21);
drawSkinnyLongLeaf(-62, 1.5, skinnyLongLeafCol);
pop();
push(); ////////leaves in the middle of the screen///////
translate(width * .49, height * 1.19);
drawShortWavyLeaf(longLeafFill3, longLeafFill3, 13, 3);
pop();
push();
translate(width * .604, height * 1.047);
drawShortWavyLeaf(teal, oxley, -17, 2.7);
pop();
push();
translate(width * .2, height * 1.1);
drawShortWavyLeaf(longLeafFill2, longLeafFill2, -20, 3);
pop();
//second flower stalk
strokeWeight(width / 960 * 2);
stroke(93, 107, 54);
noFill();
beginShape(); //flower 2 stalk
curveVertex(flower2StartX, flower2StartY);
curveVertex(flower2StartX, flower2StartY);
curveVertex(width *.896, height *.52);
curveVertex(width / 1.3, height *.89);
curveVertex(width / 1.3, height *.89);
endShape();
//second flower
push();
translate(flower2StartX, flower2StartY);
rotate(25);
scale(1);
drawFlower(0, 0, flower_fill); //lower smaller flower
pop();
//ssecond flower leaves
push();
translate(width*.908 + (flower2Sway / 4), height / 2.18);
drawSkinnyLongLeaf(-28, .84, secondFlowerLeaf);
pop();
push();
translate(width *.906 + (flower2Sway / 2.8), height / 2.1);
drawSkinnyLongLeaf(48, .87, secondFlowerLeaf);
pop();
push();
translate(width / 1.13, height / 1.84);
drawSkinnyLongLeaf(-21, 1, secondFlowerLeaf);
pop();
push();
translate(width / 1.15, height / 1.69);
drawSkinnyLongLeaf(70, 1.07, secondFlowerLeaf);
pop();
push();
translate(width / 1.17, height / 1.55);
drawSkinnyLongLeaf(-33, 1.2, secondFlowerLeaf);
pop();
push();
translate(width / 1.2, height / 1.4);
drawSkinnyLongLeaf(63, 1.3, secondFlowerLeaf);
pop();
//draw the two fat leaves in front of the flowers on the RIGHT
push();
translate(width / 1.29, height * 1.03);
drawFatLeaf(45 + fLSway, 0.9, 1, fatLeafFill);
pop();
push();
translate(width / 1.43, height * 1.1);
drawFatLeaf(-15 + (fLSway * 4), 0.9, -1, fatLeafFill);
pop();
const ease_amount_across_fatLeaf2 = ease.circularArcThroughAPoint(amount_across);
const ease_amount_up_down = ease.doubleQuadraticSigmoid(amount_across);
if (going_right) {
flowerSway3 = map(ease_amount_across, 0, 0.5, addXSingle * .5, addXSingle * 0);
fatLeaf2Sway = map(ease_amount_across_fatLeaf2, 0, 0.5, addXSingle * 0.6, addXSingle * 0);
branchupdown = map(ease_amount_up_down, 0, 0.5, addXSingle * 0.6, addXSingle * 0)
} else {
flowerSway3 = map(ease_amount_across, 0, 0.5, addXSingle * 0, addXSingle * .5);
fatLeaf2Sway = map(ease_amount_across_fatLeaf2, 0, 0.5, addXSingle * 0, addXSingle * 0.6);
branchupdown = map(ease_amount_up_down, 0.5, 1, addXSingle * 0, addXSingle * 0.6);
}
/////////behind shrt wavy leaves
push();
translate(width * .43, height * 1.04);
drawLongLeaf(0, 0, 1.18, -23, limed_spruce, limed_spruce);
pop();
push();
translate(width * .42, height * 1.03);
drawLongLeaf(0, 0, 1.1, 1, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width * .30, height * 1.03);
drawLongLeaf(0, 0, 1.2, -30 + longLeafSway / 2, longLeafFill4, longLeafStroke4);
pop();
push();
translate(width * .37, height);
drawLongLeaf(0, 0, 1, -30, longLeafFill2, longLeafStroke1);
pop();
//fly on the left
let flyScale = 0.55;
let flyX;
//setting it up off-beat, so it grows starting at 0.3 cur frac and loops back to then (instead of 0-1)
if (cur_frac >= 0.3) {
flyScale = map(cur_frac, 0.3, 0.5, 0, 0.55);
}
if (cur_frac >= 0.5) {
flyScale = map(cur_frac, 0.5, 1, 0.55, 0.55);
}
if (cur_frac <= 0.3) {
flyScale = map(cur_frac, 0, 0.3, 0.55, 0);
}
if (cur_frac <= 0.3) { //this is for the flies movement
flyX = map(cur_frac, 0, 0.3, addXSingle * 200, addXSingle * 250)
} else if (cur_frac >= 0.3) {
flyX = map(cur_frac, 0.3, 1, addXSingle * 100, addXSingle * 200)
}
push(); //draw the actual fly
translate(width / 1.9 + flyX, height / 1.5); //centre of the screen
drawFly(0, 0, cur_frac, flyScale,1);
pop();
//////////short wavy leaves stalk////////////
stroke(52, 93, 88);
strokeWeight(addXSingle * 3);
noFill();
var endOfBranchX = width * .12;
var endOfBranchY = height / 3.9;
var strokeColWavy1 = color(42, 86, 79);
//main branch (going left)
beginShape();
curveVertex(width / 3, height / 1.7);
curveVertex(width / 3, height / 1.7);
curveVertex(width / 3.8, height / 4.4);
curveVertex(endOfBranchX, endOfBranchY + branchupdown);
curveVertex(endOfBranchX, endOfBranchY + branchupdown);
endShape();
//second branch going right
beginShape();
curveVertex(width * .31, height * .419);
curveVertex(width * .31, height * .419);
curveVertex(width * .34, height * .16);
curveVertex(width * .41, height * .1);
curveVertex(width * .41, height * .1);
endShape();
////first brranch leaves
push();
translate(endOfBranchX, endOfBranchY + branchupdown);
drawShortWavyLeaf(teal, strokeColWavy1, -80 - (branchupdown / 1.5), 1);
pop();
push();
translate(endOfBranchX + addXSingle * 6, endOfBranchY + addYSingle * -1 + branchupdown);
drawShortWavyLeaf(slate_green, slate_green, -120 + (branchupdown / 1.3), .8);
pop();
push();
translate(endOfBranchX + addXSingle * 20, endOfBranchY + addYSingle * -3 + (branchupdown / 1.2));
drawShortWavyLeaf(teal, strokeColWavy1, -170, .8);
pop();
push(); //////behind the other leaves
translate(endOfBranchX + addXSingle * 167, endOfBranchY + addYSingle * 40);
drawShortWavyLeaf(slate_green, slate_green, -80, 0.93);
pop();
push(); //////behind the other leaves on other branch
translate(endOfBranchX + addXSingle * 157, endOfBranchY + addYSingle * 10);
drawShortWavyLeaf(slate_green, slate_green, 19, 0.8);
pop();
push();
translate(endOfBranchX + addXSingle * 100, endOfBranchY + addYSingle * -25 + (branchupdown / 1.9));
drawShortWavyLeaf(teal, strokeColWavy1, -20 - (branchupdown / 2), .75);
pop();
push();
translate(endOfBranchX + addXSingle * 48, endOfBranchY + addYSingle * -20 + (branchupdown / 1.5));
drawShortWavyLeaf(teal, strokeColWavy1, -50 + (branchupdown / 1.8), .82);
pop();
push();
translate(endOfBranchX + addXSingle * 68, endOfBranchY + addYSingle * -20 + (branchupdown / 1.6));
drawShortWavyLeaf(teal, strokeColWavy1, -200 + (branchupdown / 2), .93);
pop();
push();
translate(endOfBranchX + addXSingle * 118, endOfBranchY + addYSingle * -25);
drawShortWavyLeaf(teal, strokeColWavy1, -180, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 180, endOfBranchY + addYSingle * 90);
drawShortWavyLeaf(teal, strokeColWavy1, -100, .94);
pop();
push();
translate(endOfBranchX + addXSingle * 190, endOfBranchY + addYSingle * 120);
drawShortWavyLeaf(teal, strokeColWavy1, 40, 1.06);
pop();
push();
translate(endOfBranchX + addXSingle * 196, endOfBranchY + addYSingle * 150);
drawShortWavyLeaf(teal, strokeColWavy1, -87, 1.1);
pop();
///////////second branch (going right)
push();
translate(endOfBranchX + addXSingle * 187, endOfBranchY + addYSingle * 80);
drawShortWavyLeaf(teal, strokeColWavy1, 60, .9);
pop();
push();
translate(endOfBranchX + addXSingle * 191, endOfBranchY + addYSingle * 40);
drawShortWavyLeaf(teal, strokeColWavy1, 50, 1);
pop();
push();
translate(endOfBranchX + addXSingle * 201, endOfBranchY + addYSingle * -20);
drawShortWavyLeaf(teal, strokeColWavy1, 70, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 191, endOfBranchY + addYSingle * 20);
drawShortWavyLeaf(teal, strokeColWavy1, -35, .86);
pop();
push();
translate(endOfBranchX + addXSingle * 207, endOfBranchY + addYSingle * -45);
drawShortWavyLeaf(teal, strokeColWavy1, -45, .8);
pop();
push();
translate(endOfBranchX + addXSingle * 230, endOfBranchY + addYSingle * -71);
drawShortWavyLeaf(teal, strokeColWavy1, -25, .70);
pop();
push();
translate(endOfBranchX + addXSingle * 260, endOfBranchY + addYSingle * -81);
drawShortWavyLeaf(teal, strokeColWavy1, 5, .55);
pop();
push();
translate(endOfBranchX + addXSingle * 280, endOfBranchY + addYSingle * -84);
drawShortWavyLeaf(teal, strokeColWavy1, 28, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 280, endOfBranchY + addYSingle * -84);
drawShortWavyLeaf(teal, strokeColWavy1, 80, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 271, endOfBranchY + addYSingle * -80);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 271, endOfBranchY + addYSingle * -80);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .5);
pop();
push();
translate(endOfBranchX + addXSingle * 238, endOfBranchY + addYSingle * -73);
drawShortWavyLeaf(teal, strokeColWavy1, -250, .59);
pop();
//fly 1 (LEFT faster fly)///
//this fly is moving 0-1
flyScale = 0.6;
if (cur_frac <= 0.3) {
flyScale = map(cur_frac, 0, 0.3, 0, 0.6);
} else if (cur_frac >= 0.7) {
flyScale = map(cur_frac, 0.7, 1, 0.6, 0);
}
flyX = map(cur_frac, 0, 1, addXSingle * 300, addXSingle * 0)
push();
translate(width / 5 + flyX, height / 3.4);
drawFly(0, 0, cur_frac, flyScale,-1);
pop();
//////in front of branches on the left
push();
translate(width * .45, height * 1.1);
drawLongLeaf(0, 0, 1, -24, dull_greren, muted_green);
pop();
//short leaves in front on the LEFT //////////////////////////
push();
translate(width * .41, height * 1.1);
drawFatLeaf(-20 + (fatLeaf2Sway / -10), 1, -1, pale_olive);
pop();
push();
translate(width * .43, height * 1.1);
drawFatLeaf(10 + (fatLeaf2Sway / 1.2), 0.9, 1, fatLeafFill);
pop();
push();
translate(width * .37, height * 1.1);
drawFatLeaf(-56 + (fatLeaf2Sway / 1.8), 0.9, -1, fatLeafFill);
pop();
////////bottom left flowers
let backFloStartX = width * .19 + (flowerSway3 / 2.6);
let backFloStartY = height * .75;
//stalk 4 back flower
strokeWeight(addXSingle * 1.5);
stroke(longLeafFill3);
noFill();
beginShape();
curveVertex(backFloStartX - addXSingle * 16, backFloStartY);
curveVertex(backFloStartX - addXSingle * 16, backFloStartY);
curveVertex(width * .15, height * .88);
curveVertex(width * .16, height);
curveVertex(width * .16, height);
endShape();
push();
translate(backFloStartX, backFloStartY);
rotate(30);
scale(1.3);
drawFlower(0, 0, medium_spring_bud);
pop();
let bigFloStartX = width * .1 + flower2Sway;
let bigFloStartY = height * .8;
beginShape();
curveVertex(bigFloStartX, bigFloStartY);
curveVertex(bigFloStartX, bigFloStartY);
curveVertex(width * .135, height * .91);
curveVertex(width * .15, height);
curveVertex(width * .15, height);
endShape();
push();
translate(bigFloStartX, height * .8);
rotate(-40);
scale(1.3);
drawFlower(0, 0, flower_fill);
pop();
var smolFloX = width * .2 + flowerSway / 4;
var smolFloY = height * .85;
beginShape();
curveVertex(smolFloX, smolFloY);
curveVertex(smolFloX, smolFloY);
curveVertex(width * .17, height * .95);
curveVertex(width * .172, height);
curveVertex(width * .172, height);
endShape();
push();
translate(smolFloX, smolFloY);
rotate(10);
scale(1);
drawFlower(0, 0, flower_fill);
pop();
}
function drawShortWavyLeaf(fillCol, strokeColWavy, shortWavyRot, shortWavyScale) {
//drawn on the upper left
var addXSingle = width / 960;
var addYSingle = height / 540;
var shortWavyLeafX = 0;
var shortWavyLeafY = 0;
//
fill(fillCol);
push();
scale(shortWavyScale);
rotate(shortWavyRot);
noStroke();
beginShape();
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX + addXSingle * -9, shortWavyLeafY + addYSingle * -10);
curveVertex(shortWavyLeafX + addXSingle * -11, shortWavyLeafY + addYSingle * -18);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * -10, shortWavyLeafY + addYSingle * -40);
curveVertex(shortWavyLeafX + addXSingle * -12, shortWavyLeafY + addYSingle * -47);
curveVertex(shortWavyLeafX + addXSingle * -13, shortWavyLeafY + addYSingle * -55);
curveVertex(shortWavyLeafX + addXSingle * -11.5, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -65);
curveVertex(shortWavyLeafX + addXSingle * -9.5, shortWavyLeafY + addYSingle * -73);
curveVertex(shortWavyLeafX + addXSingle * -10, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * -8, shortWavyLeafY + addYSingle * -83);
curveVertex(shortWavyLeafX + addXSingle * -3, shortWavyLeafY + addYSingle * -88);
curveVertex(shortWavyLeafX, shortWavyLeafY + addYSingle * -95);
curveVertex(shortWavyLeafX + addXSingle * 2, shortWavyLeafY + addYSingle * -100);
curveVertex(shortWavyLeafX + addXSingle * 5, shortWavyLeafY + addYSingle * -92);
curveVertex(shortWavyLeafX + addXSingle * 10, shortWavyLeafY + addYSingle * -86);
curveVertex(shortWavyLeafX + addXSingle * 16, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 17.5, shortWavyLeafY + addYSingle * -73);
curveVertex(shortWavyLeafX + addXSingle * 16.5, shortWavyLeafY + addYSingle * -67);
curveVertex(shortWavyLeafX + addXSingle * 15, shortWavyLeafY + addYSingle * -59);
curveVertex(shortWavyLeafX + addXSingle * 18, shortWavyLeafY + addYSingle * -48);
curveVertex(shortWavyLeafX + addXSingle * 16, shortWavyLeafY + addYSingle * -40);
curveVertex(shortWavyLeafX + addXSingle * 13, shortWavyLeafY + addYSingle * -33);
curveVertex(shortWavyLeafX + addXSingle * 15, shortWavyLeafY + addYSingle * -20);
curveVertex(shortWavyLeafX + addXSingle * 13, shortWavyLeafY + addYSingle * -13);
curveVertex(shortWavyLeafX + addXSingle * 5.5, shortWavyLeafY + addYSingle * -6);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
endShape();
fill(strokeColWavy);
stroke(strokeColWavy);
strokeWeight(addXSingle);
beginShape();
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX + addXSingle * -2, shortWavyLeafY + addYSingle * -17);
curveVertex(shortWavyLeafX + addXSingle * 0, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * -1.3, shortWavyLeafY + addYSingle * -39);
curveVertex(shortWavyLeafX + addXSingle * .4, shortWavyLeafY + addYSingle * -50);
curveVertex(shortWavyLeafX + addXSingle * -.7, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * 1.7, shortWavyLeafY + addYSingle * -68);
curveVertex(shortWavyLeafX + addXSingle * 1, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 1.6, shortWavyLeafY + addYSingle * -87);
curveVertex(shortWavyLeafX + addXSingle * 3, shortWavyLeafY + addYSingle * -80);
curveVertex(shortWavyLeafX + addXSingle * 4.5, shortWavyLeafY + addYSingle * -68);
curveVertex(shortWavyLeafX + addXSingle * 3.5, shortWavyLeafY + addYSingle * -60);
curveVertex(shortWavyLeafX + addXSingle * 5, shortWavyLeafY + addYSingle * -50);
curveVertex(shortWavyLeafX + addXSingle * 2.3, shortWavyLeafY + addYSingle * -39);
curveVertex(shortWavyLeafX + addXSingle * 3.5, shortWavyLeafY + addYSingle * -28);
curveVertex(shortWavyLeafX + addXSingle * 1, shortWavyLeafY + addYSingle * -17);
curveVertex(shortWavyLeafX, shortWavyLeafY);
curveVertex(shortWavyLeafX, shortWavyLeafY);
endShape();
pop();
}
function drawFatLeaf(fatLeafRot, fatLeafYScal, negative, fatLeafFill) {
//drawn at the front of the screen normally, bright
push();
var addXSingle = width / 960 * negative;
var addYSingle = height / 540;
var fatLeafX = 0;
var fatLeafY = 0;
fill(fatLeafFill);
noStroke();
rotate(fatLeafRot);
scale(fatLeafYScal)
beginShape();
curveVertex(fatLeafY, fatLeafY);
curveVertex(fatLeafY, fatLeafY);
curveVertex(fatLeafX + addXSingle * -70, fatLeafY + addYSingle * -50);
curveVertex(fatLeafX + addXSingle * -80, fatLeafY + addYSingle * -90);
curveVertex(fatLeafX + addXSingle * -70, fatLeafY + addYSingle * -120);
curveVertex(fatLeafX + addXSingle * -60, fatLeafY + addYSingle * -140);
curveVertex(fatLeafX + addXSingle * -50, fatLeafY + addYSingle * -170);
curveVertex(fatLeafX + addXSingle * -57, fatLeafY + addYSingle * -200);
curveVertex(fatLeafX + addXSingle * -45, fatLeafY + addYSingle * -230);
curveVertex(fatLeafX + addXSingle * -4, fatLeafY + addYSingle * -260);
curveVertex(fatLeafX, fatLeafY + addYSingle * -262);
curveVertex(fatLeafX + addXSingle * 4, fatLeafY + addYSingle * -260);
curveVertex(fatLeafX + addXSingle * 45, fatLeafY + addYSingle * -230);
curveVertex(fatLeafX + addXSingle * 54, fatLeafY + addYSingle * -210);
curveVertex(fatLeafX + addXSingle * 45, fatLeafY + addYSingle * -190);
curveVertex(fatLeafX + addXSingle * 50, fatLeafY + addYSingle * -170);
curveVertex(fatLeafX + addXSingle * 65, fatLeafY + addYSingle * -150);
curveVertex(fatLeafX + addXSingle * 70, fatLeafY + addYSingle * -135);
curveVertex(fatLeafX + addXSingle * 60, fatLeafY + addYSingle * -105);
curveVertex(fatLeafX + addXSingle * 70, fatLeafY + addYSingle * -85);
curveVertex(fatLeafX + addXSingle * 78, fatLeafY + addYSingle * -65);
curveVertex(fatLeafX + addXSingle * 65, fatLeafY + addYSingle * -40);
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX, fatLeafY);
endShape();
stroke(118, 154, 87);
strokeWeight(height / 520 * 3);
noFill();
beginShape();
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX, fatLeafY);
curveVertex(fatLeafX + addXSingle * -1, fatLeafY + addYSingle * -35);
curveVertex(fatLeafX + addXSingle * 4, fatLeafY + addYSingle * -75);
curveVertex(fatLeafX + addXSingle * -5, fatLeafY + addYSingle * -115);
curveVertex(fatLeafX + addXSingle * 3, fatLeafY + addYSingle * -150);
curveVertex(fatLeafX + addXSingle * -4, fatLeafY + addYSingle * -175);
curveVertex(fatLeafX + addXSingle * 3, fatLeafY + addYSingle * -195);
curveVertex(fatLeafX + addXSingle * -2, fatLeafY + addYSingle * -210);
curveVertex(fatLeafX + addXSingle * 1, fatLeafY + addYSingle * -225);
//curveVertex(fatLeafX+addXSingle*1,fatLeafY+addYSingle*-225);
curveVertex(fatLeafX + addXSingle * -1, fatLeafY + addYSingle * -240);
curveVertex(fatLeafX + addXSingle, fatLeafY + addYSingle * -250);
curveVertex(fatLeafX + addXSingle, fatLeafY + addYSingle * -250);
endShape();
pop();
}
function drawSkinnyLongLeaf(skinnyLongLeafRot, skinnyLongLeafScale, skinnyLongLeafCol) {
//leaves on the rose branches
var addXSingle = width / 960;
var addYSingle = height / 540;
var skinnyLongLeafX = 0;
var skinnyLongLeafY = 0;
push();
rotate(skinnyLongLeafRot);
scale(skinnyLongLeafScale);
fill(skinnyLongLeafCol);
noStroke();
beginShape();
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX - addXSingle * 7, skinnyLongLeafY - addYSingle * 51);
curveVertex(skinnyLongLeafX - addXSingle * 1, skinnyLongLeafY - addYSingle * 100);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 105);
curveVertex(skinnyLongLeafX + addXSingle * 1, skinnyLongLeafY - addYSingle * 100);
curveVertex(skinnyLongLeafX + addXSingle * 8, skinnyLongLeafY - addYSingle * 49);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
curveVertex(skinnyLongLeafX, skinnyLongLeafY);
endShape();
stroke(45, 78, 109);
noFill();
strokeWeight(addXSingle * .7);
beginShape();
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 21);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 21);
curveVertex(skinnyLongLeafX + addXSingle * 1, skinnyLongLeafY - addYSingle * 49);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 80);
curveVertex(skinnyLongLeafX, skinnyLongLeafY - addYSingle * 80);
endShape();
pop();
}
function drawFly(flyX, flyY, cur_frac, flyScale,negative) {
let wingMove; //set up animated wing variable
var addXSingle = width / 960 * negative;
var addYSingle = height / 540;
var flyBodyCol = color(74, 77, 76);
var flyWingCol = color(166, 237, 234, 180);
//setting it up so the flies wings can flap more tha once a second
var wingFlapNum = 360 * 5 //how many times the wing flaps per second , multiples of 360
var flapAmmount = round(sin(map(cur_frac, 0, 1, 1, wingFlapNum)));
var flapAmmountSmooth = sin(map(cur_frac, 0, 1, 1, wingFlapNum));
if (flapAmmount == 0) {
wingMove = map(flapAmmountSmooth, 0, -1, 0, 10);
} else if (flapAmmount == -1) {
wingMove = map(flapAmmountSmooth, -1, 0, 10, 0);
}
noStroke();
fill(flyBodyCol);
scale(flyScale);
ellipse(flyX + addXSingle * 15, flyY, addXSingle * 17, addYSingle * 17); //head
ellipse(flyX, flyY, addXSingle * 30, addYSingle * 22); //body
rect(flyX + addXSingle * 21, flyY + addYSingle * 1, addXSingle * 8, -addYSingle * 4); //snout
ellipse(flyX + addXSingle * 30, flyY - addYSingle * 1, addXSingle * 4, addYSingle * 7) //end of snout
//wings!
fill(flyWingCol);
push();
rotate(35*negative + wingMove);
ellipse(flyX - addXSingle * 6, flyY - addYSingle * 1, addXSingle * 20, addYSingle * 10);
rotate(40*negative + wingMove);
ellipse(flyX - addXSingle * 11, flyY - addYSingle * 3, addXSingle * 30, addYSingle * 15);
pop();
}
function drawFlower(flowerBaseX, flowerBaseY, flowerFill) {
noStroke();
var addXSingle = width / 960; //1
var addYSingle = height / 540;
fill(flowerFill);
arc(flowerBaseX, flowerBaseY, addXSingle * 80, addYSingle * 70, 0, 180);
stroke(144, 179, 118);
strokeWeight(addXSingle);
beginShape();
curveVertex(flowerBaseX - addXSingle * 35, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 35, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 28, flowerBaseY - addYSingle * 18);
curveVertex(flowerBaseX - addXSingle * 24, flowerBaseY - addYSingle * 20);
curveVertex(flowerBaseX - addXSingle * 21, flowerBaseY - addYSingle * 19);
curveVertex(flowerBaseX - addXSingle * 17, flowerBaseY - addYSingle * 23);
curveVertex(flowerBaseX - addXSingle * 12, flowerBaseY - addYSingle * 25);
curveVertex(flowerBaseX - addXSingle * 6, flowerBaseY - addYSingle * 22);
curveVertex(flowerBaseX - addXSingle * 1, flowerBaseY - addYSingle * 27);
curveVertex(flowerBaseX + addXSingle * 2, flowerBaseY - addYSingle * 28);
curveVertex(flowerBaseX + addXSingle * 5, flowerBaseY - addYSingle * 27);
curveVertex(flowerBaseX + addXSingle * 10, flowerBaseY - addYSingle * 21);
curveVertex(flowerBaseX + addXSingle * 17, flowerBaseY - addYSingle * 23);
curveVertex(flowerBaseX + addXSingle * 20, flowerBaseY - addYSingle * 20);
curveVertex(flowerBaseX + addXSingle * 26, flowerBaseY - addYSingle * 21);
curveVertex(flowerBaseX + addXSingle * 30, flowerBaseY - addYSingle * 18);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY);
endShape();
beginShape();
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 3, flowerBaseY - addYSingle * 12);
curveVertex(flowerBaseX + addXSingle * 9, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX + addXSingle * 15, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX + addXSingle * 20, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX + addXSingle * 24, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX + addXSingle * 29, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 34, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX + addXSingle * 38, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX + addXSingle * 40, flowerBaseY);
endShape();
beginShape();
curveVertex(flowerBaseX - addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 40, flowerBaseY);
curveVertex(flowerBaseX - addXSingle * 38, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX - addXSingle * 32, flowerBaseY - addYSingle * 14);
curveVertex(flowerBaseX - addXSingle * 27, flowerBaseY - addYSingle * 10);
curveVertex(flowerBaseX - addXSingle * 20, flowerBaseY - addYSingle * 16);
curveVertex(flowerBaseX - addXSingle * 14, flowerBaseY - addYSingle * 12);
curveVertex(flowerBaseX - addXSingle * 10, flowerBaseY - addYSingle * 15);
curveVertex(flowerBaseX - addXSingle * 4, flowerBaseY - addYSingle * 11);
curveVertex(flowerBaseX - addXSingle * 2, flowerBaseY - addYSingle * 6);
curveVertex(flowerBaseX + addXSingle * 1, flowerBaseY - addYSingle * 7.5)
curveVertex(flowerBaseX + addXSingle * 6, flowerBaseY - addYSingle * 8);
curveVertex(flowerBaseX + addXSingle * 9, flowerBaseY - addYSingle * 6)
curveVertex(flowerBaseX + addXSingle * 11, flowerBaseY - addYSingle * 1);
curveVertex(flowerBaseX + addXSingle * 17, flowerBaseY - addYSingle * 2);
curveVertex(flowerBaseX + addXSingle * 22, flowerBaseY + addYSingle * 3);
curveVertex(flowerBaseX + addXSingle * 28, flowerBaseY + addYSingle * 3);
curveVertex(flowerBaseX + addXSingle * 36, flowerBaseY + addYSingle * 11);
curveVertex(flowerBaseX + addXSingle * 36, flowerBaseY + addYSingle * 11);
endShape();
}
function drawLongLeaf(longLeafBaseX, longLeafBaseY, longLeafScale, longLLeafRotation, longLeafFill, longLeafStrokeCol) {
//kelp looking leaf
noStroke();
angleMode(DEGREES);
push();
rotate(longLLeafRotation);
var longLeafAddXSingle = width / 960; //1
var longLeafAddYSingle = height / 540; // 1
scale(longLeafScale);
fill(longLeafFill);
beginShape();
curveVertex(longLeafBaseX - (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 50), longLeafBaseY - longLeafAddYSingle * 45);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 36), longLeafBaseY - longLeafAddYSingle * 80);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 41), longLeafBaseY - longLeafAddYSingle * 125);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 27), longLeafBaseY - longLeafAddYSingle * 156);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 31), longLeafBaseY - longLeafAddYSingle * 200);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 18), longLeafBaseY - longLeafAddYSingle * 235);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 22), longLeafBaseY - longLeafAddYSingle * 270);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 13), longLeafBaseY - longLeafAddYSingle * 295);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 11), longLeafBaseY - longLeafAddYSingle * 325);
curveVertex(longLeafBaseX - (longLeafAddXSingle * 2), longLeafBaseY - longLeafAddYSingle * 340);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 355);
vertex(longLeafBaseX + (longLeafAddXSingle * 14), longLeafBaseY - longLeafAddYSingle * 379);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 26), longLeafBaseY - longLeafAddYSingle * 365);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 24), longLeafBaseY - longLeafAddYSingle * 345);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 28), longLeafBaseY - longLeafAddYSingle * 330);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 25), longLeafBaseY - longLeafAddYSingle * 310);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 35), longLeafBaseY - longLeafAddYSingle * 285);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 30), longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 228);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 36), longLeafBaseY - longLeafAddYSingle * 200);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 45), longLeafBaseY - longLeafAddYSingle * 165);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY - longLeafAddYSingle * 132);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 49), longLeafBaseY - longLeafAddYSingle * 95);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 41), longLeafBaseY - longLeafAddYSingle * 57);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 50), longLeafBaseY - longLeafAddYSingle * 25);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY + longLeafAddYSingle * 12);
curveVertex(longLeafBaseX + (longLeafAddXSingle * 40), longLeafBaseY + longLeafAddYSingle * 12);
endShape();
stroke(longLeafStrokeCol);
noFill();
strokeWeight(longLeafAddXSingle * 4.5);
beginShape();
curveVertex(longLeafBaseX, longLeafBaseY + longLeafAddYSingle * 5);
curveVertex(longLeafBaseX, longLeafBaseY + longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 25);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 54);
curveVertex(longLeafBaseX + longLeafAddXSingle * 6, longLeafBaseY - longLeafAddYSingle * 85);
curveVertex(longLeafBaseX - longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 118);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 152);
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 211);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 238);
curveVertex(longLeafBaseX + longLeafAddXSingle * 11, longLeafBaseY - longLeafAddYSingle * 265);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 289);
curveVertex(longLeafBaseX + longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 313);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 335);
curveVertex(longLeafBaseX + longLeafAddXSingle * 12, longLeafBaseY - longLeafAddYSingle * 351);
curveVertex(longLeafBaseX + longLeafAddXSingle * 12, longLeafBaseY - longLeafAddYSingle * 351);
endShape();
noFill();
strokeWeight(longLeafAddXSingle * 3);
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 2, longLeafBaseY - longLeafAddYSingle * 5);
curveVertex(longLeafBaseX + longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 15);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 20);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 20);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 33);
curveVertex(longLeafBaseX - longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 40);
curveVertex(longLeafBaseX - longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 40);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 78);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 78);
curveVertex(longLeafBaseX + longLeafAddXSingle * 13, longLeafBaseY - longLeafAddYSingle * 85);
curveVertex(longLeafBaseX + longLeafAddXSingle * 33, longLeafBaseY - longLeafAddYSingle * 89);
curveVertex(longLeafBaseX + longLeafAddXSingle * 33, longLeafBaseY - longLeafAddYSingle * 89);
endShape();
beginShape();
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 105);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 105);
curveVertex(longLeafBaseX - longLeafAddXSingle * 13, longLeafBaseY - longLeafAddYSingle * 120);
curveVertex(longLeafBaseX - longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 122);
curveVertex(longLeafBaseX - longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 122);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 149);
curveVertex(longLeafBaseX + longLeafAddXSingle * 5, longLeafBaseY - longLeafAddYSingle * 149);
curveVertex(longLeafBaseX + longLeafAddXSingle * 14, longLeafBaseY - longLeafAddYSingle * 155);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 158);
curveVertex(longLeafBaseX + longLeafAddXSingle * 30, longLeafBaseY - longLeafAddYSingle * 158);
endShape();
beginShape();
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX - longLeafAddXSingle * 4, longLeafBaseY - longLeafAddYSingle * 185);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 192);
curveVertex(longLeafBaseX - longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 195);
curveVertex(longLeafBaseX - longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 195);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 210);
curveVertex(longLeafBaseX + longLeafAddXSingle * 7, longLeafBaseY - longLeafAddYSingle * 210);
curveVertex(longLeafBaseX + longLeafAddXSingle * 14, longLeafBaseY - longLeafAddYSingle * 219);
curveVertex(longLeafBaseX + longLeafAddXSingle * 26, longLeafBaseY - longLeafAddYSingle * 225);
curveVertex(longLeafBaseX + longLeafAddXSingle * 26, longLeafBaseY - longLeafAddYSingle * 225);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 8, longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX + longLeafAddXSingle * 8, longLeafBaseY - longLeafAddYSingle * 255);
curveVertex(longLeafBaseX, longLeafBaseY - longLeafAddYSingle * 262);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 265);
curveVertex(longLeafBaseX - longLeafAddXSingle * 10, longLeafBaseY - longLeafAddYSingle * 265);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 275);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 275);
curveVertex(longLeafBaseX + longLeafAddXSingle * 18, longLeafBaseY - longLeafAddYSingle * 280);
curveVertex(longLeafBaseX + longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 282);
curveVertex(longLeafBaseX + longLeafAddXSingle * 24, longLeafBaseY - longLeafAddYSingle * 282);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 311);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 311);
curveVertex(longLeafBaseX + longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 317);
curveVertex(longLeafBaseX - longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 319);
curveVertex(longLeafBaseX - longLeafAddXSingle * 3, longLeafBaseY - longLeafAddYSingle * 319);
endShape();
beginShape();
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 327);
curveVertex(longLeafBaseX + longLeafAddXSingle * 9, longLeafBaseY - longLeafAddYSingle * 327);
curveVertex(longLeafBaseX + longLeafAddXSingle * 15, longLeafBaseY - longLeafAddYSingle * 332);
curveVertex(longLeafBaseX + longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 334);
curveVertex(longLeafBaseX + longLeafAddXSingle * 19, longLeafBaseY - longLeafAddYSingle * 334);
endShape();
translate(width / 4, height / 4 * 3);
pop();
}
const ease = new p5.Ease();
function draw_one_frame(cur_frac) {
angleMode(DEGREES);
noStroke();
fill(191, 228, 255);
rect(0, 0, width, height); //background
noFill();
stroke(168, 207, 237); //tile shadows
strokeWeight(height*0.015);
for (let ii=0; ii<4; ii++){
for (let i=0; i<7; i++) {
line(width/14.8+width/7*i, 0, width/14.8+width/7*i, height);
line(0, width/14.8+width/7*ii, width, width/14.8+width/7*ii);
}
}
stroke(224, 242, 255); //tile grout
strokeWeight(height*0.005);
for (let ii=0; ii<4; ii++){
for (let i=0; i<7; i++) {
line(width/14+width/7*i, 0, width/14+width/7*i, height);
line(0, width/14+width/7*ii, width, width/14+width/7*ii);
}
}
let row1_x = 0.45 * width; //small row position
let sml2offset = 0.2 * width; //2nd small row offset
let sml3offset = -0.33 * width; //3rd small row offset
let row2_x = 0.3 * width; //medium row position
let mid2offset = 0.45 * width; //2nd medium row offset
let mid3offset = 0.5 * width; //3rd medium row offset
let row3_x = 0.6 * width; //big row position
let b1_size = height/10; //bubble sizes
let b2_size = height/7;
let b3_size = height/4.1;
const ease_frac = ease.smootherStep(cur_frac); //eased frames 0-1
let grid_points1 = [ //points along the path of bubbles
1.25 * height,
1.00 * height,
0.75 * height,
0.50 * height,
0.25 * height,
0.0 * height,
-0.25 * height
]
let wave_grid_points1 = []; //adjust grid points into wave pattern using noise
for (let i=0; i<grid_points1.length; i++) {
let wave = getNoiseValue(grid_points1[i], row1_x, 0, "wave_grid_points1", -b1_size*0.75, b1_size*0.75, 100);
wave_grid_points1.push(row1_x + wave);
}
let wave_grid_points1a = []; //another set of wave points for variation
for (let i=0; i<grid_points1.length; i++) {
let wave1 = getNoiseValue(grid_points1[i], row1_x, 0, "wave_grid_points1a", -b1_size*0.75, b1_size*0.75, 100);
wave_grid_points1a.push(row1_x + wave1);
}
//draw small bubbles
for(let i=0; i<grid_points1.length-1; i++) {
let cur_y_pos = map(cur_frac, 0, 1, grid_points1[i], grid_points1[i+1]);
let cur_x_pos = map(ease_frac, 0, 1, wave_grid_points1[i], wave_grid_points1[i+1]);
let cur_x_pos2 = map(ease_frac, 0, 1, wave_grid_points1a[i], wave_grid_points1a[i+1]);
drawBubble(cur_x_pos2, cur_y_pos, b1_size);
drawBubble(cur_x_pos+sml2offset, cur_y_pos-height*0.2, b1_size);
drawBubble(cur_x_pos+sml3offset, cur_y_pos-height*0.1, b1_size);
}
let grid_points2 = [
1.05 * height,
0.70 * height,
0.35 * height,
0 * height,
-0.35 * height
]
let wave_grid_points2 = [];
for (let i=0; i<grid_points2.length; i++) {
let wave2 = getNoiseValue(grid_points2[i], row2_x, 0, "wave_grid_points2", -b2_size*0.5, b2_size*0.5, 100);
wave_grid_points2.push(row2_x + wave2);
}
let wave_grid_points2a = [];
for (let i=0; i<grid_points2.length; i++) {
let wave2a = getNoiseValue(grid_points2[i], row2_x, 0, "wave_grid_points2a", -b2_size*0.5, b2_size*0.5, 100);
wave_grid_points2a.push(row2_x + wave2a);
}
//draw medium bubbles
for(let i=0; i<grid_points2.length-1; i++) {
let cur_y_pos = map(cur_frac, 0, 1, grid_points2[i], grid_points2[i+1]);
let cur_x_pos = map(ease_frac, 0, 1, wave_grid_points2[i], wave_grid_points2[i+1]);
let cur_x_pos2 = map(ease_frac, 0, 1, wave_grid_points1a[i], wave_grid_points1a[i+1]);
let cur_x_pos3 = map(ease_frac, 0, 1, wave_grid_points2a[i], wave_grid_points2a[i+1]);
drawBubble(cur_x_pos3, cur_y_pos, b2_size);
drawBubble(cur_x_pos+mid2offset, cur_y_pos+height*0.2, b2_size);
drawBubble(cur_x_pos2+mid3offset, cur_y_pos+height*0.1, b2_size);
}
let grid_points3 = [
1.10 * height,
0.60 * height,
0.10 * height,
-0.40 * height
]
let wave_grid_points3 = [];
for (let i=0; i<grid_points3.length; i++) {
let wave3 = getNoiseValue(grid_points3[i], row3_x, 0, "wave_grid_points3", -b3_size*0.35, b3_size*0.35, 100);
wave_grid_points3.push(row3_x + wave3);
}
//draw big bubbles
for(let i=0; i<grid_points3.length-1; i++) {
let cur_y_pos = map(cur_frac, 0, 1, grid_points3[i], grid_points3[i+1]);
let cur_x_pos = map(ease_frac, 0, 1, wave_grid_points3[i], wave_grid_points3[i+1]);
drawBubble(cur_x_pos, cur_y_pos, b3_size);
}
//drawing the cat
push();
scale(1.2);
translate(0,-height*0.15);
let change_direction = true; //set up variables for 50/50 back and forth
let amount_along = 0;
if (cur_frac < 0.5) {
change_direction = true;
amount_along = cur_frac * 2;
}
else {
change_direction = false;
amount_along = (cur_frac-0.5) * 2;
}
const eye_min = height*0.732;
const eye_max = height*0.768;
const ease_amount_along = ease.circularInOut(amount_along);
const ease_eyes = ease.circularInOut(cur_frac);
if(cur_frac <= 0.25){ //eyes move down for 1/4, up for 3/4
eye_y_pos = map(ease_amount_along, 0, 1, eye_min, eye_max);
}
else{
eye_y_pos = map(ease_eyes, 0, 1, eye_max, eye_min);
}
if(change_direction) { //tail flicking back and forth
tail_pos1 = map(ease_amount_along, 0, 1, height*0.325, height*0.375);
tail_pos2 = map(ease_amount_along, 0, 1, height*0.37, height*0.33);
tail_pos3 = map(ease_amount_along, 0, 1, height*0.36, height*0.34);
}
else {
tail_pos1 = map(ease_amount_along, 0, 1, height*0.375, height*0.325);
tail_pos2 = map(ease_amount_along, 0, 1, height*0.33, height*0.37);
tail_pos3 = map(ease_amount_along, 0, 1, height*0.34, height*0.36);
}
let catGrey = color(115, 131, 158);
let catLight = color(153, 170, 196);
let lightGreen = color(111, 189, 158);
let darkGreen = color(10, 144, 90);
noStroke();
fill(155, 194, 224, 185); //shadows
let shadowX = height*0.025;
let shadowY = height*0.05;
beginShape(); //ears shadow
curveVertex(height*0.08+shadowX, height*0.52+shadowY);
curveVertex(height*0.08+shadowX, height*0.52+shadowY);
curveVertex(height*0.23+shadowX, height*0.55+shadowY);
curveVertex(height*0.155+shadowX, height*0.625+shadowY);
curveVertex(height*0.155+shadowX, height*0.625+shadowY);
endShape(CLOSE);
beginShape();
curveVertex(height*0.08+shadowX, height*0.84+shadowY);
curveVertex(height*0.08+shadowX, height*0.84+shadowY);
curveVertex(height*0.23+shadowX, height*0.8+shadowY);
curveVertex(height*0.155+shadowX, height*0.735+shadowY);
curveVertex(height*0.155+shadowX, height*0.735+shadowY);
endShape(CLOSE);
fill(155, 194, 224, 205);
ellipse(width*0.005+shadowX, height*0.68+shadowY, height*0.31, height*0.36); //head shadow
noFill();
stroke(155, 194, 224, 185); //tail shadow
strokeWeight(height*0.07);
beginShape();
curveVertex(-height*0.05+shadowX, height*0.35+shadowY);
curveVertex(-height*0.05+shadowX, height*0.35+shadowY);
curveVertex(height*0.12+shadowX, tail_pos1+shadowY);
curveVertex(height*0.25+shadowX, tail_pos2+shadowY);
curveVertex(height*0.3+shadowX, tail_pos3+shadowY);
curveVertex(height*0.3+shadowX, tail_pos3+shadowY);
endShape();
strokeWeight(height*0.007); //whisker shadow
line(width*0.015+shadowX, height*0.858+shadowY, width*0.02+shadowX, height*0.88+shadowY);
line(width*0.001+shadowX, height*0.858+shadowY, width*0.005+shadowX, height*0.89+shadowY);
//end of shadows
noStroke();
fill(catGrey);
beginShape(); //ears
curveVertex(height*0.08, height*0.52);
curveVertex(height*0.08, height*0.52);
curveVertex(height*0.23, height*0.55);
curveVertex(height*0.13, height*0.64);
curveVertex(height*0.13, height*0.64);
endShape(CLOSE);
beginShape();
curveVertex(height*0.08, height*0.84);
curveVertex(height*0.08, height*0.84);
curveVertex(height*0.23, height*0.8);
curveVertex(height*0.13, height*0.72);
curveVertex(height*0.13, height*0.72);
endShape(CLOSE);
fill(103, 118, 143); //ear shading
beginShape();
curveVertex(height*0.08, height*0.84);
curveVertex(height*0.08, height*0.84);
curveVertex(height*0.23, height*0.8);
curveVertex(height*0.09, height*0.75);
curveVertex(height*0.09, height*0.75);
endShape(CLOSE);
push();
fill(catLight);
scale(0.6);
beginShape(); //inner ears
curveVertex(height*0.15, height*0.91);
curveVertex(height*0.15, height*0.91);
curveVertex(height*0.35, height*0.94);
curveVertex(height*0.25, height*1.03);
curveVertex(height*0.25, height*1.03);
endShape(CLOSE);
beginShape();
curveVertex(height*0.15, height*1.355);
curveVertex(height*0.15, height*1.355);
curveVertex(height*0.35, height*1.315);
curveVertex(height*0.25, height*1.235);
curveVertex(height*0.25, height*1.235);
endShape(CLOSE);
fill(143, 160, 186); //inner ear shading
beginShape();
curveVertex(height*0.15, height*1.355);
curveVertex(height*0.15, height*1.355);
curveVertex(height*0.35, height*1.317);
curveVertex(height*0.23, height*1.27);
curveVertex(height*0.23, height*1.27);
endShape(CLOSE);
pop();
fill(103, 118, 143); //head shading
ellipse(width*0.005, height*0.68, height*0.31, height*0.36);
fill(catGrey); //head
ellipse(width*0.005, height*0.67, height*0.295, height*0.345);
push();
translate(-height*0.003, height*0.012); //tail shading
noFill();
stroke(103, 118, 143);
strokeWeight(height*0.074);
beginShape();
curveVertex(-height*0.05, height*0.35);
curveVertex(-height*0.05, height*0.35);
curveVertex(height*0.12, tail_pos1);
curveVertex(height*0.25, tail_pos2);
curveVertex(height*0.3, tail_pos3);
curveVertex(height*0.3, tail_pos3);
endShape();
stroke(143, 160, 186);
strokeWeight(height*0.075);
strokeCap(SQUARE);
beginShape();
curveVertex(height*0.09, tail_pos1);
curveVertex(height*0.25, tail_pos2);
curveVertex(height*0.3, tail_pos3);
curveVertex(height*0.3, tail_pos3);
endShape();
noStroke();
fill(143, 160, 186);
ellipse(height*0.3, tail_pos3, height*0.075);
pop();
noFill();
stroke(catGrey); //drawing tail
strokeWeight(height*0.07);
beginShape();
curveVertex(-height*0.05, height*0.35);
curveVertex(-height*0.05, height*0.35);
curveVertex(height*0.12, tail_pos1);
curveVertex(height*0.25, tail_pos2);
curveVertex(height*0.3, tail_pos3);
curveVertex(height*0.3, tail_pos3);
endShape();
noStroke();
fill(143, 160, 186); //extra shading
ellipse(height*0.25, tail_pos2+height*0.033, height*0.031);
noFill();
stroke(catLight); //lighter end of tail
strokeWeight(height*0.071);
strokeCap(SQUARE);
beginShape();
curveVertex(height*0.09, tail_pos1);
curveVertex(height*0.25, tail_pos2);
curveVertex(height*0.3, tail_pos3);
curveVertex(height*0.3, tail_pos3);
endShape();
noStroke();
fill(catLight); //extra circles for end of tail
ellipse(height*0.3, tail_pos3, height*0.071);
ellipse(height*0.25, tail_pos2, height*0.031);
ellipse(height*0.25, tail_pos2+height*0.02, height*0.031);
ellipse(height*0.25, tail_pos2-height*0.02, height*0.031);
noStroke();
fill(lightGreen); //eyes
ellipse(width*0.025, height*0.75, height*0.055, height*0.06);
ellipse(width*0.025, height*0.61, height*0.055, height*0.06);
fill(lerpColor(lightGreen,darkGreen,0.25)); //eye gradient
ellipse(width*0.025, eye_y_pos, height*0.048, height*0.053);
ellipse(width*0.025, eye_y_pos-height*0.14, height*0.048, height*0.053);
fill(lerpColor(lightGreen,darkGreen,0.5));
ellipse(width*0.025, eye_y_pos, height*0.043, height*0.048);
ellipse(width*0.025, eye_y_pos-height*0.14, height*0.043, height*0.048);
fill(lerpColor(lightGreen,darkGreen,0.75));
ellipse(width*0.025, eye_y_pos, height*0.038, height*0.043);
ellipse(width*0.025, eye_y_pos-height*0.14, height*0.038, height*0.043);
fill(darkGreen);
ellipse(width*0.025, eye_y_pos, height*0.033, height*0.038);
ellipse(width*0.025, eye_y_pos-height*0.14, height*0.033, height*0.038);
fill(10); //pupils
ellipse(width*0.025, eye_y_pos, height*0.04, height*0.015);
ellipse(width*0.025, eye_y_pos-height*0.14, height*0.04, height*0.015);
fill(240, 245, 255); //shine
ellipse(width*0.023, height*0.73, height*0.01, height*0.015);
ellipse(width*0.023, height*0.59, height*0.01, height*0.015);
noFill(); //circle around eyes to cover extra circles
strokeWeight(height*0.05);
stroke(catGrey);
ellipse(width*0.025, height*0.75, height*0.105, height*0.11);
ellipse(width*0.025, height*0.61, height*0.105, height*0.11);
stroke(catLight); //whiskers
strokeCap(ROUND);
strokeWeight(height*0.007);
line(-width*0.018, height*0.72, width*0.02, height*0.88);
line(-width*0.018, height*0.72, width*0.005, height*0.89);
line(-width*0.018, height*0.64, width*0.02, height*0.48);
line(-width*0.018, height*0.64, width*0.005, height*0.47);
pop();
}
function drawBubble(x,y,s){
angleMode(DEGREES);
let b1_size = height/10; //bubble sizes
let b2_size = height/7;
let b3_size = height/4.1;
let green = color(82, 235, 150, 50);
let blue = color(70, 154, 250, 50);
let purple = color(191, 106, 247, 50);
let pink = color(252, 109, 248, 50);
noStroke();
fill(168, 207, 237, 150);
if(s==b3_size){
fill(168, 207, 237, 115);
ellipse(x+height*0.06,y+height*0.1,s*0.9);
}
else if(s==b2_size){
ellipse(x+height*0.04,y+height*0.054,s*0.9);
}
else{
ellipse(x+height*0.015,y+height*0.03,s*0.9);
}
noFill();
//colour gradient
strokeWeight(s*0.1);
stroke(green);
ellipse(x,y,s*0.3);
ellipse(x,y,s*0.333);
stroke(lerpColor(green,blue,0.33));
ellipse(x,y,s*0.366);
ellipse(x,y,s*0.4);
stroke(lerpColor(green,blue,0.66));
ellipse(x,y,s*0.433);
ellipse(x,y,s*0.466);
ellipse(x,y,s*0.5);
stroke(blue);
ellipse(x,y,s*0.533);
ellipse(x,y,s*0.566);
ellipse(x,y,s*0.6);
stroke(lerpColor(blue,purple,0.33));
ellipse(x,y,s*0.633);
ellipse(x,y,s*0.666);
ellipse(x,y,s*0.7);
ellipse(x,y,s*0.733);
stroke(lerpColor(blue,purple,0.66));
ellipse(x,y,s*0.766);
ellipse(x,y,s*0.8);
ellipse(x,y,s*0.833);
stroke(purple);
ellipse(x,y,s*0.866);
ellipse(x,y,s*0.9);
stroke(lerpColor(purple,pink,0.5));
ellipse(x,y,s*0.933);
stroke(pink);
strokeWeight(s*0.05);
ellipse(x,y,s*1);
//white highlights
stroke(255,230);
strokeWeight(s*0.05);
arc(x,y,s,s,-185,-70);
arc(x,y,s,s,-210,-200);
arc(x,y,s,s,25,80);
stroke(255,240);
strokeWeight(s*0.225);
arc(x,y,s/2,s/2,-180,-80);
strokeWeight(s*0.2);
arc(x,y,s/2,s/2,35,60);
}
/*
* FaceMap class - holds all informaiton about one mapped
* face and is able to draw itself.
*/
// remove this or set to false to enable full program (load will be slower)
var DEBUG_MODE = true;
// this can be used to set the number of sliders to show
var NUM_SLIDERS = 3;
// other variables can be in here too
const fg_color = [255];
// example of a global function
// given a segment, this returns the average point [x, y]
function segment_average(segment) {
let sum_x = 0;
let sum_y = 0;
let s_len = segment.length;
for (let i=0; i<s_len; i++) {
sum_x = sum_x + segment[i][0];
sum_y = sum_y + segment[i][1];
}
return [sum_x / s_len , sum_y / s_len ];
}
// This where you define your own face object
function Face() {
// these are state variables for a face
// (your variables should be different!)
this.eye_type = 1; // can be either 1 (cyclops) or 2 (two eyes)
this.eye_shift = -1; // range is -10 to 10
this.mouth_value = 1; // range is 0.5 to 8
// example of a function *inside* the face object.
// this draws a segment, and do_loop will connect the ends if true
this.draw_segment = function(segment, do_loop) {
for(let i=0; i<segment.length; i++) {
let px = segment[i][0];
let py = segment[i][1];
if(i < segment.length - 1) {
let nx = segment[i+1][0];
let ny = segment[i+1][1];
ellipse(px,py,.1)
line(px, py, nx, ny);
}
else if(do_loop) {
let nx = segment[0][0];
let ny = segment[0][1];
line(px, py, nx, ny);
}
}
};
/*
* Draw the face with position lists that include:
* chin, right_eye, left_eye, right_eyebrow, left_eyebrow
* bottom_lip, top_lip, nose_tip, nose_bridge,
*/
this.draw = function(positions) {
rectMode(CENTER)
strokeWeight(.01);
// eyebrows
stroke(fg_color);
let left_eyebrow_pos = segment_average(positions.left_eyebrow);
this.draw_segment(positions.left_eyebrow);
let right_eyebrow_pos = segment_average(positions.right_eyebrow);
this.draw_segment(positions.right_eyebrow);
// draw segments of face using points
stroke(fg_color);
this.draw_segment(positions.chin);
stroke(fg_color);
this.draw_segment(positions.nose_bridge);
let nose_tip_pos = segment_average(positions.nose_tip);
this.draw_segment(positions.nose_tip);
stroke(fg_color);
this.draw_segment(positions.top_lip);
let top_lip_pos = segment_average(positions.top_lip);
this.draw_segment(positions.bottom_lip);
stroke(fg_color);
let left_eye_pos = segment_average(positions.left_eye);
this.draw_segment(positions.left_eye, true);
let right_eye_pos = segment_average(positions.right_eye);
this.draw_segment(positions.right_eye, true);
// eyes
noStroke();
let curEyeShift = 0.04 * this.eye_shift;
fill(fg_color);
ellipse(left_eye_pos[0] + curEyeShift, left_eye_pos[1], 0.18);
ellipse(right_eye_pos[0] + curEyeShift, right_eye_pos[1], 0.18);
var gridSize = 3;
var cellSize = .75;
/*** TOM ADDED THIS LOOP #1 to "color in" the face ***/
// this is a lookup table that keeps track of previous cells
let leftmost_cell_in_row = [];
for (let y = -gridSize; y < gridSize; y+=cellSize) {
// each row we'll draw one line from left_x to right_x
let left_x = null;
let right_x = null;
for (let x = -gridSize; x < gridSize; x+=cellSize) {
let lastX = null;
let lastY = null;
for (let i = 0; i < positions.chin.length; i++) {
if (positions.chin[i][0] > (x - cellSize/2) && positions.chin[i][0] < (x + cellSize/2) && positions.chin[i][1] > (y - cellSize/2) && positions.chin[i][1] < (y + cellSize/2)) {
if (x != lastX && y != lastY) {
lastX = x;
lastY = y;
// first check if this is the first one
if (left_x == null) {
// just record this for both left and right
left_x = x;
right_x = x;
}
else if(x < left_x) {
// new left_x
left_x = x;
}
else if(x > right_x) {
right_x = x;
}
}
}
}
noFill();
stroke(200,50)
rect(x, y, cellSize, cellSize);
}
if (left_x != null) {
// now draw the line (series of cells)
fill(255,255,0);
stroke(200,10)
for(let j=left_x; j<=right_x; j+=cellSize) {
rect(j, y, cellSize, cellSize);
}
}
}
/*** END OF TOM'S ADDITONS ***/
for (let x = -gridSize; x < gridSize; x+=cellSize) {
for (let y = -gridSize; y < gridSize; y+=cellSize) {
let lastX = null;
let lastY = null;
if (left_eye_pos[0] > (x - cellSize/2) && left_eye_pos[0] < (x + cellSize/2) && left_eye_pos[1] > (y - cellSize/2) && left_eye_pos[1] < (y + cellSize/2)) {
if (this.eye_type === 1) {
eye1(x,y);
} else {
eye2(x,y);
}
} else if (right_eye_pos[0] > (x - cellSize/2) && right_eye_pos[0] < (x + cellSize/2) && right_eye_pos[1] > (y - cellSize/2) && right_eye_pos[1] < (y + cellSize/2)) {
if (this.eye_type === 1) {
eye1(x,y);
} else {
eye2(x,y);
}
} else if (positions.nose_bridge[0][0] > (x - cellSize/2) && positions.nose_bridge[0][0] < (x + cellSize/2) && positions.nose_bridge[0][1] > (y - cellSize/2) && positions.nose_bridge[0][1] < (y + cellSize/2)) {
noseBridge(x, y);
} else if (positions.nose_bridge[3][0] > (x - cellSize/2) && positions.nose_bridge[3][0] < (x + cellSize/2) && positions.nose_bridge[3][1] > (y - cellSize/2) && positions.nose_bridge[3][1] < (y + cellSize/2)) {
noseTip(x, y)
} else if (top_lip_pos[0] > (x - cellSize/2) && top_lip_pos[0] < (x + cellSize/2) && top_lip_pos[1] > (y - cellSize/2) && top_lip_pos[1] < (y + cellSize/2)) {
mouth(x, y);
} else if (left_eyebrow_pos[0] > (x - cellSize/2) && left_eyebrow_pos[0] < (x + cellSize/2) && left_eyebrow_pos[1] > (y - cellSize/2) && left_eyebrow_pos[1] < (y + cellSize/2)) {
eyebrow(x, y);
} else if (right_eyebrow_pos[0] > (x - cellSize/2) && right_eyebrow_pos[0] < (x + cellSize/2) && right_eyebrow_pos[1] > (y - cellSize/2) && right_eyebrow_pos[1] < (y + cellSize/2)) {
eyebrow(x, y);
} else {
for (let i = 0; i < positions.chin.length; i++) {
if (positions.chin[i][0] > (x - cellSize/2) && positions.chin[i][0] < (x + cellSize/2) && positions.chin[i][1] > (y - cellSize/2) && positions.chin[i][1] < (y + cellSize/2)) {
if (x != lastX && y != lastY) {
fill(255,0,0);
stroke(200,10)
lastX = x;
lastY = y;
rect(x, y, cellSize, cellSize);
}
}
}
}
noFill();
stroke(200,50)
rect(x, y, cellSize, cellSize);
}
}
// print(this.eye_type)
function eye1(x, y) {
fill(255, 0, 0);
beginShape()
vertex(x - cellSize/2, y - cellSize/2);
vertex(x + cellSize/2, y - cellSize/2);
vertex(x + cellSize/2, y + cellSize/2);
vertex(x - cellSize/2, y + cellSize/2);
endShape(CLOSE);
fill(255);
beginShape();
vertex(x - cellSize/2, y);
bezierVertex(x - cellSize/4, y, x - cellSize/4, y + cellSize/4, x, y + cellSize/4);
bezierVertex(x + cellSize/4, y + cellSize/4, x + cellSize/4, y, x + cellSize/2, y);
bezierVertex(x + cellSize/4, y, x + cellSize/4, y - cellSize/4, x, y - cellSize/4);
bezierVertex(x - cellSize/4, y - cellSize/4, x - cellSize/4, y, x - cellSize/2, y);
endShape();
fill(0)
ellipse(x,y,cellSize/4)
}
function eye2(x, y) {
fill(255, 0, 0);
beginShape()
vertex(x - cellSize/2, y - cellSize/2);
vertex(x + cellSize/2, y - cellSize/2);
vertex(x + cellSize/2, y + cellSize/2);
vertex(x - cellSize/2, y + cellSize/2);
endShape(CLOSE);
fill(255);
ellipse(x, y, cellSize)
fill(0)
ellipse(x,y,cellSize/4)
}
function noseBridge(x,y) {
fill(255,0,0)
beginShape();
vertex(x - cellSize/2, y - cellSize/2);
vertex(x + positions.nose_bridge[0][0], y - cellSize/2);
vertex(x + positions.nose_bridge[0][0], y + cellSize/2);
vertex(x - cellSize/2, y + cellSize/2);
endShape(CLOSE);
fill(255);
beginShape();
vertex(x + cellSize/2, y - cellSize/2);
vertex(x + positions.nose_bridge[0][0], y - cellSize/2);
vertex(x + positions.nose_bridge[0][0], y + cellSize/2);
vertex(x + cellSize/2, y + cellSize/2);
endShape(CLOSE);
}
function noseTip(x,y) {
fill(255,0,0)
beginShape();
vertex(x - cellSize/2, y + nose_tip_pos[1]);
vertex(x + cellSize/2, y + nose_tip_pos[1]);
vertex(x + cellSize/2, y + cellSize/2);
vertex(x - cellSize/2, y + cellSize/2);
endShape(CLOSE);
fill(255);
beginShape();
vertex(x - cellSize/2, y + nose_tip_pos[1]);
vertex(x + cellSize/2, y + nose_tip_pos[1]);
vertex(x + cellSize/2, y - cellSize/2);
vertex(x - cellSize/2, y - cellSize/2);
endShape(CLOSE);
}
function mouth(x,y) {
fill(255,0,0)
beginShape();
vertex(x - cellSize/2, y + cellSize/8);
vertex(x + cellSize/2, y + cellSize/8);
vertex(x + cellSize/2, y + cellSize/2);
vertex(x - cellSize/2, y + cellSize/2);
endShape(CLOSE);
fill(255,0,0)
beginShape();
vertex(x - cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y - cellSize/2);
vertex(x - cellSize/2, y - cellSize/2);
endShape(CLOSE);
fill(255)
beginShape();
vertex(x - cellSize/2, y + cellSize/8);
vertex(x - cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y + cellSize/8);
endShape(CLOSE);
}
function eyebrow(x,y) {
fill(255)
beginShape();
vertex(x - cellSize/2, y + cellSize/8);
vertex(x - cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y - cellSize/8);
vertex(x + cellSize/2, y + cellSize/8);
endShape(CLOSE);
}
}
/* set internal properties based on list numbers 0-100 */
this.setProperties = function(settings) {
this.eye_type = int(map(settings[0], 0, 100, 1, 2));
this.eye_shift = map(settings[1], 0, 100, -2, 2);
this.mouth_value = map(settings[2], 0, 100, 0.5, 8);
}
/* get internal properties as list of numbers 0-100 */
this.getProperties = function() {
let settings = new Array(3);
settings[0] = map(this.eye_type, 1, 2, 0, 100);
settings[1] = map(this.eye_shift, -2, 2, 0, 100);
settings[2] = map(this.mouth_value, 0.5, 8, 0, 100);
return settings;
}
}
/**
* This class lets you encode animated GIF files
* Base class : http://www.java2s.com/Code/Java/2D-Graphics-GUI/AnimatedGifEncoder.htm
* @author Kevin Weiner (original Java version - kweiner@fmsware.com)
* @author Thibault Imbert (AS3 version - bytearray.org)
* @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
* @version 0.1 AS3 implementation
*/
GIFEncoder = function() {
for (var i = 0, chr = {}; i < 256; i++)
chr[i] = String.fromCharCode(i);
function ByteArray() {
this.bin = [];
}
ByteArray.prototype.getData = function() {
for (var v = '', l = this.bin.length, i = 0; i < l; i++)
v += chr[this.bin[i]];
return v;
};
ByteArray.prototype.writeByte = function(val) {
this.bin.push(val);
};
ByteArray.prototype.writeUTFBytes = function(string) {
for (var l = string.length, i = 0; i < l; i++)
this.writeByte(string.charCodeAt(i));
};
ByteArray.prototype.writeBytes = function(array, offset, length) {
for (var l = length || array.length, i = offset || 0; i < l; i++)
this.writeByte(array[i]);
};
var exports = {};
var width; // image size
var height;
var transparent = null; // transparent color if given
var transIndex; // transparent index in color table
var repeat = -1; // no repeat
var delay = 0; // frame delay (hundredths)
var started = false; // ready to output frames
var out;
var image; // current frame
var pixels; // BGR byte array from frame
var indexedPixels; // converted frame indexed to palette
var colorDepth; // number of bit planes
var colorTab; // RGB palette
var usedEntry = []; // active palette entries
var palSize = 7; // color table size (bits-1)
var dispose = -1; // disposal code (-1 = use default)
var closeStream = false; // close stream when finished
var firstFrame = true;
var sizeSet = false; // if false, get size from first frame
var sample = 10; // default sample interval for quantizer
var comment = "Generated by jsgif (https://github.com/antimatter15/jsgif/)"; // default comment for generated gif
/**
* Sets the delay time between each frame, or changes it for subsequent frames
* (applies to last frame added)
* int delay time in milliseconds
* @param ms
*/
var setDelay = exports.setDelay = function setDelay(ms) {
delay = Math.round(ms / 10);
};
/**
* Sets the GIF frame disposal code for the last added frame and any
*
* subsequent frames. Default is 0 if no transparent color has been set,
* otherwise 2.
* @param code
* int disposal code.
*/
var setDispose = exports.setDispose = function setDispose(code) {
if (code >= 0) dispose = code;
};
/**
* Sets the number of times the set of GIF frames should be played. Default is
* 1; 0 means play indefinitely. Must be invoked before the first image is
* added.
*
* @param iter
* int number of iterations.
* @return
*/
var setRepeat = exports.setRepeat = function setRepeat(iter) {
if (iter >= 0) repeat = iter;
};
/**
* Sets the transparent color for the last added frame and any subsequent
* frames. Since all colors are subject to modification in the quantization
* process, the color in the final palette for each frame closest to the given
* color becomes the transparent color for that frame. May be set to null to
* indicate no transparent color.
* @param
* Color to be treated as transparent on display.
*/
var setTransparent = exports.setTransparent = function setTransparent(c) {
transparent = c;
};
/**
* Sets the comment for the block comment
* @param
* string to be insterted as comment
*/
var setComment = exports.setComment = function setComment(c) {
comment = c;
};
/**
* The addFrame method takes an incoming BitmapData object to create each frames
* @param
* BitmapData object to be treated as a GIF's frame
*/
var addFrame = exports.addFrame = function addFrame(im, is_imageData) {
if ((im === null) || !started || out === null) {
throw new Error("Please call start method before calling addFrame");
}
var ok = true;
try {
if (!is_imageData) {
image = im.getImageData(0, 0, im.canvas.width, im.canvas.height).data;
if (!sizeSet) setSize(im.canvas.width, im.canvas.height);
} else {
if(im instanceof ImageData) {
image = im.data;
if(!sizeset || width!=im.width || height!=im.height) {
setSize(im.width,im.height);
} else {
}
} else if(im instanceof Uint8ClampedArray) {
if(im.length==(width*height*4)) {
image=im;
} else {
console.log("Please set the correct size: ImageData length mismatch");
ok=false;
}
} else {
console.log("Please provide correct input");
ok=false;
}
}
getImagePixels(); // convert to correct format if necessary
analyzePixels(); // build color table & map pixels
if (firstFrame) {
writeLSD(); // logical screen descriptior
writePalette(); // global color table
if (repeat >= 0) {
// use NS app extension to indicate reps
writeNetscapeExt();
}
}
writeGraphicCtrlExt(); // write graphic control extension
if (comment !== '') {
writeCommentExt(); // write comment extension
}
writeImageDesc(); // image descriptor
if (!firstFrame) writePalette(); // local color table
writePixels(); // encode and write pixel data
firstFrame = false;
} catch (e) {
ok = false;
}
return ok;
};
/**
* @description: Downloads the encoded gif with the given name
* No need of any conversion from the stream data (out) to base64
* Solves the issue of large file sizes when there are more frames
* and does not involve in creation of any temporary data in the process
* so no wastage of memory, and speeds up the process of downloading
* to just calling this function.
* @parameter {String} filename filename used for downloading the gif
*/
var download = exports.download = function download(filename) {
if(out===null || closeStream==false) {
console.log("Please call start method and add frames and call finish method before calling download");
} else {
filename= filename !== undefined ? ( filename.endsWith(".gif")? filename: filename+".gif" ): "download.gif";
var templink = document.createElement("a");
templink.download=filename;
templink.href= URL.createObjectURL(new Blob([new Uint8Array(out.bin)], {type : "image/gif" } ));
templink.click();
}
}
/**
* Adds final trailer to the GIF stream, if you don't call the finish method
* the GIF stream will not be valid.
*/
var finish = exports.finish = function finish() {
if (!started) return false;
var ok = true;
started = false;
try {
out.writeByte(0x3b); // gif trailer
closeStream=true;
} catch (e) {
ok = false;
}
return ok;
};
/**
* Resets some members so that a new stream can be started.
* This method is actually called by the start method
*/
var reset = function reset() {
// reset for subsequent use
transIndex = 0;
image = null;
pixels = null;
indexedPixels = null;
colorTab = null;
closeStream = false;
firstFrame = true;
};
/**
* * Sets frame rate in frames per second. Equivalent to
* <code>setDelay(1000/fps)</code>.
* @param fps
* float frame rate (frames per second)
*/
var setFrameRate = exports.setFrameRate = function setFrameRate(fps) {
if (fps != 0xf) delay = Math.round(100 / fps);
};
/**
* Sets quality of color quantization (conversion of images to the maximum 256
* colors allowed by the GIF specification). Lower values (minimum = 1)
* produce better colors, but slow processing significantly. 10 is the
* default, and produces good color mapping at reasonable speeds. Values
* greater than 20 do not yield significant improvements in speed.
* @param quality
* int greater than 0.
* @return
*/
var setQuality = exports.setQuality = function setQuality(quality) {
if (quality < 1) quality = 1;
sample = quality;
};
/**
* Sets the GIF frame size. The default size is the size of the first frame
* added if this method is not invoked.
* @param w
* int frame width.
* @param h
* int frame width.
*/
var setSize = exports.setSize = function setSize(w, h) {
if (started && !firstFrame) return;
width = w;
height = h;
if (width < 1) width = 320;
if (height < 1) height = 240;
sizeSet = true;
};
/**
* Initiates GIF file creation on the given stream.
* @param os
* OutputStream on which GIF images are written.
* @return false if initial write failed.
*/
var start = exports.start = function start() {
reset();
var ok = true;
closeStream = false;
out = new ByteArray();
try {
out.writeUTFBytes("GIF89a"); // header
} catch (e) {
ok = false;
}
return started = ok;
};
var cont = exports.cont = function cont() {
reset();
var ok = true;
closeStream = false;
out = new ByteArray();
return started = ok;
};
/**
* Analyzes image colors and creates color map.
*/
var analyzePixels = function analyzePixels() {
var len = pixels.length;
var nPix = len / 3;
indexedPixels = [];
var nq = new NeuQuant(pixels, len, sample);
// initialize quantizer
colorTab = nq.process(); // create reduced palette
// map image pixels to new palette
var k = 0;
for (var j = 0; j < nPix; j++) {
var index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff);
usedEntry[index] = true;
indexedPixels[j] = index;
}
pixels = null;
colorDepth = 8;
palSize = 7;
// get closest match to transparent color if specified
if (transparent !== null) {
transIndex = findClosest(transparent);
}
};
/**
* Returns index of palette color closest to c
*/
var findClosest = function findClosest(c) {
if (colorTab === null) return -1;
var r = (c & 0xFF0000) >> 16;
var g = (c & 0x00FF00) >> 8;
var b = (c & 0x0000FF);
var minpos = 0;
var dmin = 256 * 256 * 256;
var len = colorTab.length;
for (var i = 0; i < len;) {
var dr = r - (colorTab[i++] & 0xff);
var dg = g - (colorTab[i++] & 0xff);
var db = b - (colorTab[i] & 0xff);
var d = dr * dr + dg * dg + db * db;
var index = i / 3;
if (usedEntry[index] && (d < dmin)) {
dmin = d;
minpos = index;
}
i++;
}
return minpos;
};
/**
* Extracts image pixels into byte array "pixels
*/
var getImagePixels = function getImagePixels() {
var w = width;
var h = height;
pixels = [];
var data = image;
var count = 0;
for (var i = 0; i < h; i++) {
for (var j = 0; j < w; j++) {
var b = (i * w * 4) + j * 4;
pixels[count++] = data[b];
pixels[count++] = data[b + 1];
pixels[count++] = data[b + 2];
}
}
};
/**
* Writes Graphic Control Extension
*/
var writeGraphicCtrlExt = function writeGraphicCtrlExt() {
out.writeByte(0x21); // extension introducer
out.writeByte(0xf9); // GCE label
out.writeByte(4); // data block size
var transp;
var disp;
if (transparent === null) {
transp = 0;
disp = 0; // dispose = no action
} else {
transp = 1;
disp = 2; // force clear if using transparent color
}
if (dispose >= 0) {
disp = dispose & 7; // user override
}
disp <<= 2;
// packed fields
out.writeByte(0 | // 1:3 reserved
disp | // 4:6 disposal
0 | // 7 user input - 0 = none
transp); // 8 transparency flag
WriteShort(delay); // delay x 1/100 sec
out.writeByte(transIndex); // transparent color index
out.writeByte(0); // block terminator
};
/**
* Writes Comment Extention
*/
var writeCommentExt = function writeCommentExt() {
out.writeByte(0x21); // extension introducer
out.writeByte(0xfe); // comment label
out.writeByte(comment.length); // Block Size (s)
out.writeUTFBytes(comment);
out.writeByte(0); // block terminator
};
/**
* Writes Image Descriptor
*/
var writeImageDesc = function writeImageDesc() {
out.writeByte(0x2c); // image separator
WriteShort(0); // image position x,y = 0,0
WriteShort(0);
WriteShort(width); // image size
WriteShort(height);
// packed fields
if (firstFrame) {
// no LCT - GCT is used for first (or only) frame
out.writeByte(0);
} else {
// specify normal LCT
out.writeByte(0x80 | // 1 local color table 1=yes
0 | // 2 interlace - 0=no
0 | // 3 sorted - 0=no
0 | // 4-5 reserved
palSize); // 6-8 size of color table
}
};
/**
* Writes Logical Screen Descriptor
*/
var writeLSD = function writeLSD() {
// logical screen size
WriteShort(width);
WriteShort(height);
// packed fields
out.writeByte((0x80 | // 1 : global color table flag = 1 (gct used)
0x70 | // 2-4 : color resolution = 7
0x00 | // 5 : gct sort flag = 0
palSize)); // 6-8 : gct size
out.writeByte(0); // background color index
out.writeByte(0); // pixel aspect ratio - assume 1:1
};
/**
* Writes Netscape application extension to define repeat count.
*/
var writeNetscapeExt = function writeNetscapeExt() {
out.writeByte(0x21); // extension introducer
out.writeByte(0xff); // app extension label
out.writeByte(11); // block size
out.writeUTFBytes("NETSCAPE" + "2.0"); // app id + auth code
out.writeByte(3); // sub-block size
out.writeByte(1); // loop sub-block id
WriteShort(repeat); // loop count (extra iterations, 0=repeat forever)
out.writeByte(0); // block terminator
};
/**
* Writes color table
*/
var writePalette = function writePalette() {
out.writeBytes(colorTab);
var n = (3 * 256) - colorTab.length;
for (var i = 0; i < n; i++) out.writeByte(0);
};
var WriteShort = function WriteShort(pValue) {
out.writeByte(pValue & 0xFF);
out.writeByte((pValue >> 8) & 0xFF);
};
/**
* Encodes and writes pixel data
*/
var writePixels = function writePixels() {
var myencoder = new LZWEncoder(width, height, indexedPixels, colorDepth);
myencoder.encode(out);
};
/**
* Retrieves the GIF stream
*/
var stream = exports.stream = function stream() {
return out;
};
var setProperties = exports.setProperties = function setProperties(has_start, is_first) {
started = has_start;
firstFrame = is_first;
};
return exports;
};
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js"></script>
<script src="https://d3js.org/d3-random.v1.min.js"></script>
<script language="javascript" type="text/javascript" src="p5.func.js"></script>
<script type="text/javascript" src="LZWEncoder.js"></script>
<script type="text/javascript" src="NeuQuant.js"></script>
<script type="text/javascript" src="GIFEncoder.js"></script>
<script type="text/javascript" src="b64.js"></script>
<script type="text/javascript" src="z_recorder.js"></script>
<script language="javascript" type="text/javascript" src="simplex-noise.js"></script>
<script language="javascript" type="text/javascript" src="canvas_size.js"></script>
<script language="javascript" type="text/javascript" src="draw_one_frame.js"></script>
<script src="z_clmtrackr.js"></script>
<script src="z_model_pca_20_svm.js"></script>
<script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="z_focused_random.js"></script>
<script language="javascript" type="text/javascript" src="z_face_system.js"></script>
<script language="javascript" type="text/javascript" src="z_kdTree.js"></script>
<script language="javascript" type="text/javascript" src="z_face-api.js"></script>
<script language="javascript" type="text/javascript" src="z_training_images.js"></script>
<script language="javascript" type="text/javascript" src="z_testing_images.js"></script>
<script language="javascript" type="text/javascript" src="face.js"></script>
<script language="javascript" type="text/javascript" src="system_runner.js"></script>
<style>
body { padding: 0; margin: 0; }
.inner { position: absolute; }
#controls {
font: 300 12px "Helvetica Neue";
padding: 5;
margin: 5;
background: #f0f0f0;
opacity: 0.0;
-webkit-transition: opacity 0.2s ease;
-moz-transition: opacity 0.2s ease;
-o-transition: opacity 0.2s ease;
-ms-transition: opacity 0.2s ease;
}
#controls:hover { opacity: 0.9; }
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner" id="controls" height="500">
<table>
<tr>
<td>setting 1</td>
<td id="slider1Container"></td>
</tr>
<tr>
<td>setting 2</td>
<td id="slider2Container"></td>
</tr>
<tr>
<td>setting 3</td>
<td id="slider3Container"></td>
</tr>
<tr>
<td>setting 4</td>
<td id="slider4Container"></td>
</tr>
<tr>
<td>setting 5</td>
<td id="slider5Container"></td>
</tr>
<tr>
<td>setting 6</td>
<td id="slider6Container"></td>
</tr>
<tr>
<td>setting 7</td>
<td id="slider7Container"></td>
</tr>
<tr>
<td>setting 8</td>
<td id="slider8Container"></td>
</tr>
<!-- YOU CAN ADD MORE SLIDERS HERE, LIKE THIS
<tr>
<td>setting 9</td>
<td id="slider9Container"></td>
</tr>
<tr>
<td>setting 10</td>
<td id="slider10Container"></td>
</tr>
<tr>
<td>setting 11</td>
<td id="slider11Container"></td>
</tr>
<tr>
<td>setting 12</td>
<td id="slider12Container"></td>
</tr>
... AND KEEP GOING
-->
<tr>
</tr>
<tr>
<td>show target</td>
<td id="sliderTintContainer"></td>
</tr>
<tr>
<td>Draw function</td>
<td id="selector1Container"></td>
</tr>
<tr>
<td>Face Draw</td>
<td id="checkbox1Container"></td>
</tr>
<tr>
<td>Face Targets</td>
<td id="checkbox2Container"></td>
</tr>
<tr>
<td>Face Points</td>
<td id="checkbox3Container"></td>
</tr>
<tr>
<td></td>
<td id="button1Container"></td>
</tr>
<tr>
<td></td>
<td id="button2Container"></td>
</tr>
<tr>
<td></td>
<td id="button3Container"></td>
</tr>
<tr>
<td></td>
<td id="button4Container"></td>
</tr>
</table>
</div>
<div>
<div id="canvasContainer"></div>
<a href="face.js">face code</a><br>
<a href="sketch.html">sketches</a>
</div>
</div>
<pre>
<p id="output">
</p>
</pre>
</body>
/**
* This class handles LZW encoding
* Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott.
* @author Kevin Weiner (original Java version - kweiner@fmsware.com)
* @author Thibault Imbert (AS3 version - bytearray.org)
* @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
* @version 0.1 AS3 implementation
*/
LZWEncoder = function() {
var exports = {};
var EOF = -1;
var imgW;
var imgH;
var pixAry;
var initCodeSize;
var remaining;
var curPixel;
// GIFCOMPR.C - GIF Image compression routines
// Lempel-Ziv compression based on 'compress'. GIF modifications by
// David Rowley (mgardi@watdcsu.waterloo.edu)
// General DEFINEs
var BITS = 12;
var HSIZE = 5003; // 80% occupancy
// GIF Image compression - modified 'compress'
// Based on: compress.c - File compression ala IEEE Computer, June 1984.
// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
// Jim McKie (decvax!mcvax!jim)
// Steve Davies (decvax!vax135!petsd!peora!srd)
// Ken Turkowski (decvax!decwrl!turtlevax!ken)
// James A. Woods (decvax!ihnp4!ames!jaw)
// Joe Orost (decvax!vax135!petsd!joe)
var n_bits; // number of bits/code
var maxbits = BITS; // user settable max # bits/code
var maxcode; // maximum code, given n_bits
var maxmaxcode = 1 << BITS; // should NEVER generate this code
var htab = [];
var codetab = [];
var hsize = HSIZE; // for dynamic table sizing
var free_ent = 0; // first unused entry
// block compression parameters -- after all codes are used up,
// and compression rate changes, start over.
var clear_flg = false;
// Algorithm: use open addressing double hashing (no chaining) on the
// prefix code / next character combination. We do a variant of Knuth's
// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
// secondary probe. Here, the modular division first probe is gives way
// to a faster exclusive-or manipulation. Also do block compression with
// an adaptive reset, whereby the code table is cleared when the compression
// ratio decreases, but after the table fills. The variable-length output
// codes are re-sized at this point, and a special CLEAR code is generated
// for the decompressor. Late addition: construct the table according to
// file size for noticeable speed improvement on small files. Please direct
// questions about this implementation to ames!jaw.
var g_init_bits;
var ClearCode;
var EOFCode;
// output
// Output the given code.
// Inputs:
// code: A n_bits-bit integer. If == -1, then EOF. This assumes
// that n_bits =< wordsize - 1.
// Outputs:
// Outputs code to the file.
// Assumptions:
// Chars are 8 bits long.
// Algorithm:
// Maintain a BITS character long buffer (so that 8 codes will
// fit in it exactly). Use the VAX insv instruction to insert each
// code in turn. When the buffer fills up empty it and start over.
var cur_accum = 0;
var cur_bits = 0;
var masks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF];
// Number of characters so far in this 'packet'
var a_count;
// Define the storage for the packet accumulator
var accum = [];
var LZWEncoder = exports.LZWEncoder = function LZWEncoder(width, height, pixels, color_depth) {
imgW = width;
imgH = height;
pixAry = pixels;
initCodeSize = Math.max(2, color_depth);
};
// Add a character to the end of the current packet, and if it is 254
// characters, flush the packet to disk.
var char_out = function char_out(c, outs) {
accum[a_count++] = c;
if (a_count >= 254) flush_char(outs);
};
// Clear out the hash table
// table clear for block compress
var cl_block = function cl_block(outs) {
cl_hash(hsize);
free_ent = ClearCode + 2;
clear_flg = true;
output(ClearCode, outs);
};
// reset code table
var cl_hash = function cl_hash(hsize) {
for (var i = 0; i < hsize; ++i) htab[i] = -1;
};
var compress = exports.compress = function compress(init_bits, outs) {
var fcode;
var i; /* = 0 */
var c;
var ent;
var disp;
var hsize_reg;
var hshift;
// Set up the globals: g_init_bits - initial number of bits
g_init_bits = init_bits;
// Set up the necessary values
clear_flg = false;
n_bits = g_init_bits;
maxcode = MAXCODE(n_bits);
ClearCode = 1 << (init_bits - 1);
EOFCode = ClearCode + 1;
free_ent = ClearCode + 2;
a_count = 0; // clear packet
ent = nextPixel();
hshift = 0;
for (fcode = hsize; fcode < 65536; fcode *= 2)
++hshift;
hshift = 8 - hshift; // set hash code range bound
hsize_reg = hsize;
cl_hash(hsize_reg); // clear hash table
output(ClearCode, outs);
outer_loop: while ((c = nextPixel()) != EOF) {
fcode = (c << maxbits) + ent;
i = (c << hshift) ^ ent; // xor hashing
if (htab[i] == fcode) {
ent = codetab[i];
continue;
}
else if (htab[i] >= 0) { // non-empty slot
disp = hsize_reg - i; // secondary hash (after G. Knott)
if (i === 0) disp = 1;
do {
if ((i -= disp) < 0)
i += hsize_reg;
if (htab[i] == fcode) {
ent = codetab[i];
continue outer_loop;
}
} while (htab[i] >= 0);
}
output(ent, outs);
ent = c;
if (free_ent < maxmaxcode) {
codetab[i] = free_ent++; // code -> hashtable
htab[i] = fcode;
}
else cl_block(outs);
}
// Put out the final code.
output(ent, outs);
output(EOFCode, outs);
};
// ----------------------------------------------------------------------------
var encode = exports.encode = function encode(os) {
os.writeByte(initCodeSize); // write "initial code size" byte
remaining = imgW * imgH; // reset navigation variables
curPixel = 0;
compress(initCodeSize + 1, os); // compress and write the pixel data
os.writeByte(0); // write block terminator
};
// Flush the packet to disk, and reset the accumulator
var flush_char = function flush_char(outs) {
if (a_count > 0) {
outs.writeByte(a_count);
outs.writeBytes(accum, 0, a_count);
a_count = 0;
}
};
var MAXCODE = function MAXCODE(n_bits) {
return (1 << n_bits) - 1;
};
// ----------------------------------------------------------------------------
// Return the next pixel from the image
// ----------------------------------------------------------------------------
var nextPixel = function nextPixel() {
if (remaining === 0) return EOF;
--remaining;
var pix = pixAry[curPixel++];
return pix & 0xff;
};
var output = function output(code, outs) {
cur_accum &= masks[cur_bits];
if (cur_bits > 0) cur_accum |= (code << cur_bits);
else cur_accum = code;
cur_bits += n_bits;
while (cur_bits >= 8) {
char_out((cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
// If the next entry is going to be too big for the code size,
// then increase it, if possible.
if (free_ent > maxcode || clear_flg) {
if (clear_flg) {
maxcode = MAXCODE(n_bits = g_init_bits);
clear_flg = false;
} else {
++n_bits;
if (n_bits == maxbits) maxcode = maxmaxcode;
else maxcode = MAXCODE(n_bits);
}
}
if (code == EOFCode) {
// At EOF, write the rest of the buffer.
while (cur_bits > 0) {
char_out((cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
flush_char(outs);
}
};
LZWEncoder.apply(this, arguments);
return exports;
};
/*
* NeuQuant Neural-Net Quantization Algorithm
* ------------------------------------------
*
* Copyright (c) 1994 Anthony Dekker
*
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See
* "Kohonen neural networks for optimal colour quantization" in "Network:
* Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of
* the algorithm.
*
* Any party obtaining a copy of these files from the author, directly or
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
* world-wide, paid up, royalty-free, nonexclusive right and license to deal in
* this software and documentation files (the "Software"), including without
* limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons who
* receive copies from any such party to do so, with the only requirement being
* that this copyright notice remain intact.
*/
/*
* This class handles Neural-Net quantization algorithm
* @author Kevin Weiner (original Java version - kweiner@fmsware.com)
* @author Thibault Imbert (AS3 version - bytearray.org)
* @author Kevin Kwok (JavaScript version - https://github.com/antimatter15/jsgif)
* @version 0.1 AS3 implementation
*/
NeuQuant = function() {
var exports = {};
var netsize = 256; /* number of colours used */
/* four primes near 500 - assume no image has a length so large */
/* that it is divisible by all four primes */
var prime1 = 499;
var prime2 = 491;
var prime3 = 487;
var prime4 = 503;
var minpicturebytes = (3 * prime4); /* minimum size for input image */
/*
* Program Skeleton ---------------- [select samplefac in range 1..30] [read
* image from input file] pic = (unsigned char*) malloc(3*width*height);
* initnet(pic,3*width*height,samplefac); learn(); unbiasnet(); [write output
* image header, using writecolourmap(f)] inxbuild(); write output image using
* inxsearch(b,g,r)
*/
/*
* Network Definitions -------------------
*/
var maxnetpos = (netsize - 1);
var netbiasshift = 4; /* bias for colour values */
var ncycles = 100; /* no. of learning cycles */
/* defs for freq and bias */
var intbiasshift = 16; /* bias for fractions */
var intbias = (1 << intbiasshift);
var gammashift = 10; /* gamma = 1024 */
var gamma = (1 << gammashift);
var betashift = 10;
var beta = (intbias >> betashift); /* beta = 1/1024 */
var betagamma = (intbias << (gammashift - betashift));
/* defs for decreasing radius factor */
var initrad = (netsize >> 3); /* for 256 cols, radius starts */
var radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
var radiusbias = (1 << radiusbiasshift);
var initradius = (initrad * radiusbias); /* and decreases by a */
var radiusdec = 30; /* factor of 1/30 each cycle */
/* defs for decreasing alpha factor */
var alphabiasshift = 10; /* alpha starts at 1.0 */
var initalpha = (1 << alphabiasshift);
var alphadec; /* biased by 10 bits */
/* radbias and alpharadbias used for radpower calculation */
var radbiasshift = 8;
var radbias = (1 << radbiasshift);
var alpharadbshift = (alphabiasshift + radbiasshift);
var alpharadbias = (1 << alpharadbshift);
/*
* Types and Global Variables --------------------------
*/
var thepicture; /* the input image itself */
var lengthcount; /* lengthcount = H*W*3 */
var samplefac; /* sampling factor 1..30 */
// typedef int pixel[4]; /* BGRc */
var network; /* the network itself - [netsize][4] */
var netindex = [];
/* for network lookup - really 256 */
var bias = [];
/* bias and freq arrays for learning */
var freq = [];
var radpower = [];
var NeuQuant = exports.NeuQuant = function NeuQuant(thepic, len, sample) {
var i;
var p;
thepicture = thepic;
lengthcount = len;
samplefac = sample;
network = new Array(netsize);
for (i = 0; i < netsize; i++) {
network[i] = new Array(4);
p = network[i];
p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
freq[i] = intbias / netsize; /* 1/netsize */
bias[i] = 0;
}
};
var colorMap = function colorMap() {
var map = [];
var index = new Array(netsize);
for (var i = 0; i < netsize; i++)
index[network[i][3]] = i;
var k = 0;
for (var l = 0; l < netsize; l++) {
var j = index[l];
map[k++] = (network[j][0]);
map[k++] = (network[j][1]);
map[k++] = (network[j][2]);
}
return map;
};
/*
* Insertion sort of network and building of netindex[0..255] (to do after
* unbias)
* -------------------------------------------------------------------------------
*/
var inxbuild = function inxbuild() {
var i;
var j;
var smallpos;
var smallval;
var p;
var q;
var previouscol;
var startpos;
previouscol = 0;
startpos = 0;
for (i = 0; i < netsize; i++) {
p = network[i];
smallpos = i;
smallval = p[1]; /* index on g */
/* find smallest in i..netsize-1 */
for (j = i + 1; j < netsize; j++) {
q = network[j];
if (q[1] < smallval) { /* index on g */
smallpos = j;
smallval = q[1]; /* index on g */
}
}
q = network[smallpos];
/* swap p (i) and q (smallpos) entries */
if (i != smallpos) {
j = q[0];
q[0] = p[0];
p[0] = j;
j = q[1];
q[1] = p[1];
p[1] = j;
j = q[2];
q[2] = p[2];
p[2] = j;
j = q[3];
q[3] = p[3];
p[3] = j;
}
/* smallval entry is now in position i */
if (smallval != previouscol) {
netindex[previouscol] = (startpos + i) >> 1;
for (j = previouscol + 1; j < smallval; j++) netindex[j] = i;
previouscol = smallval;
startpos = i;
}
}
netindex[previouscol] = (startpos + maxnetpos) >> 1;
for (j = previouscol + 1; j < 256; j++) netindex[j] = maxnetpos; /* really 256 */
};
/*
* Main Learning Loop ------------------
*/
var learn = function learn() {
var i;
var j;
var b;
var g;
var r;
var radius;
var rad;
var alpha;
var step;
var delta;
var samplepixels;
var p;
var pix;
var lim;
if (lengthcount < minpicturebytes) samplefac = 1;
alphadec = 30 + ((samplefac - 1) / 3);
p = thepicture;
pix = 0;
lim = lengthcount;
samplepixels = lengthcount / (3 * samplefac);
delta = (samplepixels / ncycles) | 0;
alpha = initalpha;
radius = initradius;
rad = radius >> radiusbiasshift;
if (rad <= 1) rad = 0;
for (i = 0; i < rad; i++) radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
if (lengthcount < minpicturebytes) step = 3;
else if ((lengthcount % prime1) !== 0) step = 3 * prime1;
else {
if ((lengthcount % prime2) !== 0) step = 3 * prime2;
else {
if ((lengthcount % prime3) !== 0) step = 3 * prime3;
else step = 3 * prime4;
}
}
i = 0;
while (i < samplepixels) {
b = (p[pix + 0] & 0xff) << netbiasshift;
g = (p[pix + 1] & 0xff) << netbiasshift;
r = (p[pix + 2] & 0xff) << netbiasshift;
j = contest(b, g, r);
altersingle(alpha, j, b, g, r);
if (rad !== 0) alterneigh(rad, j, b, g, r); /* alter neighbours */
pix += step;
if (pix >= lim) pix -= lengthcount;
i++;
if (delta === 0) delta = 1;
if (i % delta === 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
if (rad <= 1) rad = 0;
for (j = 0; j < rad; j++) radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
}
}
};
/*
** Search for BGR values 0..255 (after net is unbiased) and return colour
* index
* ----------------------------------------------------------------------------
*/
var map = exports.map = function map(b, g, r) {
var i;
var j;
var dist;
var a;
var bestd;
var p;
var best;
bestd = 1000; /* biggest possible dist is 256*3 */
best = -1;
i = netindex[g]; /* index on g */
j = i - 1; /* start at netindex[g] and work outwards */
while ((i < netsize) || (j >= 0)) {
if (i < netsize) {
p = network[i];
dist = p[1] - g; /* inx key */
if (dist >= bestd) i = netsize; /* stop iter */
else {
i++;
if (dist < 0) dist = -dist;
a = p[0] - b;
if (a < 0) a = -a;
dist += a;
if (dist < bestd) {
a = p[2] - r;
if (a < 0) a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
best = p[3];
}
}
}
}
if (j >= 0) {
p = network[j];
dist = g - p[1]; /* inx key - reverse dif */
if (dist >= bestd) j = -1; /* stop iter */
else {
j--;
if (dist < 0) dist = -dist;
a = p[0] - b;
if (a < 0) a = -a;
dist += a;
if (dist < bestd) {
a = p[2] - r;
if (a < 0) a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
best = p[3];
}
}
}
}
}
return (best);
};
var process = exports.process = function process() {
learn();
unbiasnet();
inxbuild();
return colorMap();
};
/*
* Unbias network to give byte values 0..255 and record position i to prepare
* for sort
* -----------------------------------------------------------------------------------
*/
var unbiasnet = function unbiasnet() {
var i;
var j;
for (i = 0; i < netsize; i++) {
network[i][0] >>= netbiasshift;
network[i][1] >>= netbiasshift;
network[i][2] >>= netbiasshift;
network[i][3] = i; /* record colour no */
}
};
/*
* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in
* radpower[|i-j|]
* ---------------------------------------------------------------------------------
*/
var alterneigh = function alterneigh(rad, i, b, g, r) {
var j;
var k;
var lo;
var hi;
var a;
var m;
var p;
lo = i - rad;
if (lo < -1) lo = -1;
hi = i + rad;
if (hi > netsize) hi = netsize;
j = i + 1;
k = i - 1;
m = 1;
while ((j < hi) || (k > lo)) {
a = radpower[m++];
if (j < hi) {
p = network[j++];
try {
p[0] -= (a * (p[0] - b)) / alpharadbias;
p[1] -= (a * (p[1] - g)) / alpharadbias;
p[2] -= (a * (p[2] - r)) / alpharadbias;
} catch (e) {} // prevents 1.3 miscompilation
}
if (k > lo) {
p = network[k--];
try {
p[0] -= (a * (p[0] - b)) / alpharadbias;
p[1] -= (a * (p[1] - g)) / alpharadbias;
p[2] -= (a * (p[2] - r)) / alpharadbias;
} catch (e) {}
}
}
};
/*
* Move neuron i towards biased (b,g,r) by factor alpha
* ----------------------------------------------------
*/
var altersingle = function altersingle(alpha, i, b, g, r) {
/* alter hit neuron */
var n = network[i];
n[0] -= (alpha * (n[0] - b)) / initalpha;
n[1] -= (alpha * (n[1] - g)) / initalpha;
n[2] -= (alpha * (n[2] - r)) / initalpha;
};
/*
* Search for biased BGR values ----------------------------
*/
var contest = function contest(b, g, r) {
/* finds closest neuron (min dist) and updates freq */
/* finds best neuron (min dist-bias) and returns position */
/* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
/* bias[i] = gamma*((1/netsize)-freq[i]) */
var i;
var dist;
var a;
var biasdist;
var betafreq;
var bestpos;
var bestbiaspos;
var bestd;
var bestbiasd;
var n;
bestd = ~ (1 << 31);
bestbiasd = bestd;
bestpos = -1;
bestbiaspos = bestpos;
for (i = 0; i < netsize; i++) {
n = network[i];
dist = n[0] - b;
if (dist < 0) dist = -dist;
a = n[1] - g;
if (a < 0) a = -a;
dist += a;
a = n[2] - r;
if (a < 0) a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
bestpos = i;
}
biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));
if (biasdist < bestbiasd) {
bestbiasd = biasdist;
bestbiaspos = i;
}
betafreq = (freq[i] >> betashift);
freq[i] -= betafreq;
bias[i] += (betafreq << gammashift);
}
freq[bestpos] += beta;
bias[bestpos] -= betagamma;
return (bestbiaspos);
};
NeuQuant.apply(this, arguments);
return exports;
};
/*! p5.func.js v0.0.1 2017-05-27 */
/**
* @module p5.func
* @submodule p5.func
* @for p5.func
* @main
*/
/**
* p5.func
* R. Luke DuBois (dubois@nyu.edu)
* Integrated Digital Media / Brooklyn Experimental Media Center
* New York University
* The MIT License (MIT).
*
* https://github.com/IDMNYU/p5.js-func
*
* the p5.func module contains five new objects for extending p5.js :
* p5.Gen() : function generators (waveforms, curves, window functions, noise, etc.)
* p5.Ease() : easing / interpolation functions
* p5.ArrayEval() : equation evaluator to generate pre-computed arrays
* p5.Filt() : biquadratic filter object
* p5.FastFourierTransform() : signal neutral FFT implementation
*
* p5.func also contains some miscellaneous functions:
* imap() : constrainted integer mapping function
* wrap() : wrapping function
* fold() : folding function
* createArray()/normalizeArray()/resizeArray()/multiplyArray()/addArray()/subtractArray()/divideArray()/moduloArray()/sumArray() : array functions
* f2ib() / ib2f() : int<->float coercion with bit parity
* sinc() : sinc (sinus cardinalis) function
* besselI0() : Bessel function
* fplot() : formattable console plot of any array
*
* primary sources:
* RTcmix Scorefile Commands: http://rtcmix.org/reference/scorefile/
* Robert Penner's Easing Functions: http://robertpenner.com/easing/
* Golan Levin's Pattern Master: https://github.com/golanlevin/Pattern_Master
* Robert Bristow-Johnson's Audio EQ Cookbook: http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
* Corban Brook's dsp.js: https://github.com/corbanbrook/dsp.js/
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd)
define('p5.func', ['p5'], function (p5) { (factory(p5));});
else if (typeof exports === 'object')
factory(require('../p5'));
else
factory(root['p5']);
}(this, function (p5) {
// =============================================================================
// p5.Gen
// =============================================================================
/**
* Base class for a function generator
*
* @class p5.Gen
* @constructor
*/
p5.Gen = function() {
//
// this object implements GEN table-style
// algorithms adapted from MUSICN languages
// (e.g. Csound, RTcmix, ChucK, Supercollider, Max).
// these algorithms are solved by direct (0.-1.)
// evaluation with utility functions to compute arrays.
//
// some code below is adapted from RTcmix :
// https://github.com/RTcmix/RTcmix
// Copyright (C) 2005 The RTcmix Development Team, released under the Apache 2.0 License
//
this.version = 0.01; // just some crap for constructor
var that = this; // some bullshit
}; // end p5.Gen constructor
// harmonic / periodic wave from a list of partial strengths.
// Csound / RTcmix GEN10, ported from RTcmix.
p5.Gen.prototype.harmonics = function(_x, _args) {
var u = true; // single value?
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
if(!Array.isArray(_args)) _args = [_args]; // catch single harmonic
var _sum; // match type:
if(Array.isArray(_x)) _sum = new Array(_x.length);
else if(_x.constructor === Float32Array) _sum = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _sum = new Float64Array(_x.length);
for(var i in _x) {
var j = _args.length;
_sum[i] = 0.0;
while (j--) {
if (_args[j] != 0) {
var _val = TWO_PI * _x[i] * (j + 1);
_sum[i] += (sin(_val) * _args[j]);
}
}
}
return(u ? _sum : _sum[0]);
};
// wave from triples (ratio, amp, phase).
// Csound / RTcmix GEN09, ported from RTcmix.
p5.Gen.prototype.triples = function(_x, _args) {
var u = true; // single value?
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
if(_args.length<2) {
console.log("p5.Gen : we need at least 3 arguments!")
return(0.);
}
else if(_args.length%3!=0) {
console.log("p5.Gen : incomplete <partial, amp, phase> triplet!");
}
var _sum; // match type:
if(Array.isArray(_x)) _sum = new Array(_x.length);
else if(_x.constructor === Float32Array) _sum = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _sum = new Float64Array(_x.length);
for(i in _x) {
_sum[i] = 0.0;
for (var j = _args.length - 1; j > 0; j -= 3) {
if (_args[j - 1] != 0.0) {
var val;
if (_args[j - 2] == 0.0) val = 1.0; // BGG: harmonic 0 (DC)
else {
val = sin(TWO_PI * (_x[i] / (1.0 / _args[j - 2]) + _args[j] / 360.0));
}
_sum[i] += (val * _args[j - 1]);
}
}
}
return(u ? _sum : _sum[0]);
};
// transfer function from chebyshev polynomials.
// Csound / RTcmix GEN17, ported from RTcmix.
p5.Gen.prototype.chebyshev = function(_x, _args) {
var u = true; // single value?
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
if(!Array.isArray(_args)) _args = [_args]; // catch single value
// compute the transfer function using the chebyshev equation...
var _sum // match type:
if(Array.isArray(_x)) _sum = new Array(_x.length);
else if(_x.constructor === Float32Array) _sum = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _sum = new Float64Array(_x.length);
for(var i in _x) {
var v=_x[i]*2.-1.;
_sum[i]=0.;
var Tn1=1;
var Tn=v;
for(var j=0; j<_args.length;j++) {
_sum[i]+=_args[j]*Tn;
Tn2=Tn1;
Tn1=Tn;
Tn=2*v*Tn1-Tn2;
}
}
return(u ? _sum : _sum[0]);
}
// linear breakpoint function (time, value pairs with y normalization).
// Csound GEN27 / RTcmix GEN24, rewritten by rld.
p5.Gen.prototype.bpf = function(_x, _args) {
var u = true; // single value?
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
if(_args.length%2!=0) {
console.log("p5.Gen : incomplete <time, value> pair!")
return(0.);
}
var endtime = _args[_args.length - 2];
var starttime = _args[0];
if (endtime - starttime <= 0.0) {
console.log("p5.Gen : bpf times must be in ascending order!");
return(0.);
}
var scaler = 1.0 / (endtime - starttime);
var thistime = 0;
var nexttime = 0;
var thisval = 0;
var nextval = 0;
var _y // match type:
if(Array.isArray(_x)) _y = new Array(_x.length);
else if(_x.constructor === Float32Array) _y = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _y = new Float64Array(_x.length);
for(i in _x)
{
for (var k = 1; k < _args.length; k += 2) {
thistime = _args[k-1]*scaler;
thisval = _args[k];
if(k<_args.length-1) {
nexttime = _args[k+1]*scaler;
nextval = _args[k+2];
}
else {
nexttime = thistime;
nextval = thisval;
}
if(nexttime - thistime < 0.0) { // okay for them to be the same
console.log("p5.Gen : bpf times music be in ascending order!");
return(0.);
}
if(_x[i]>=thistime && _x[i]<=nexttime) // this point in bpf
{
var _thisval = _args[k+1];
_y[i] = map(_x[i], thistime, nexttime, thisval, nextval);
break;
}
}
}
return(u ? _y : _y[0]);
}
// common random number distributions.
// Csound GEN21 / RTcmix GEN20, written by rld.
// if no seed, auto-generated from millis().
// algorithms adapted from dodge and jerse (1985).
// inspired by denis lorrain's
// 'a panoply of stochastic cannons' (1980):
// http://www.jstor.org/stable/3679442
p5.Gen.prototype.random = function(_x, _type) {
// distributions based on RTcmix GEN20:
// even distribution ["even" or "linear"]
// low weighted linear distribution ["low"]
// high weighted linear distribution ["high"]
// triangle linear distribution ["triangle"]
// gaussian distribution ["gaussian"]
// cauchy distribution ["cauchy"]
//
// a -1 in the seed parameter (or missing) will
// instruct the algorithm to use the millisecond
// clock for a random seed.
var u = true; // single value?
var _s = 0.;
if(!_x) // no arguments, so do linear with random seed
{
_type = 'linear';
_x = [millis()];
u = false;
}
else if(typeof(_x)!='string') // first argument is a number, so seed
{
if(!Array.isArray(arguments[0]) && arguments[0].constructor !== Float32Array && arguments[0].constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
}
else // argument is a string, so type
{
_type=_x; // it's the type, not the seed
_x = [millis()]; // random seed
u = false;
}
var _v; // match type:
if(Array.isArray(_x)) _v= new Array(_x.length);
else if(_x.constructor === Float32Array) _v = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _v = new Float64Array(_x.length);
if(_x[0]===-1) randomSeed(millis()*100000.);
for(var i in _x)
{
if(_x[i]!=-1) randomSeed(_x[i]*100000.);
switch(_type) {
case "linear":
case "even":
_v[i] = random();
break;
case "low":
_v[i] = min(random(), random());
break;
case "high":
_v[i] = max(random(), random());
break;
case "triangle":
_v[i] = (random()+random())/2.0;
break;
case "gaussian":
var n = 12;
var sigma = 0.166666;
var randnum = 0.0;
for (var j = 0; j < n; j++) {
randnum += random();
}
_v[i] = sigma * (randnum - n/2) + 0.5;
break;
case "cauchy":
var alpha = 0.00628338;
do {
do {
_v[i] = random();
} while (_v[i] == 0.5);
_v[i] = (alpha * tan(_v[i] * PI)) + 0.5;
} while (_v[i] < 0.0 || _v[i] > 1.0);
break;
default:
_v[i] = random();
break;
}
}
return(u ? _v : _v[0]);
}
// common window functions for signal processing.
// Csound GEN20 / RTcmix GEN25 (paris smaragdis / dave topper)
// and Pattern Master by @golanlevin .
// rewritten / ported from C and Java by rld.
// equations from Wikipedia: https://en.wikipedia.org/wiki/Window_function
p5.Gen.prototype.window = function(_x, _type, _args) {
// flag order based on CSOUND GEN20:
// 1 = hamming
// 2 = hanning
// 3 = bartlett (triangle)
// 4 = blackman (3-term)
// 5 = blackman-harris (4-term)
// 6 = gaussian
// 7 = kaiser
// 8 = rectangle
// 9 = sinc
// these and others are addressible by name.
var u = true; // single value?
if(!Array.isArray(_args)) _args = [_args]; // catch single value
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
var _y; // match type:
if(Array.isArray(_x)) _y= new Array(_x.length);
else if(_x.constructor === Float32Array) _y = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _y = new Float64Array(_x.length);
var i;
switch(_type) {
// proposed by richard wesley hamming (1915-1998).
// optimized to quash the nearest sidelobe.
case 1:
case "hamming":
var alpha = 0.54;
var beta = 0.46;
for(i in _x) _y[i] = alpha - beta * cos(TWO_PI * _x[i]);
break;
// named for julius von hann (1839-1921).
// sidelobes fall at 18db/oct.
case 2:
case "hanning": // not the guy's actual name
case "vonhann": // the guy's actual name
case "hann": // sort of the guy's actual name
case "hannsolo": // no
case "hanningvonhannmeister": // very much no
for(i in _x) _y[i] = 0.5 * (1-cos(TWO_PI*_x[i]));
break;
// proposed by m.s. bartlett (1910-2002).
// also by lipót (leopold) fejér (1880-1959).
// triangular (2nd order b-spline) window.
case 3:
case "bartlett":
case "fejer":
case "fejér": // get the accent right
case "triangle":
for(i in _x) _y[i] = 1.0 - abs((_x[i]-0.5)/0.5);
break;
// bartlett-hann window.
case "bartlett-hann":
var a0 = 0.62;
var a1 = 0.48;
var a2 = 0.38;
for(i in _x) _y[i] = a0 - a1*abs(_x[i] - 0.5) - a2*cos(2*PI*_x[i]);
break;
case 4:
// proposed by ralph beebe blackman (1904-1990).
// 'exact' blackman kills sidelobes 3 and 4, but only 6db/oct damping.
// 'unqualified' blackman still has the sidelobes, but an 18db/oct damping.
case "blackman":
// 'exact' blackman:
var a0 = 7938/18608;
var a1 = 9240/18608;
var a2 = 1430/18608;
// 'unqualified' blackman:
// var a0 = 0.42;
// var a1 = 0.5;
// var a2 = 0.08;
for(i in _x) _y[i] = a0 - a1 * cos(2.*PI*_x[i]) + a2 * cos(4.*PI*_x[i]);
break;
// generalized (variable center) blackman.
case "generalizedblackman":
if(!_args[0]) _args[0] = 0.5; // default center
var _a = _args[0];
var a0 = (1.0 - _a)/2.0;
var a1 = 0.5;
var a2 = _a / 2.0;
for(i in _x)
{
var pix = PI*_x[i];
_y[i] = a0 - a1*cos(2*pix) + a2*cos(4*pix);
}
break;
// blackman window improved by fred harris (brooklyn poly '61):
// http://web.mit.edu/xiphmont/Public/windows.pdf
// 4-term sinc functions to minimize sidelobes.
case 5:
case "blackman-harris":
var a0 = 0.35875;
var a1 = 0.48829;
var a2 = 0.14128;
var a3 = 0.01168;
for(i in _x) _y[i] = a0 - a1 * cos(2.*PI*_x[i]) + a2 * cos(4.*PI*_x[i]) + a3 * cos(6.*PI*_x[i]);
break;
// 4-term blackman-nuttal (same as BH with different coefficients).
case "blackman-nuttal":
var a0 = 0.3635819;
var a1 = 0.4891775;
var a2 = 0.1365995;
var a3 = 0.0106411;
for(i in _x) _y[i] = a0 - a1 * cos(2.*PI*_x[i]) + a2 * cos(4.*PI*_x[i]) + a3 * cos(6.*PI*_x[i]);
break;
// 4-term nuttal (same as BH with different coefficients).
case "nuttal":
var a0 = 0.355768;
var a1 = 0.487396;
var a2 = 0.144232;
var a3 = 0.012604;
for(i in _x) _y[i] = a0 - a1 * cos(2.*PI*_x[i]) + a2 * cos(4.*PI*_x[i]) + a3 * cos(6.*PI*_x[i]);
break;
// gaussians are eigenfunctions of fourier transforms.
// gaussian window needs to be zeroed at the ends.
// parabolic.
case 6:
case "gaussian":
if(!_args[0]) _args[0] = 0.4; // default sigma
var sigma = _args[0];
for(i in _x) _y[i] = exp(-0.5 * ((_x[i]-0.5) / (sigma*0.5)) * ((_x[i]-0.5) / (sigma*0.5)));
break;
// jim kaiser's 1980 approximation of a DPSS /
// slepian window using bessel functions,
// developed at bell labs for audio coding.
// concentrates the energy in the main lobe.
case 7:
case "kaiser":
var alpha = 3.;
for(i in _x) {
var above = PI * alpha * sqrt(1.0 - (2. * _x[i] - 1.0) * (2. * _x[i] - 1.0));
var below = PI * alpha;
_y[i] = besselI0(above) / besselI0(below);
}
break;
// an 'unwindow'. all samples within window envelope are at unity.
// bad signal-to-noise ratio. lots of scalloping loss.
// sometimes named for peter gustav lejeune dirichlet (1805-1859).
case 8:
case "rectangle":
case "boxcar":
case "dirichlet":
for(i in _x) _y[i] = 1.; // nothing to it
break;
// cosine window
case "cosine":
for(i in _x) _y[i] = sin(PI*_x[i]);
break;
// named for cornelius lanczos (1906-1974).
// a normalized (double-window) sinc function is often
// used as a kernel for interpolation / low-pass filtering.
case 9:
case "sinc":
case "sync": // learn to spell
case "lanczos":
for(i in _x) _y[i] = sinc(2*_x[i]-1.0);
break;
// flat top window.
case "flattop":
var a0 = 1.000;
var a1 = 1.930;
var a2 = 1.290;
var a3 = 0.388;
var a4 = 0.032;
for(i in _x) {
_y[i] = a0 - a1*cos(2*PI*_x[i]) + a2*cos(4*PI*_x[i]) - a3*cos(6*PI*_x[i]) + a4*cos(8*PI*_x[i]);
_y[i] /= (a0 + a1 + a2 + a3 + a4);
}
break;
// tukey window courtesy of @golanlevin :
// The Tukey window, also known as the tapered cosine window,
// can be regarded as a cosine lobe of width \tfrac{\alpha N}{2}
// that is convolved with a rectangle window of width \left(1 -\tfrac{\alpha}{2}\right)N.
// At alpha=0 it becomes rectangular, and at alpha=1 it becomes a Hann window.
case "tukey":
if(!_args[0]) _args[0] = 0.5; // default center
var _a = _args[0];
var ah = _a/2.0;
var omah = 1.0 - ah;
for(i in _x)
{
_y[i] = 1.0;
if (_x[i] <= ah) {
_y[i] = 0.5 * (1.0 + cos(PI*((2*_x[i]/_a)-1.0)));
}
else if (_x[i] > omah) {
_y[i] = 0.5 * (1.0 + cos(PI*((2*_x[i]/_a)-(2/_a)+1.0)));
}
}
break;
// adjustable sliding gaussian courtesy of @golanlevin .
case "slidinggaussian":
if(!_args[0]) _args[0] = 0.5; // default center
if(!_args[1]) _args[1] = 0.4; // default sigma
var dx = 2.0*(_args[0] - 0.5);
var sigma = _args[1] * 2.;
for(var i in _x) _y[i] = exp(0.0 - (sq(_x[i]*2.-1.0-dx) / (2.0*sigma*sigma)));
break;
// adjustable center cosine window courtesy of @golanlevin .
case "adjustablecosine":
if(!_args[0]) _args[0] = 0.5; // default center
var _a = _args[0];
var ah = _a/2.0;
var omah = 1.0 - ah;
for(i in _x)
{
_y[i] = 1.0;
if (_x[i] <= _a) {
_y[i] = 0.5 * (1.0 + cos(PI*((_x[i]/_a)-1.0)));
}
else {
_y[i] = 0.5 * (1.0 + cos(PI*(((_x[i]-_a)/(1.0-_a)))));
}
}
break;
// adjustable center elliptic window courtesy of @golanlevin .
case "elliptic":
if(!_args[0]) _args[0] = 0.5; // default center
var _a = _args[0];
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
for(i in _x)
{
_y[i] = 0;
if (_x[i]<=_a){
_y[i] = (1.0/_a) * sqrt(sq(_a) - sq(_x[i]-_a));
}
else {
_y[i] = (1.0/(1-_a)) * sqrt(sq(1.0-_a) - sq(_x[i]-_a));
}
}
break;
// adjustable center hyperelliptic window courtesy of @golanlevin .
case "hyperelliptic":
if(!_args[0]) _args[0] = 0.5; // default center
if(!_args[1]) _args[1] = 3; // default order
var _a = _args[0];
var _n = _args[1];
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
for(i in _x)
{
_y[i] = 0;
var pwn = _n * 2.0;
if (_x[i]<=_a){
_y[i] = (1.0/_a) * pow( pow(_a, pwn) - pow(_x[i]-_a, pwn), 1.0/pwn);
}
else {
_y[i] = ((1.0/ (1-_a))) * pow( pow(1.0-_a, pwn) - pow(_x[i]-_a, pwn), 1.0/pwn);
}
}
break;
// adjustable center squircular window courtesy of @golanlevin .
case "squircular":
if(!_args[0]) _args[0] = 0.5; // default center
if(!_args[1]) _args[1] = 3; // default order
var _a = _args[0];
var _n = _args[1];
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
for(i in _x)
{
_y[i] = 0;
var pwn = max(2, _n * 2.0);
if (_x[i]<=_a){
_y[i] = (1-_a) + pow( pow(_a, pwn) - pow(_x[i]-_a, pwn), 1.0/pwn);
}
else {
_y[i] = _a + pow( pow(1.0-_a, pwn) - pow(_x[i]-_a, pwn), 1.0/pwn);
}
}
break;
// poisson window functions courtesy of @golanlevin .
case "poisson":
if(!_args[0]) _args[0] = 0.5; // default center
var tau = max(_args[0], Number.EPSILON);
for(var i in _x) _y[i] = exp (0.0 - (abs(_x[i] - 0.5))*(1.0/tau));
break;
case "hann-poisson":
case "poisson-hann":
case "hannpoisson":
case "poissonhann":
if(!_args[0]) _args[0] = 0.5; // default center
var tau = 25.0 * max(_args[0]*_args[0]*_args[0]*_args[0], Number.EPSILON); // nice control
for(i in _x) {
var hy = 0.5 * (1.0 - cos(TWO_PI*_x[i]));
var py = exp (0.0 - (abs(_x[i] - 0.5))*(1.0/tau));
_y[i] = hy * py;
}
break;
case "slidinghann-poisson":
case "slidingpoisson-hann":
case "slidinghannpoisson":
case "slidingpoissonhann":
if(!_args[0]) _args[0] = 0.5; // default center
if(!_args[1]) _args[1] = 0.5; // default sigma
var tau = 25.0 * max(_args[1]*_args[1]*_args[1]*_args[1], Number.EPSILON); // nice control
for(i in _x) {
var newx = constrain(_x[i] + (0.5 - _args[0]), 0, 1);
var hy = 0.5 * (1.0 - cos(TWO_PI*newx));
var py = exp (0.0 - (abs(newx - 0.5))*(1.0/tau));
_y[i] = hy * py;
}
break;
for(i in _x) _y[i] = _x[i];
default:
}
return(u ? _y : _y[0]);
}
// common waveform functions (0-1 evaluation).
p5.Gen.prototype.waveform = function(_x, _type) {
// algorithms:
// sine
// cosine
// saw / sawup
// sawdown
// phasor (ramp 0.-1.)
// square
// rect / rectangle
// pulse
// tri / triangle
// buzz
var u = true; // single value?
if(!Array.isArray(_x) && _x.constructor !== Float32Array && _x.constructor !== Float64Array) {
_x = [_x]; // process all values as arrays
u = false;
}
var _y // match type:
if(Array.isArray(_x)) _y = new Array(_x.length);
else if(_x.constructor === Float32Array) _y = new Float32Array(_x.length);
else if(_x.constructor === Float64Array) _y = new Float64Array(_x.length);
var i;
switch(_type) {
// sine wave 0. to 1. to -1. to 0.
case "sine":
case "sin":
_y = this.harmonics(_x, [1.]);
break;
// cosine wave 1. to -1. to 1.
case "cosine":
case "cos":
_y = this.triples(_x, [1., 1., 90]);
break;
// rising saw -1. to 1.
case "saw":
case "sawtooth":
case "sawup":
_y = this.bpf(_x, [0, -1., 1, 1.]);
break;
// falling saw 1. to -1.
case "sawdown":
_y = this.bpf(_x, [0, 1., 1, -1.]);
break;
// phasor ramp 0. to 1.
case "phasor":
_y = this.bpf(_x, [0, 0., 1, 1.]);
break;
// square wave 1. to -1. (equal duty cycle)
case "square":
_y = this.bpf(_x, [0, 1., 1, 1., 1, -1., 2, -1]);
break;
// rectangle wave 1. to -1. (10% duty cycle)
case "rect":
case "rectangle":
_y = this.bpf(_x, [0, 1., 1, 1., 1, -1., 10, -1]);
break;
// pulse wave 1. to -1. (1% duty cycle)
case "pulse":
_y = this.bpf(_x, [0, 1., 1, 1., 1, -1., 100, -1]);
break;
// triangle wave 0. to 1. to -1. to 0.
case "tri":
case "triangle":
_y = this.bpf(_x, [0, 0, 1, 1, 2, 0, 3, -1, 4, 0]);
break;
// buzz wave (10 harmonics at equal amplitude) 0. to 1. to -1. to 0.
case "buzz":
_y = this.harmonics(_x, [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]);
break;
default:
}
return(u ? _y : _y[0]);
}
// list algorithms
p5.Gen.prototype.listAlgos = function() {
var _styles = new Array();
for(var i in this.__proto__) {
var _t = true;
if(i=="listAlgos") _t=false;
else if(i=="fillArray") _t=false;
else if(i=="fillFloat32Array") _t=false;
else if(i=="fillFloat64Array") _t=false;
if(_t) _styles.push(i);
}
return(_styles);
}
// array xfer (for pre-rendered use)
p5.Gen.prototype.fillArray = function(_algo, _len, _args, _seed) {
var _p = new Array(_len);
var _dest = new Array(_len);
if(_algo==='random') { // 4th argument is seed
for(var i = 0;i<_len;i++)
{
if(_seed) _p[i] = i/(_len-1)*10000.+_seed;
else _p[i] = '-1';
}
}
else {
for(var i = 0;i<_len;i++)
{
_p[i] = i/(_len-1); // 0.-1.
}
}
_dest = this[_algo](_p, _args, _seed);
return(_dest);
}
// array xfer (for pre-rendered use)
p5.Gen.prototype.fillFloat32Array = function(_algo, _len, _args, _seed) {
var _p = new Float32Array(_len);
var _dest = new Float32Array(_len);
if(_algo==='random') { // 4th argument is seed
for(var i = 0;i<_len;i++)
{
if(_seed) _p[i] = i/(_len-1)*10000.+_seed;
else _p[i] = '-1';
}
}
else {
for(var i = 0;i<_len;i++)
{
_p[i] = i/(_len-1); // 0.-1.
}
}
_dest = this[_algo](_p, _args, _seed);
return(_dest);
}
// array xfer (for pre-rendered use)
p5.Gen.prototype.fillFloat64Array = function(_algo, _len, _args, _seed) {
var _p = new Float64Array(_len);
var _dest = new Float64Array(_len);
if(_algo==='random') { // 4th argument is seed
for(var i = 0;i<_len;i++)
{
if(_seed) _p[i] = i/(_len-1)*10000.+_seed;
else _p[i] = '-1';
}
}
else {
for(var i = 0;i<_len;i++)
{
_p[i] = i/(_len-1); // 0.-1.
}
}
_dest = this[_algo](_p, _args, _seed);
return(_dest);
}
// =============================================================================
// p5.Ease
// =============================================================================
/**
* Base class for an easing function
*
* @class p5.Ease
* @constructor
*/
p5.Ease = function() {
//
// this object generates easing / tweening functions
// through direct (0.-1.) evaluation, with utilities
// to pre-evaluate functions into lookup tables.
//
// algorithms based on:
//
// robert penner's algorithms discussed in
// 'programming macromedia flash mx' (2002).
// Copyright (C) 2001 Robert Penner, released under the BSD License
//
// golan levin's Pattern_Master functions:
// https://github.com/golanlevin/Pattern_Master
// Copyright (C) 2006 Golan Levin
//
// some functions have additional parameters,
// such as an order of interpolation (n) or up to four
// coefficients (a, b, c, d) which will change the
// behavior of the easing function.
//
this.version = 0.01; // just some crap for constructor
var that = this; // some bullshit
}; // end p5.Ease constructor
// Penner's Easing Functions:
// line y = x
p5.Ease.prototype.linear = function(_x) {
return(_x);
};
// parabola y = x^2
p5.Ease.prototype.quadraticIn = function(_x) {
return(_x * _x);
};
// parabola y = -x^2 + 2x
p5.Ease.prototype.quadraticOut = function(_x) {
return(-(_x * (_x - 2)));
}
// piecewise quadratic
// y = (1/2)((2x)^2) ; [0, 0.5)
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
p5.Ease.prototype.quadraticInOut = function(_x) {
if(_x < 0.5)
{
return(2 * _x * _x);
}
else
{
return((-2 * _x * _x) + (4 * _x) - 1);
}
}
// cubic y = x^3
p5.Ease.prototype.cubicIn = function(_x) {
return(_x * _x * _x);
}
// cubic y = (x - 1)^3 + 1
p5.Ease.prototype.cubicOut = function(_x) {
var _v = (_x - 1);
return(_v * _v * _v + 1);
}
// piecewise cubic
// y = (1/2)((2x)^3) ; [0, 0.5)
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
p5.Ease.prototype.cubicInOut = function(_x) {
if(_x < 0.5)
{
return(4 * _x * _x * _x);
}
else
{
var _v = ((2 * _x) - 2);
return(0.5 * _v * _v * _v + 1);
}
}
// quartic x^4
p5.Ease.prototype.quarticIn = function(_x) {
return(_x * _x * _x * _x);
}
// quartic y = 1 - (x - 1)^4
p5.Ease.prototype.quarticOut = function(_x) {
var _v = (_x - 1);
return(_v * _v * _v * (1 - _x) + 1);
}
// piecewise quartic
// y = (1/2)((2x)^4) ; [0, 0.5)
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
p5.Ease.prototype.quarticInOut = function(_x) {
if(_x < 0.5)
{
return(8 * _x * _x * _x * _x);
}
else
{
var _v = (_x - 1);
return(-8 * _v * _v * _v * _v + 1);
}
}
// quintic y = x^5
p5.Ease.prototype.quinticIn = function(_x) {
return(_x * _x * _x * _x * _x);
}
// quintic y = (x - 1)^5 + 1
p5.Ease.prototype.quinticOut = function(_x) {
var _v = (_x - 1);
return(_v * _v * _v * _v * _v + 1);
}
// piecewise quintic
// y = (1/2)((2x)^5) ; [0, 0.5)
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
p5.Ease.prototype.quinticInOut = function(_x) {
if(_x < 0.5)
{
return(16 * _x * _x * _x * _x * _x);
}
else
{
var _v = ((2 * _x) - 2);
return(0.5 * _v * _v * _v * _v * _v + 1);
}
}
// quarter-cycle sine
p5.Ease.prototype.sineIn = function(_x) {
return(sin((_x - 1) * HALF_PI) + 1);
}
// quarter-cycle cosine
p5.Ease.prototype.sineOut = function(_x) {
return(sin(_x * HALF_PI));
}
// half sine
p5.Ease.prototype.sineInOut = function(_x) {
return(0.5 * (1 - cos(_x * PI)));
}
// shifted quadrant IV of unit circle
p5.Ease.prototype.circularIn = function(_x) {
return(1 - sqrt(1 - (_x * _x)));
}
// shifted quadrant II of unit circle
p5.Ease.prototype.circularOut = function(_x) {
return(sqrt((2 - _x) * _x));
}
// piecewise circular function
// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
p5.Ease.prototype.circularInOut = function(_x) {
if(_x < 0.5)
{
return(0.5 * (1 - sqrt(1 - 4 * (_x * _x))));
}
else
{
return(0.5 * (sqrt(-((2 * _x) - 3) * ((2 * _x) - 1)) + 1));
}
}
// exponential function y = 2^(10(x - 1))
p5.Ease.prototype.exponentialIn = function(_x) {
return((_x == 0.0) ? _x : pow(2, 10 * (_x - 1)));
}
// exponential function y = -2^(-10x) + 1
p5.Ease.prototype.exponentialOut = function(_x) {
return((_x == 1.0) ? _x : 1 - pow(2, -10 * _x));
}
// piecewise exponential
// y = (1/2)2^(10(2x - 1)) ; [0,0.5)
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
p5.Ease.prototype.exponentialInOut = function(_x) {
if(_x == 0.0 || _x == 1.0) return _x;
if(_x < 0.5)
{
return(0.5 * pow(2, (20 * _x) - 10));
}
else
{
return(-0.5 * pow(2, (-20 * _x) + 10) + 1);
}
}
// damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
p5.Ease.prototype.elasticIn = function(_x) {
return(sin(13 * HALF_PI * _x) * pow(2, 10 * (_x - 1)));
}
// damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
p5.Ease.prototype.elasticOut = function(_x) {
return(sin(-13 * HALF_PI * (_x + 1)) * pow(2, -10 * _x) + 1);
}
// piecewise damped sine wave:
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
p5.Ease.prototype.elasticInOut = function(_x) {
if(_x < 0.5)
{
return(0.5 * sin(13 * HALF_PI * (2 * _x)) * pow(2, 10 * ((2 * _x) - 1)));
}
else
{
return(0.5 * (sin(-13 * HALF_PI * ((2 * _x - 1) + 1)) * pow(2, -10 * (2 * _x - 1)) + 2));
}
}
// overshooting cubic y = x^3-x*sin(x*pi)
p5.Ease.prototype.backIn = function(_x) {
return(_x * _x * _x - _x * sin(_x * PI));
}
// overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
p5.Ease.prototype.backOut = function(_x) {
var f = (1 - _x);
return(1 - (f * f * f - f * sin(f * PI)));
}
// piecewise overshooting cubic function:
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
p5.Ease.prototype.backInOut = function(_x) {
if(_x < 0.5)
{
var f = 2 * _x;
return(0.5 * (f * f * f - f * sin(f * PI)));
}
else
{
var f = (1 - (2*_x - 1));
return(0.5 * (1 - (f * f * f - f * sin(f * PI))) + 0.5);
}
}
// penner's four-part bounce algorithm
p5.Ease.prototype.bounceIn = function(_x) {
return(1 - this.bounceOut(1 - _x));
}
// penner's four-part bounce algorithm
p5.Ease.prototype.bounceOut = function(_x) {
if(_x < 4/11.0)
{
return((121 * _x * _x)/16.0);
}
else if(_x < 8/11.0)
{
return((363/40.0 * _x * _x) - (99/10.0 * _x) + 17/5.0);
}
else if(_x < 9/10.0)
{
return((4356/361.0 * _x * _x) - (35442/1805.0 * _x) + 16061/1805.0);
}
else
{
return((54/5.0 * _x * _x) - (513/25.0 * _x) + 268/25.0);
}
}
// piecewise penner's four-part bounce algorithm
p5.Ease.prototype.bounceInOut = function(_x) {
if(_x < 0.5)
{
return(0.5 * this.bounceIn(_x*2));
}
else
{
return(0.5 * this.bounceOut(_x * 2 - 1) + 0.5);
}
}
// Golan's Pattern Master Functions:
// bryce summers' cubic easing function (@Bryce-Summers)
p5.Ease.prototype.brycesCubic = function(_x, _n)
{
if(!_n) _n = 3; // default
var p = pow(_x, _n-1);
var xn = p * _x;
return(_n*p - (_n-1)*xn);
}
// staircase function - n is # of steps
p5.Ease.prototype.staircase = function(_x, _n)
{
if(!_n) _n = 3; // default
var _y = floor(_x*_n) / (_n-1);
if(_x>=1.) _y=1.;
return(_y);
}
// staircase function with smoothing - a is smoothing, n is # of steps
p5.Ease.prototype.exponentialSmoothedStaircase = function(_x, _a, _n)
{
if(!_a) _a = 0.25; // default
if(!_n) _n = 3; // default
// See http://web.mit.edu/fnl/volume/204/winston.html
var fa = sq (map(_a, 0,1, 5,30));
var _y = 0;
for (var i=0; i<_n; i++){
_y += (1.0/(_n-1.0))/ (1.0 + exp(fa*(((i+1.0)/_n) - _x)));
}
_y = constrain(_y, 0,1);
return(_y);
}
// gompertz curve
// http://en.wikipedia.org/wiki/Gompertz_curve
p5.Ease.prototype.gompertz = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
_a = max(_a, min_param_a);
var b = -8.0;
var c = 0 - _a*16.0;
var _y = exp( b * exp(c * _x));
var maxVal = exp(b * exp(c));
var minVal = exp(b);
_y = map(_y, minVal, maxVal, 0, 1);
return(_y);
}
// clamped processing map function with terms reordered:
// min in, max in, min out, max out
p5.Ease.prototype.generalizedLinearMap = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.; // default
if(!_b) _b = 0.; // default
if(!_c) _c = 1.; // default
if(!_d) _d = 1.; // default
var _y = 0;
if (_a < _c) {
if (_x <= _a) {
_y = _b;
}
else if (_x >= _c) {
_y = _d;
}
else {
_y = map(_x, _a, _c, _b, _d);
}
}
else {
if (_x <= _c) {
_y = _d;
}
else if (_x >= _a) {
_y = _b;
}
else {
_y = map(_x, _c, _a, _d, _b);
}
}
return(_y);
}
// double-(odd) polynomial ogee
// what the hell is an ogee, you may ask?
// https://en.wikipedia.org/wiki/Ogee
p5.Ease.prototype.doubleOddPolynomialOgee = function(_x, _a, _b, _n)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_n) _n = 3; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
var p = 2*_n + 1;
var _y = 0;
if (_x <= _a) {
_y = _b - _b*pow(1-_x/_a, p);
}
else {
_y = _b + (1-_b)*pow((_x-_a)/(1-_a), p);
}
return(_y);
}
// double-linear interpolator
p5.Ease.prototype.doubleLinear = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var _y = 0;
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
if (_x<=_a) {
_y = (_b/_a) * _x;
}
else {
_y = _b + ((1-_b)/(1-_a))*(_x-_a);
}
return(_y);
}
// triple-linear interpolator
p5.Ease.prototype.tripleLinear = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
if(!_d) _d = 0.25; // default
var _y = 0;
if (_a < _c) {
if (_x <= _a) {
_y = map(_x, 0, _a, 0, _b);
}
else if (_x >= _c) {
_y = map(_x, _c, 1, _d, 1);
}
else {
_y = map(_x, _a, _c, _b, _d);
}
}
else {
if (_x <= _c) {
_y = map(_x, 0, _c, 0, _d);
}
else if (_x >= _a) {
_y = map(_x, _a, 1, _b, 1);
}
else {
_y = map(_x, _c, _a, _d, _b);
}
}
return(_y);
}
// variable staircase interpolator
p5.Ease.prototype.variableStaircase = function(_x, _a, _n)
{
if(!_a) _a = 0.25; // default
if(!_n) _n = 3; // default
var aa = (_a - 0.5);
if (aa == 0) {
return(_x);
}
var x0 = (floor (_x*_n))/ _n;
var x1 = (ceil (_x*_n))/ _n;
var y0 = x0;
var y1 = x1;
var px = 0.5*(x0+x1) + aa/_n;
var py = 0.5*(x0+x1) - aa/_n;
var _y = 0;
if ((_x < px) && (_x > x0)) {
_y = map(_x, x0, px, y0, py);
}
else {
_y = map(_x, px, x1, py, y1);
}
return(_y);
}
// quadratic bezier staircase function
p5.Ease.prototype.quadraticBezierStaircase = function(_x, _a, _n)
{
if(!_a) _a = 0.25; // default
if(!_n) _n = 3; // default
var aa = (_a - 0.5);
if (aa == 0) {
return(_x);
}
var x0 = (floor (_x*_n))/ _n;
var x1 = (ceil (_x*_n))/ _n;
var y0 = x0;
var y1 = x1;
var px = 0.5*(x0+x1) + aa/_n;
var py = 0.5*(x0+x1) - aa/_n;
var p0x = (x0 + px)/2.0;
var p0y = (y0 + py)/2.0;
var p1x = (x1 + px)/2.0;
var p1y = (y1 + py)/2.0;
var _y = 0;
var denom = (1.0/_n)*0.5;
if ((_x <= p0x) && (_x >= x0)) {
// left side
if (floor (_x*_n) <= 0){
_y = map(_x, x0, px, y0, py);
} else {
if (abs(_x - x0) < Number.EPSILON){
// problem when x == x0 !
}
var za = (x0 - (p1x - 1.0/_n))/denom;
var zb = (y0 - (p1y - 1.0/_n))/denom;
var zx = (_x - (p1x - 1.0/_n))/denom;
var om2a = 1.0 - 2.0*za;
var interior = max (0, za*za + om2a*zx);
var t = (sqrt(interior) - za)/om2a;
var zy = (1.0-2.0*zb)*(t*t) + (2*zb)*t;
zy *= (p1y - p0y);
zy += p1y; //(p1y - 1.0/n);
if (_x > x0){
zy -= 1.0/_n;
}
_y = zy;
}
}
else if ((_x >= p1x) && (_x <= x1)) {
// right side
if (ceil(_x*_n) >= _n) {
_y = map(_x, px, x1, py, y1);
}
else {
if (abs(_x - x1) < Number.EPSILON){
// problem when x == x1 !
}
var za = (x1 - p1x)/denom;
var zb = (y1 - p1y)/denom;
var zx = (_x - p1x)/denom;
if (za == 0.5) {
za += Number.EPSILON;
}
var om2a = 1.0 - 2.0*za;
if (abs(om2a) < Number.EPSILON) {
om2a = ((om2a < 0) ? -1:1) * Number.EPSILON;
}
var interior = max (0, za*za + om2a*zx);
var t = (sqrt(interior) - za)/om2a;
var zy = (1.0-2.0*zb)*(t*t) + (2*zb)*t;
zy *= (p1y - p0y);
zy += p1y;
_y = zy;
}
}
else {
// center
var za = (px - p0x)/denom;
var zb = (py - p0y)/denom;
var zx = (_x - p0x)/denom;
if (za == 0.5) {
za += Number.EPSILON;
}
var om2a = 1.0 - 2.0*za;
var t = (sqrt(za*za + om2a*zx) - za)/om2a;
var zy = (1.0-2.0*zb)*(t*t) + (2*zb)*t;
zy *= (p1y - p0y);
zy += p0y;
_y = zy;
}
return(_y);
}
// symmetric double-element sigmoid function (a is slope)
// https://en.wikipedia.org/wiki/Sigmoid_function
p5.Ease.prototype.doubleExponentialSigmoid = function(_x, _a)
{
if(!_a) _a = 0.75; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
_a = 1-_a;
var _y = 0;
if (_x<=0.5){
_y = (pow(2.0*_x, 1.0/_a))/2.0;
}
else {
_y = 1.0 - (pow(2.0*(1.0-_x), 1.0/_a))/2.0;
}
return(_y);
}
// double-element sigmoid function with an adjustable center (b is center)
p5.Ease.prototype.adjustableCenterDoubleExponentialSigmoid = function(_x, _a, _b)
{
if(!_a) _a = 0.75; // default
if(!_b) _b = 0.5; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
_a = 1-_a;
var _y = 0;
var w = max(0, min(1, _x-(_b-0.5)));
if (w<=0.5){
_y = (pow(2.0*w, 1.0/_a))/2.0;
}
else {
_y = 1.0 - (pow(2.0*(1.0-w), 1.0/_a))/2.0;
}
return(_y);
}
// quadratic sigmoid function
p5.Ease.prototype.doubleQuadraticSigmoid = function(_x)
{
var _y = 0;
if (_x<=0.5){
_y = sq(2.0*_x)/2.0;
}
else {
_y = 1.0 - sq(2.0*(_x-1.0))/2.0;
}
return(_y);
}
// double polynomial sigmoid function
p5.Ease.prototype.doublePolynomialSigmoid = function(_x, _n)
{
if(!_n) _n = 3; // default
var _y = 0;
if (_n%2 == 0){
// even polynomial
if (_x<=0.5){
_y = pow(2.0*_x, _n)/2.0;
}
else {
_y = 1.0 - pow(2*(_x-1.0), _n)/2.0;
}
}
else {
// odd polynomial
if (_x<=0.5){
_y = pow(2.0*_x, _n)/2.0;
}
else {
_y = 1.0 + pow(2.0*(_x-1.0), _n)/2.0;
}
}
return(_y);
}
// double elliptic ogee
// http://www.flong.com/texts/code/shapers_circ/
p5.Ease.prototype.doubleEllipticOgee = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
var _y = 0;
if (_x<=_a){
_y = (_b/_a) * sqrt(sq(_a) - sq(_x-_a));
}
else {
_y = 1.0 - ((1.0-_b)/(1.0-_a))*sqrt(sq(1.0-_a) - sq(_x-_a));
}
return(_y);
}
// double-cubic ogee
p5.Ease.prototype.doubleCubicOgee = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
var _y = 0;
if (_x <= _a){
_y = _b - _b*pow(1.0-_x/_a, 3.0);
}
else {
_y = _b + (1.0-_b)*pow((_x-_a)/(1.0-_a), 3.0);
}
return(_y);
}
// double circular sigmoid function
p5.Ease.prototype.doubleCircularSigmoid = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var _y = 0;
if (_x<=_a) {
_y = _a - sqrt(_a*_a - _x*_x);
}
else {
_y = _a + sqrt(sq(1.0-_a) - sq(_x-1.0));
}
return(_y);
}
// double squircular sigmoid function
p5.Ease.prototype.doubleSquircularSigmoid = function(_x, _a, _n)
{
if(!_a) _a = 0.25; // default
if(!_n) _n = 3; // default
var pwn = max(2, _n * 2.0);
var _y = 0;
if (_x<=_a) {
_y = _a - pow( pow(_a,pwn) - pow(_x,pwn), 1.0/pwn);
}
else {
_y = _a + pow(pow(1.0-_a, pwn) - pow(_x-1.0, pwn), 1.0/pwn);
}
return(_y);
}
// double quadratic bezier curve
// http://engineeringtraining.tpub.com/14069/css/14069_150.htm
p5.Ease.prototype.doubleQuadraticBezier = function(_x, _a, _b, _c, _d)
{
// produces mysterious values when a=0,b=1,c=0.667,d=0.417
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
if(!_d) _d = 0.25; // default
var xmid = (_a + _c)/2.0;
var ymid = (_b + _d)/2.0;
xmid = constrain (xmid, Number.EPSILON, 1.0-Number.EPSILON);
ymid = constrain (ymid, Number.EPSILON, 1.0-Number.EPSILON);
var _y = 0;
var om2a;
var t;
var xx;
var aa;
var bb;
if (_x <= xmid){
xx = _x / xmid;
aa = _a / xmid;
bb = _b / ymid;
om2a = 1.0 - 2.0*aa;
if (om2a == 0) {
om2a = Number.EPSILON;
}
t = (sqrt(aa*aa + om2a*xx) - aa)/om2a;
_y = (1.0-2.0*bb)*(t*t) + (2*bb)*t;
_y *= ymid;
}
else {
xx = (_x - xmid)/(1.0-xmid);
aa = (_c - xmid)/(1.0-xmid);
bb = (_d - ymid)/(1.0-ymid);
om2a = 1.0 - 2.0*aa;
if (om2a == 0) {
om2a = Number.EPSILON;
}
t = (sqrt(aa*aa + om2a*xx) - aa)/om2a;
_y = (1.0-2.0*bb)*(t*t) + (2*bb)*t;
_y *= (1.0 - ymid);
_y += ymid;
}
return(_y);
}
// double-elliptic sigmoid function
p5.Ease.prototype.doubleEllipticSigmoid = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var _y = 0;
if (_x<=_a){
if (_a <= 0){
_y = 0;
} else {
_y = _b * (1.0 - (sqrt(sq(_a) - sq(_x))/_a));
}
}
else {
if (_a >= 1){
_y = 1.0;
} else {
_y = _b + ((1.0-_b)/(1.0-_a))*sqrt(sq(1.0-_a) - sq(_x-1.0));
}
}
return(_y);
}
// simplified double-cubic ogee
p5.Ease.prototype.doubleCubicOgeeSimplified = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
_b = 1 - _b; //reverse, for intelligibility.
var _y = 0;
if (_x<=_a){
if (_a <= 0){
_y = 0;
} else {
var val = 1 - _x/_a;
_y = _b*_x + (1-_b)*_a*(1.0- val*val*val);
}
}
else {
if (_a >= 1){
_y = 1;
} else {
var val = (_x-_a)/(1-_a);
_y = _b*_x + (1-_b)*(_a + (1-_a)* val*val*val);
}
}
return(_y);
}
// raised inverted cosine function
p5.Ease.prototype.raisedInvertedCosine = function(_x)
{
var _y = (1.0 - cos(PI*_x))/2.0;
return(_y);
}
// blinn / wyvill's cosine approximation
// http://www.flong.com/texts/code/shapers_poly/
p5.Ease.prototype.cosineApproximation = function(_x)
{
var x2 = _x*_x;
var x4 = x2*x2;
var x6 = x4*x2;
var fa = (4.0/9.0);
var fb = (17.0/9.0);
var fc = (22.0/9.0);
var _y = fa*x6 - fb*x4 + fc*x2;
return(_y);
}
// smoothstep function
// https://en.wikipedia.org/wiki/Smoothstep
p5.Ease.prototype.smoothStep = function(_x)
{
return(_x*_x*(3.0 - 2.0*_x));
}
// ken perlin's 'smoother step' smoothstep function
// https://www.amazon.com/Texturing-Modeling-Third-Procedural-Approach/dp/1558608486
p5.Ease.prototype.smootherStep = function(_x)
{
return(_x*_x*_x*(_x*(_x*6.0 - 15.0) + 10.0));
}
// maclaurin cosine approximation
// http://blogs.ubc.ca/infiniteseriesmodule/units/unit-3-power-series/taylor-series/the-maclaurin-expansion-of-cosx/
p5.Ease.prototype.maclaurinCosine = function(_x)
{
var nTerms = 6; // anything less is fouled
_x *= PI;
var xp = 1.0;
var x2 = _x*_x;
var sig = 1.0;
var fact = 1.0;
var _y = xp;
for (var i=0; i<nTerms; i++) {
xp *= x2;
sig = 0-sig;
fact *= (i*2+1);
fact *= (i*2+2);
_y += sig * (xp / fact);
}
_y = (1.0 - _y)/2.0;
return(_y);
}
// paul bourke's catmull rom spline
// https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
// from http://paulbourke.net/miscellaneous/interpolation/
p5.Ease.prototype.catmullRomInterpolate = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var y0 = _a;
var y3 = _b;
var x2 = _x*_x;
var a0 = -0.5*y0 + 0.5*y3 - 1.5 ;
var a1 = y0 - 0.5*y3 + 2.0 ;
var a2 = -0.5*y0 + 0.5 ;
var _y = a0*_x*x2 + a1*x2 + a2*_x;
return(constrain(_y, 0, 1));
}
// hermite polynomial function
// https://en.wikipedia.org/wiki/Hermite_polynomials
// from http://musicdsp.org/showArchiveComment.php?ArchiveID=93
// by Laurent de Soras
p5.Ease.prototype.hermite = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.; // default - ???
if(!_c) _c = 1.; // default - ???
if(!_d) _d = 0.25; // default
_a = map(_a, 0,1, -1,1);
_c = map(_c, 0,1, -1,1);
var hC = (_c - _a) * 0.5;
var hV = (_b - _c);
var hW = hC + hV;
var hA = hW + hV + (_d - _b) * 0.5;
var hB = hW + hA;
var _y = (((hA * _x) - hB) * _x + hC) * _x + _b;
return(_y);
}
// hermite polynomial function
// from http://paulbourke.net/miscellaneous/interpolation/
p5.Ease.prototype.hermite2 = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
if(!_d) _d = 0.25; // default
//
// Tension: 1 is high, 0 normal, -1 is low
// Bias: 0 is even, positive is towards first segment, negative towards the other
//
var tension = map (_c, 0,1, -1,1);
var bias = map (_d, 0,1, -1,1);
var y0 = 2.0 * (_a - 0.5); //? a
var y1 = 0.0;
var y2 = 1.0;
var y3 = _b;
var x2 = _x * _x;
var x3 = x2 * _x;
var m0, m1;
m0 = (y1-y0)*(1.0+bias)*(1.0-tension)/2.0;
m0 += (y2-y1)*(1.0-bias)*(1.0-tension)/2.0;
m1 = (y2-y1)*(1.0+bias)*(1.0-tension)/2.0;
m1 += (y3-y2)*(1.0-bias)*(1.0-tension)/2.0;
var a0 = 2.0*x3 - 3.0*x2 + 1.0;
var a1 = x3 - 2.0*x2 + _x;
var a2 = x3 - x2;
var a3 = -2.0*x3 + 3.0*x2;
var _y = a0*y1 + a1*m0 + a2*m1 + a3*y2;
return(_y);
}
// error function
// http://en.wikipedia.org/wiki/Error_function
// Note that this implementation is a shifted, scaled and normalized error function!
p5.Ease.prototype.normalizedErf = function(_x)
{
var erfBound = 2.0; // set bounds for artificial "normalization"
var erfBoundNorm = 0.99532226501; // this = erf(2.0), i.e., erf(erfBound)
var z = map(_x, 0.0, 1.0, 0-erfBound, erfBound);
var z2 = z*z;
var a = (8.0*(PI-3.0)) / ((3*PI)*(4.0-PI));
var _y = sqrt (1.0 - exp(0 - z2*( (a*z2 + 4.0/PI) / (a*z2 + 1.0))));
if (z < 0.0) _y = 0-_y;
_y /= erfBoundNorm;
_y = (_y+1.0) / 2.0;
return(_y);
}
// inverse error function
p5.Ease.prototype.normalizedInverseErf = function(_x)
{
var erfBound = 2.0;
var erfBoundNorm = 0.99532226501; // this = erf(2.0), i.e., erf(erfBound)
var z = map(_x, 0, 1, -erfBoundNorm, erfBoundNorm);
var z2 = z*z;
var a = (8.0*(PI-3.0)) / ((3*PI)*(4.0-PI));
var A = (2.0 / (PI *a)) + (log(1.0-z2) / 2.0);
var B = (log(1.0-z2) / a);
var _y = sqrt( sqrt(A*A - B) - A );
if (z < 0.0) _y = 0-_y;
_y /= erfBound;
_y = (_y+1.0);
_y /= 2.0;
_y = constrain(_y, 0, 1); // necessary
return(_y);
}
// exponential emphasis function
p5.Ease.prototype.exponentialEmphasis = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
if (_a < 0.5) {
// emphasis
_a = 2*(_a);
var _y = pow(_x, _a);
return(_y);
}
else {
// de-emphasis
_a = 2*(_a-0.5);
var _y = pow(_x, 1.0/(1-_a));
return(_y);
}
}
// iterative square root
// http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
// ancient babylonian technology
p5.Ease.prototype.iterativeSquareRoot = function(_x)
{
var _y = 0.5;
var n = 6;
for (var i=0; i<n; i++) {
_y = (_y + _x/_y)/2.0;
}
return(_y);
}
// fast inverse square root
// http://en.wikipedia.org/wiki/Fast_inverse_square_root
// http://stackoverflow.com/questions/11513344/how-to-implement-the-fast-inverse-square-root-in-java
p5.Ease.prototype.fastSquareRoot = function(_x)
{
var xhalf = 0.5 * _x;
var i = f2ib(_x);
i = 0x5f3759df - (i>>1);
_x = ib2f(i);
_x = _x*(1.5 - xhalf*_x*_x);
return(1.0/_x);
}
// symmetric double-exponential ogee
p5.Ease.prototype.doubleExponentialOgee = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
var _y = 0;
if (_x<=0.5){
_y = (pow(2.0*_x, 1.0-_a))/2.0;
}
else {
_y = 1.0 - (pow(2.0*(1.0-_x), 1.0-_a))/2.0;
}
return(_y);
}
// joining two lines with a circular arc fillet
// Adapted from robert d. miller / graphics gems
// http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/fillet.c
p5.Ease.prototype.circularFillet = function(_x, _a, _b, _c)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
var arcStartAngle = 0;
var arcEndAngle = 0;
var arcStartX = 0;
var arcStartY = 0;
var arcEndX = 0;
var arcEndY = 0;
var arcCenterX = 0;
var arcCenterY = 0;
var arcRadius = 0;
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0 + Number.EPSILON;
var max_param_b = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
var R = _c;
// helper function:
// return signed distance from line Ax + By + C = 0 to point P.
function linetopoint(a, b, c, ptx, pty) {
var lp = 0.0;
var d = sqrt((a*a)+(b*b));
if (d != 0.0) {
lp = (a*ptx + b*pty + c)/d;
}
return(lp);
}
// compute fillet parameters:
computefillet: {
var p1x = 0;
var p1y = 0;
var p2x = _a;
var p2y = _b;
var p3x = _a;
var p3y = _b;
var p4x = 1;
var p4y = 1;
var r = R;
var c1 = p2x*p1y - p1x*p2y;
var a1 = p2y-p1y;
var b1 = p1x-p2x;
var c2 = p4x*p3y - p3x*p4y;
var a2 = p4y-p3y;
var b2 = p3x-p4x;
if ((a1*b2) == (a2*b1)) { /* Parallel or coincident lines */
break computefillet;
}
var d1, d2;
var mPx, mPy;
mPx= (p3x + p4x)/2.0;
mPy= (p3y + p4y)/2.0;
d1 = linetopoint(a1, b1, c1, mPx, mPy); /* Find distance p1p2 to p3 */
if (d1 == 0.0) {
break computefillet;
}
mPx= (p1x + p2x)/2.0;
mPy= (p1y + p2y)/2.0;
d2 = linetopoint(a2, b2, c2, mPx, mPy); /* Find distance p3p4 to p2 */
if (d2 == 0.0) {
break computefillet;
}
var c1p, c2p, d;
var rr = r;
if (d1 <= 0.0) {
rr= -rr;
}
c1p = c1 - rr*sqrt((a1*a1)+(b1*b1)); /* Line parallel l1 at d */
rr = r;
if (d2 <= 0.0) {
rr = -rr;
}
c2p = c2 - rr*sqrt((a2*a2)+(b2*b2)); /* Line parallel l2 at d */
d = (a1*b2)-(a2*b1);
var pCx = (c2p*b1-c1p*b2)/d; /* Intersect constructed lines */
var pCy = (c1p*a2-c2p*a1)/d; /* to find center of arc */
var pAx = 0;
var pAy = 0;
var pBx = 0;
var pBy = 0;
var dP, cP;
dP = (a1*a1) + (b1*b1); /* Clip or extend lines as required */
if (dP != 0.0) {
cP = a1*pCy - b1*pCx;
pAx = (-a1*c1 - b1*cP)/dP;
pAy = ( a1*cP - b1*c1)/dP;
}
dP = (a2*a2) + (b2*b2);
if (dP != 0.0) {
cP = a2*pCy - b2*pCx;
pBx = (-a2*c2 - b2*cP)/dP;
pBy = ( a2*cP - b2*c2)/dP;
}
var gv1x = pAx-pCx;
var gv1y = pAy-pCy;
var gv2x = pBx-pCx;
var gv2y = pBy-pCy;
var arcStart = atan2(gv1y, gv1x);
var arcAngle = 0.0;
var dd = sqrt(((gv1x*gv1x)+(gv1y*gv1y)) * ((gv2x*gv2x)+(gv2y*gv2y)));
if (dd != 0.0) {
arcAngle = (acos((gv1x*gv2x + gv1y*gv2y)/dd));
}
var crossProduct = (gv1x*gv2y - gv2x*gv1y);
if (crossProduct < 0.0) {
arcStart -= arcAngle;
}
var arc1 = arcStart;
var arc2 = arcStart + arcAngle;
if (crossProduct < 0.0) {
arc1 = arcStart + arcAngle;
arc2 = arcStart;
}
arcCenterX = pCx;
arcCenterY = pCy;
arcStartAngle = arc1;
arcEndAngle = arc2;
arcRadius = r;
arcStartX = arcCenterX + arcRadius*cos(arcStartAngle);
arcStartY = arcCenterY + arcRadius*sin(arcStartAngle);
arcEndX = arcCenterX + arcRadius*cos(arcEndAngle);
arcEndY = arcCenterY + arcRadius*sin(arcEndAngle);
}
// end compute
var t = 0;
var y = 0;
_x = constrain(_x, 0, 1);
if (_x <= arcStartX) {
if (arcStartX < Math.EPSILON){
_y = 0;
} else {
t = _x / arcStartX;
_y = t * arcStartY;
}
}
else if (_x >= arcEndX) {
t = (_x - arcEndX)/(1 - arcEndX);
_y = arcEndY + t*(1 - arcEndY);
}
else {
if (_x >= arcCenterX) {
_y = arcCenterY - sqrt(sq(arcRadius) - sq(_x-arcCenterX));
}
else {
_y = arcCenterY + sqrt(sq(arcRadius) - sq(_x-arcCenterX));
}
}
return(_y);
}
// circular arc through a point
// adapted from paul bourke
// http://paulbourke.net/geometry/circlesphere/Circle.cpp
p5.Ease.prototype.circularArcThroughAPoint = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var m = {};
m.centerX = 0;
m.centerY = 0;
m.dRadius = 0;
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0 + Number.EPSILON;
var max_param_b = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
_x = constrain(_x, 0+Number.EPSILON,1-Number.EPSILON);
var pt1x = 0;
var pt1y = 0;
var pt2x = _a;
var pt2y = _b;
var pt3x = 1;
var pt3y = 1;
// helper functions:
// check if the lines defined by the given points are perpendicular
// to the x or y axis - used as a check before calcCircleFrom3Points()
// from paul bourke's Circle.cpp
function isPerpendicular(pt1x, pt1y, pt2x, pt2y, pt3x, pt3y)
{
var yDelta_a = pt2y - pt1y;
var xDelta_a = pt2x - pt1x;
var yDelta_b = pt3y - pt2y;
var xDelta_b = pt3x - pt2x;
// checking whether the line of the two pts are vertical
if (abs(xDelta_a) <= Number.EPSILON && abs(yDelta_b) <= Number.EPSILON){
return(false);
}
if (abs(yDelta_a) <= Number.EPSILON){
return(true);
}
else if (abs(yDelta_b) <= Number.EPSILON){
return(true);
}
else if (abs(xDelta_a)<= Number.EPSILON){
return(true);
}
else if (abs(xDelta_b)<= Number.EPSILON){
return(true);
}
else return(false);
}
// from paul bourke's Circle.cpp
function calcCircleFrom3Points(pt1x, pt1y, pt2x, pt2y, pt3x, pt3y, m)
{
var yDelta_a = pt2y - pt1y;
var xDelta_a = pt2x - pt1x;
var yDelta_b = pt3y - pt2y;
var xDelta_b = pt3x - pt2x;
if (abs(xDelta_a) <= Number.EPSILON && abs(yDelta_b) <= Number.EPSILON){
m.centerX = 0.5*(pt2x + pt3x);
m.centerY = 0.5*(pt1y + pt2y);
m.dRadius = sqrt(sq(m.centerX-pt1x) + sq(m.centerY-pt1y));
return;
}
// isPerpendicular() assures that xDelta(s) are not zero
var aSlope = yDelta_a / xDelta_a;
var bSlope = yDelta_b / xDelta_b;
if (abs(aSlope-bSlope) <= Number.EPSILON){ // checking whether the given points are colinear.
return;
}
// calc center
m.centerX = (aSlope*bSlope*(pt1y - pt3y) + bSlope*(pt1x + pt2x)- aSlope*(pt2x+pt3x) )/(2* (bSlope-aSlope) );
m.centerY = -1*(m.centerX - (pt1x+pt2x)/2)/aSlope + (pt1y+pt2y)/2;
m.dRadius = sqrt(sq(m.centerX-pt1x) + sq(m.centerY-pt1y));
}
if (!isPerpendicular(pt1x,pt1y, pt2x,pt2y, pt3x,pt3y) ) calcCircleFrom3Points (pt1x,pt1y, pt2x,pt2y, pt3x,pt3y, m);
else if (!isPerpendicular(pt1x,pt1y, pt3x,pt3y, pt2x,pt2y) ) calcCircleFrom3Points (pt1x,pt1y, pt3x,pt3y, pt2x,pt2y, m);
else if (!isPerpendicular(pt2x,pt2y, pt1x,pt1y, pt3x,pt3y) ) calcCircleFrom3Points (pt2x,pt2y, pt1x,pt1y, pt3x,pt3y, m);
else if (!isPerpendicular(pt2x,pt2y, pt3x,pt3y, pt1x,pt1y) ) calcCircleFrom3Points (pt2x,pt2y, pt3x,pt3y, pt1x,pt1y, m);
else if (!isPerpendicular(pt3x,pt3y, pt2x,pt2y, pt1x,pt1y) ) calcCircleFrom3Points (pt3x,pt3y, pt2x,pt2y, pt1x,pt1y, m);
else if (!isPerpendicular(pt3x,pt3y, pt1x,pt1y, pt2x,pt2y) ) calcCircleFrom3Points (pt3x,pt3y, pt1x,pt1y, pt2x,pt2y, m);
else {
return 0;
}
// constrain
if ((m.centerX > 0) && (m.centerX < 1)){
if (_a < m.centerX){
m.centerX = 1;
m.centerY = 0;
m.dRadius = 1;
} else {
m.centerX = 0;
m.centerY = 1;
m.dRadius = 1;
}
}
//------------------
var _y = 0;
if (_x >= m.centerX){
_y = m.centerY - sqrt(sq(m.dRadius) - sq(_x-m.centerX));
}
else{
_y = m.centerY + sqrt(sq(m.dRadius) - sq(_x-m.centerX));
}
return(_y);
}
// bezier shapers
// adapted from BEZMATH.PS (1993)
// by don lancaster, SYNERGETICS inc.
// http://www.tinaja.com/text/bezmath.html
p5.Ease.prototype.quadraticBezier = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var min_param_a = 0.0;
var max_param_a = 1.0;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
if (_a == 0.5){
_a += Number.EPSILON;
}
// solve t from x (an inverse operation)
var om2a = 1.0 - 2.0*_a;
var t = (sqrt(_a*_a + om2a*_x) - _a)/om2a;
var _y = (1.0-2.0*_b)*(t*t) + (2*_b)*t;
return(_y);
}
// cubic bezier shaper
p5.Ease.prototype.cubicBezier = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
if(!_d) _d = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0;
var max_param_b = 1.0;
var min_param_c = 0.0 + Number.EPSILON;
var max_param_c = 1.0 - Number.EPSILON;
var min_param_d = 0.0;
var max_param_d = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
_c = constrain(_c, min_param_c, max_param_c);
_d = constrain(_d, min_param_d, max_param_d);
//-------------------------------------------
var y0a = 0.00; // initial y
var x0a = 0.00; // initial x
var y1a = _b; // 1st influence y
var x1a = _a; // 1st influence x
var y2a = _d; // 2nd influence y
var x2a = _c; // 2nd influence x
var y3a = 1.00; // final y
var x3a = 1.00; // final x
var A = x3a - 3*x2a + 3*x1a - x0a;
var B = 3*x2a - 6*x1a + 3*x0a;
var C = 3*x1a - 3*x0a;
var D = x0a;
var E = y3a - 3*y2a + 3*y1a - y0a;
var F = 3*y2a - 6*y1a + 3*y0a;
var G = 3*y1a - 3*y0a;
var H = y0a;
// Solve for t given x (using Newton-Raphelson), then solve for y given t.
// Assume for the first guess that t = x.
var currentt = _x;
var nRefinementIterations = 5;
for (var i=0; i<nRefinementIterations; i++){
var currentx = A*(currentt*currentt*currentt) + B*(currentt*currentt) + C*currentt + D;
var currentslope = 1.0/(3.0*A*currentt*currentt + 2.0*B*currentt + C);
currentt -= (currentx - _x)*(currentslope);
currentt = constrain(currentt, 0,1.0);
}
//------------
var _y = E*(currentt*currentt*currentt) + F*(currentt*currentt) + G*currentt + H;
return(_y);
}
// parabola through a point
p5.Ease.prototype.parabolaThroughAPoint = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
var A = (1-_b)/(1-_a) - (_b/_a);
var B = (A*(_a*_a)-_b)/_a;
var _y = A*(_x*_x) - B*(_x);
_y = constrain(_y, 0,1);
return(_y);
}
// damped sine wave
// n.b. decays to 0 at x=1
// http://en.wikipedia.org/wiki/Damped_sine_wave
p5.Ease.prototype.dampedSinusoid = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var omega = 100*_a;
var lambda = -6.90775527; // ln(lambda) = 0.001 // decay constant
var phi = 0;
var e = 2.718281828459045;
var t = _x;
var _y = pow(e, lambda*t) * cos(omega*t + phi);
return(_y);
}
// damped sine wave (reversed)
p5.Ease.prototype.dampedSinusoidReverse = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var omega = 100*_a;
var lambda = -6.90775527; // ln(lambda) = 0.001
var phi = 0;
var e = 2.718281828459045;
var t = 1.0-_x;
var _y = pow(e, lambda*t) * cos(omega*t + phi);
return(_y);
}
// cubic bezier through two points
p5.Ease.prototype.cubicBezierThrough2Points = function(_x, _a, _b, _c, _d)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
if(!_c) _c = 0.75; // default
if(!_d) _d = 0.25; // default
var _y = 0;
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var min_param_b = 0.0 + Number.EPSILON;
var max_param_b = 1.0 - Number.EPSILON;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
var x0 = 0;
var y0 = 0;
var x4 = _a;
var y4 = _b;
var x5 = _c;
var y5 = _d;
var x3 = 1;
var y3 = 1;
var x1,y1,x2,y2; // to be solved.
var t1 = 0.3;
var t2 = 0.7;
var B0t1 = (1-t1)*(1-t1)*(1-t1);
var B1t1 = 3*t1*(1-t1)*(1-t1);
var B2t1 = 3*t1*t1*(1-t1);
var B3t1 = t1*t1*t1;
var B0t2 = (1-t2)*(1-t2)*(1-t2);
var B1t2 = 3*t2*(1-t2)*(1-t2);;
var B2t2 = 3*t2*t2*(1-t2);;
var B3t2 = t2*t2*t2;
var ccx = x4 - x0*B0t1 - x3*B3t1;
var ccy = y4 - y0*B0t1 - y3*B3t1;
var ffx = x5 - x0*B0t2 - x3*B3t2;
var ffy = y5 - y0*B0t2 - y3*B3t2;
x2 = (ccx - (ffx*B1t1)/B1t2) / (B2t1 - (B1t1*B2t2)/B1t2);
y2 = (ccy - (ffy*B1t1)/B1t2) / (B2t1 - (B1t1*B2t2)/B1t2);
x1 = (ccx - x2*B2t1) / B1t1;
y1 = (ccy - y2*B2t1) / B1t1;
x1 = constrain(x1, 0+Number.EPSILON,1-Number.EPSILON);
x2 = constrain(x2, 0+Number.EPSILON,1-Number.EPSILON);
_y = this.cubicBezier (_x, x1,y1, x2,y2);
_y = constrain(_y,0,1);
return(_y);
}
// double circular ogee
p5.Ease.prototype.doubleCircularOgee = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0;
var max_param_a = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
var _y = 0;
if (_x<=_a){
_y = sqrt(sq(_a) - sq(_x-_a));
}
else {
_y = 1 - sqrt(sq(1-_a) - sq(_x-_a));
}
return(_y);
}
// double squircular ogee
p5.Ease.prototype.doubleSquircularOgee = function(_x, _a, _n)
{
if(!_a) _a = 0.25; // default
if(!_n) _n = 3; // default
var min_param_a = 0.0;
var max_param_a = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
var pown = 2.0 * _n;
var _y = 0;
if (_x<=_a){
_y = pow( pow(_a,pown) - pow(_x-_a, pown), 1.0/pown);
}
else {
_y = 1.0 - pow( pow(1-_a,pown) - pow(_x-_a, pown), 1.0/pown);
}
return(_y);
}
// generalized combo sigmoid / logit function
p5.Ease.prototype.generalSigmoidLogitCombo = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var _y = 0;
if (_a < 0.5){
// Logit
var dy = _b - 0.5;
_y = dy + this.normalizedLogit (_x, 1.0-(2.0*_a));
} else {
// Sigmoid
var dx = _b - 0.5;
_y = this.normalizedLogitSigmoid (_x+dx, (2.0*(_a-0.5)));
}
_y = constrain(_y, 0, 1);
return(_y);
}
// normalized logistic sigmoid function
p5.Ease.prototype.normalizedLogitSigmoid = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var emph = 5.0;
_a = constrain(_a, min_param_a, max_param_a);
_a = (1.0/(1.0-_a) - 1.0);
_a = emph * _a;
var _y = 1.0 / (1.0 + exp(0 - (_x-0.5)*_a ));
var miny = 1.0 / (1.0 + exp( 0.5*_a ));
var maxy = 1.0 / (1.0 + exp( -0.5*_a ));
_y = map(_y, miny, maxy, 0, 1);
return(_y);
}
// logit function
// https://en.wikipedia.org/wiki/Logit
p5.Ease.prototype.normalizedLogit = function(_x, _a)
{
if(!_a) _a = 0.25; // default
var min_param_a = 0.0 + Number.EPSILON;
var max_param_a = 1.0 - Number.EPSILON;
var emph = 5.0;
_a = constrain(_a, min_param_a, max_param_a);
_a = (1/(1-_a) - 1);
_a = emph * _a;
var minx = 1.0 / (1.0 + exp( 0.5*_a ));
var maxx = 1.0 / (1.0 + exp( -0.5*_a ));
_x = map(_x, 0,1, minx, maxx);
var _y = log (_x / (1.0 - _x)) ;
_y *= 1.0/_a;
_y += 0.5;
_y = constrain (_y, 0, 1);
return(_y);
}
// quartic easing function
p5.Ease.prototype.generalizedQuartic = function(_x, _a, _b)
{
if(!_a) _a = 0.25; // default
if(!_b) _b = 0.75; // default
var min_param_a = 0.0;
var max_param_a = 1.0;
var min_param_b = 0.0;
var max_param_b = 1.0;
_a = constrain(_a, min_param_a, max_param_a);
_b = constrain(_b, min_param_b, max_param_b);
_a = 1.0-_a;
var _w = (1-2*_a)*(_x*_x) + (2*_a)*_x;
var _y = (1-2*_b)*(_w*_w) + (2*_b)*_w;
return(_y);
}
// boxcar function (normalized heaviside step function)
// http://mathworld.wolfram.com/BoxcarFunction.html
// https://en.wikipedia.org/wiki/Heaviside_step_function
p5.Ease.prototype.boxcar = function(_x)
{
return(_x>=0.5);
}
// list algorithms
p5.Ease.prototype.listAlgos = function() {
var _styles = new Array();
for(var i in this.__proto__) {
var _t = true;
if(i=="listAlgos") _t=false;
else if(i=="fillArray") _t=false;
else if(i=="fillFloat32Array") _t=false;
else if(i=="fillFloat64Array") _t=false;
if(_t) _styles.push(i);
}
return(_styles);
}
// array xfer (for pre-rendered use)
p5.Ease.prototype.fillArray = function(_algo, _len, _args) {
var _dest = new Array(_len);
for(var i = 0;i<_len;i++)
{
var _p = i/(_len-1); // 0.-1.
_dest[i] = this[_algo](_p, _args);
}
return(_dest);
}
// array xfer (for pre-rendered use)
p5.Ease.prototype.fillFloat32Array = function(_algo, _len, _args) {
var _dest = new Float32Array(_len);
for(var i = 0;i<_len;i++)
{
var _p = i/(_len-1); // 0.-1.
_dest[i] = this[_algo](_p, _args);
}
return(_dest);
}
// array xfer (for pre-rendered use)
p5.Ease.prototype.fillFloat64Array = function(_algo, _len, _args) {
var _dest = new Float64Array(_len);
for(var i = 0;i<_len;i++)
{
var _p = i/(_len-1); // 0.-1.
_dest[i] = this[_algo](_p, _args);
}
return(_dest);
}
// =============================================================================
// p5.ArrayEval
// =============================================================================
/**
* Base class for an array evaluator
*
* @class p5.Gen
* @constructor
*/
p5.ArrayEval = function() {
//
// this object implements an 'eval'-style
// equation evaluator across n-dimensional arrays.
// insired by the 'exprfill' / [jit.expr] functionality
// in Max/MSP.
//
// note that the javascript eval() function is *not*
// considered to be particularly secure, as it can
// easily be used to execute arbitrary code.
//
// see here for an exhausting discussion of the issue:
// https://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea
//
// the p5.ArrayEval object has three methods to create
// 1-, 2-, and 3- dimensional javascript arrays based on
// a formula encoded in a string.
// the letters u, v, and w will be replaced with various
// 'normal' maps based on their cell positions.
// * u, v, w will unwrap to 0. to 1. across dimension 1, 2, and 3
// * su, sv, sw will unwrap to -1. to 1.
// * cu, cv, cw will unwrap to their integer position in the array
// * du, dv, dw gets replaced with the length of the array in that dimension
//
// the object returns an array that solves the equation, so...
// if you instantiate an object...
// var e = new p5.ArrayEval();
// then...
// e.eval('u', 40);
// will return a one-dimensional array with 40 values from 0. to 1.
// and...
// e.eval2d('su*sv', 20, 20);
// will return a two-dimensional array with 20x20 values from -1. to 1. multiplied together.
//
// because the eval() is run in the browser, any code included will add
// functionality to the p5.ArrayEval object, e.g. p5.js math functions
// (sin(), cos(), etc.) will work correctly.
//
this.version = 0.01; // just some crap for constructor
var that = this; // some bullshit
// global dims
var l1 = 0;
var l2 = 0;
var l3 = 0;
}; // end p5.ArrayEval constructor
// array return - 1d
p5.ArrayEval.prototype.eval = function(_evalstr, _l1) {
this.l1 = _l1; // make global
var multi = 0; // default one output
var e;
if(Array.isArray(_evalstr)) multi = 1; // array per result
var _dest;
if(multi) _dest = createArray(_l1, _evalstr.length);
else _dest = createArray(_l1);
// string expansion:
// u unwraps to 0-1
// su unwraps to -1 to 1
// cu unwraps to cell value (0 to dim-1)
// du unwraps to a constant representing the dimension (size)
if(multi)
{
for(e in _evalstr)
{
_evalstr[e] = _evalstr[e].replace(/cu/g, "i");
_evalstr[e] = _evalstr[e].replace(/du/g, "l1");
_evalstr[e] = _evalstr[e].replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/u/g, "(i/(l1-1))");
}
}
else {
_evalstr = _evalstr.replace(/cu/g, "i");
_evalstr = _evalstr.replace(/du/g, "l1");
_evalstr = _evalstr.replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr = _evalstr.replace(/u/g, "(i/(l1-1))");
}
//console.log(_evalstr);
for(var i = 0;i<this.l1;i++)
{
if(multi)
{
for(e = 0;e<_evalstr.length;e++)
{
_dest[i][e] = eval('with(this) { ' + _evalstr[e] + ' }');
}
}
else _dest[i] = eval('with(this) { ' + _evalstr + ' }');
}
return(_dest);
}
// function synonym
p5.ArrayEval.prototype.eval1d = function(_evalstr, _l1)
{
return(this.eval(_evalstr, _l1));
}
// array return - 2d
p5.ArrayEval.prototype.eval2d = function(_evalstr, _l1, _l2) {
this.l1 = _l1; // make global
this.l2 = _l2; // make global
var multi = 0; // default one output
var e;
if(Array.isArray(_evalstr)) multi = 1; // array per result
var _dest;
if(multi) _dest = createArray(_l1, _l2, _evalstr.length);
else _dest = createArray(_l1, _l2);
// string expansion:
// u unwraps to 0-1
// su unwraps to -1 to 1
// cu unwraps to cell value (0 to dim-1)
// du unwraps to a constant representing the dimension (size)
// v unwraps to 0-1
// sv unwraps to -1 to 1
// cv unwraps to cell value (0 to dim-1)
// dv unwraps to a constant representing the dimension (size)
if(multi)
{
for(e in _evalstr)
{
_evalstr[e] = _evalstr[e].replace(/cu/g, "i");
_evalstr[e] = _evalstr[e].replace(/du/g, "l1");
_evalstr[e] = _evalstr[e].replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/u/g, "(i/(l1-1))");
_evalstr[e] = _evalstr[e].replace(/cv/g, "j");
_evalstr[e] = _evalstr[e].replace(/dv/g, "l2");
_evalstr[e] = _evalstr[e].replace(/sv/g, "(j/(l2-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/v/g, "(j/(l2-1))");
}
}
else {
_evalstr = _evalstr.replace(/cu/g, "i");
_evalstr = _evalstr.replace(/du/g, "l1");
_evalstr = _evalstr.replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr = _evalstr.replace(/u/g, "(i/(l1-1))");
_evalstr = _evalstr.replace(/cv/g, "j");
_evalstr = _evalstr.replace(/dv/g, "l2");
_evalstr = _evalstr.replace(/sv/g, "(j/(l2-1)*2.-1.)");
_evalstr = _evalstr.replace(/v/g, "(j/(l2-1))");
}
//console.log(_evalstr);
for(var i = 0;i<this.l1;i++)
{
for(var j = 0;j<this.l2;j++)
{
if(multi)
{
for(e = 0;e<_evalstr.length;e++)
{
_dest[i][j][e] = eval('with(this) { ' + _evalstr[e] + ' }');
}
}
else _dest[i][j] = eval('with(this) { ' + _evalstr + ' }');
}
}
return(_dest);
}
// array return - 3d
p5.ArrayEval.prototype.eval3d = function(_evalstr, _l1, _l2, _l3) {
this.l1 = _l1; // make global
this.l2 = _l2; // make global
this.l3 = _l3; // make global
var multi = 0; // default one output
var e;
if(Array.isArray(_evalstr)) multi = 1; // array per result
var _dest;
if(multi) _dest = createArray(_l1, _l2, _l3, _evalstr.length);
else _dest = createArray(_l1, _l2, _l3);
// string expansion:
// u unwraps to 0-1
// su unwraps to -1 to 1
// cu unwraps to cell value (0 to dim-1)
// du unwraps to a constant representing the dimension (size)
// v unwraps to 0-1
// sv unwraps to -1 to 1
// cv unwraps to cell value (0 to dim-1)
// dv unwraps to a constant representing the dimension (size)
// w unwraps to 0-1
// sw unwraps to -1 to 1
// cw unwraps to cell value (0 to dim-1)
// dw unwraps to a constant representing the dimension (size)
if(multi)
{
for(e in _evalstr)
{
_evalstr[e] = _evalstr[e].replace(/cu/g, "i");
_evalstr[e] = _evalstr[e].replace(/du/g, "l1");
_evalstr[e] = _evalstr[e].replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/u/g, "(i/(l1-1))");
_evalstr[e] = _evalstr[e].replace(/cv/g, "j");
_evalstr[e] = _evalstr[e].replace(/dv/g, "l2");
_evalstr[e] = _evalstr[e].replace(/sv/g, "(j/(l2-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/v/g, "(j/(l2-1))");
_evalstr[e] = _evalstr[e].replace(/cw/g, "k");
_evalstr[e] = _evalstr[e].replace(/dw/g, "l3");
_evalstr[e] = _evalstr[e].replace(/sw/g, "(k/(l3-1)*2.-1.)");
_evalstr[e] = _evalstr[e].replace(/w/g, "(k/(l3-1))");
}
}
else {
_evalstr = _evalstr.replace(/cu/g, "i");
_evalstr = _evalstr.replace(/du/g, "l1");
_evalstr = _evalstr.replace(/su/g, "(i/(l1-1)*2.-1.)");
_evalstr = _evalstr.replace(/u/g, "(i/(l1-1))");
_evalstr = _evalstr.replace(/cv/g, "j");
_evalstr = _evalstr.replace(/dv/g, "l2");
_evalstr = _evalstr.replace(/sv/g, "(j/(l2-1)*2.-1.)");
_evalstr = _evalstr.replace(/v/g, "(j/(l2-1))");
_evalstr = _evalstr.replace(/cw/g, "k");
_evalstr = _evalstr.replace(/dw/g, "l3");
_evalstr = _evalstr.replace(/sw/g, "(k/(l3-1)*2.-1.)");
_evalstr = _evalstr.replace(/w/g, "(k/(l3-1))");
}
//console.log(_evalstr);
for(var i = 0;i<this.l1;i++)
{
for(var j = 0;j<this.l2;j++)
{
for(var k = 0;k<this.l3;k++)
{
if(multi)
{
for(e = 0;e<_evalstr.length;e++)
{
_dest[i][j][k][e] = eval('with(this) { ' + _evalstr[e] + ' }');
}
}
else _dest[i][j][k] = eval('with(this) { ' + _evalstr + ' }');
}
}
}
return(_dest);
}
// =============================================================================
// p5.Filt
// =============================================================================
/**
* Base class for a time-domain filter
*
* @class p5.Filt
* @constructor
*/
p5.Filt = function(_fs) {
//
// this object implements time-domain filtering based on
// robert bristow-johnson's cookbook formulae for
// biquadratic (2 pole, 2 zero) filters :
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
// Copyright (C) 2003 Robert Bristow-Johnson
//
// we are using his general 2p2z / biquad formula:
// y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2] - (a1/a0)*y[n-1] - (a2/a0)*y[n-2]
//
// this is the same algorithm used in the [biquad~] object in PureData and Max/MSP,
// the [2p2z~] object in Max/FTS, the BiQuad.cpp ugen in the STK (ChucK, etc.),
// SOS in SuperCollider, the biquada opcode in CSOUND, etc. etc. etc.
//
// the biquadratic filter equation is pretty standard, insofar as you can
// construct any 'simple' filter (lowpass, highpass, bandpass, bandstop,
// allpass, etc.) with independent gain controls (coefficients) for the
// input (x[n]), (usually) the overall output (y[n]), and four samples
// of memory - the two previous input samples (x[n-1], x[n-2]), and the
// two previous output samples (y[n-1], y[n-2]).
//
// so this filter has both 2nd-order FIR (feedforward) and 2nd-order IIR
// (feedback) capabilities. you set the coefficients by running some
// trig against your desired filter characteristics...
// * type
// * cutoff / center frequency
// * Q / resonance
// * gain (for some filters)
// ...and the known sample rate (Fs).
//
// more complex filters can be constructed by 'cascading' biquad filters
// in series, e.g. for butterworth / chebyshev filters that require a
// more flat frequency response than a simple biquad can offer.
//
// you can find lots of info about this filter by searching for
// 'biquad' on your internet machine. however...
//
// some people, they will flip their 'a' and 'b' coefficients.
// some people, they will skip a0 and use 5 coefficients for biquad formulae.
// some people, they like to go out dancing.
//
// p5.Filt is offered here as a module to allow for filter design
// independent of the Web Audio framework used by p5.sound / Tone.js.
// there are lots of other things one might want to 'filter' besides sound.
// the defaults provided here are against the nominal graphics frame rate
// for p5.js (60Hz), giving an effective nyquist (upper frequency limit)
// of 30Hz. try running a random() generator through it, or using it
// to smooth out a noisy signal coming from a sensor or a network API.
// it wil process input sample-by-sample through the tick() method or
// process arrays vector-by-vector through the process() method.
//
if(!_fs) _fs = 60.; // nominal p5 default framerate
this.version = 0.01; // just some crap for constructor
var that = this; // some bullshit
// biquad / 2p2z coefficients
this.a0 = 1.; // denominator gain for filter output (y[n] term)
this.b0 = 1.; // gain for current input (x[n] term)
this.a1 = 0.; // gain for previous input (x[n-1] term)
this.b1 = 0.; // gain for previous previous input (x[n-2] term)
this.a2 = 0.; // gain for previous output (y[n-1] term)
this.b2 = 0.; // gain for previous previous output (y[n-2] term)
// sample memory
this.xn = 0.; // x[n] (input)
this.yn = 0.; // y[n] (output)
this.xpn = 0.; // x[n-1] (previous input)
this.ypn = 0.; // y[n-1] (previous output)
this.xppn = 0.; // x[n-2] (previous previous input)
this.yppn = 0.; // y[n-2] (previous previous output)
// parameters
this.fs = _fs; // sampling rate
this.type = "LPF"; // default to lowpass filter
this.f0 = this.fs/4.; // center/cutoff frequency; default to fs/4 (half nyquist)
this.dB = 0.; // gain for peaking / shelving
this.Q = 1.; // width / resonance of filter
// intermediates
this.A; // amplitude
this.w0; // filter increment in radians
this.cw0; // cosine of w0 - precompute
this.sw0; // sine of w0 - precompute
this.alpha; // alpha term - precompute
this.soff; // shelving offset - precompute
// compute coefficients based on default parameters
this.precalc();
}; // end p5.Filt constructor
// define the filter characteristics all at once.
p5.Filt.prototype.set = function(_type, _f0, _Q, _dB)
{
if(_type) this.type = _type;
if(_f0) this.f0 = _f0;
if(_Q) this.Q = _Q;
if(_dB) this.dB = _dB; // only matters for shelving filters
this.precalc();
}
// set the sampling rate (fs) of the filter.
p5.Filt.prototype.setFs = function(_fs)
{
if(_fs) this.fs = _fs;
this.precalc();
}
// set the type of the filter.
p5.Filt.prototype.setType = function(_type)
{
if(_type) this.type = _type;
this.precalc();
}
// set the cutoff/center frequency.
p5.Filt.prototype.setFreq = function(_f0)
{
if(_f0) this.f0 = _f0;
this.precalc();
}
// set the Q(uality) of the filter.
p5.Filt.prototype.setQ = function(_Q)
{
if(_Q) this.Q = _Q;
this.precalc();
}
// set the gain (in decibels).
p5.Filt.prototype.setGain = function(_dB)
{
if(_dB) this.dB = _dB;
this.precalc();
}
// set the bandwidth in Hz (inverse of Q).
p5.Filt.prototype.setBW = function(_bw)
{
// technically...
// this.Q = 1.0/(2*Math.sinh(log(2)/2*_bw*this.w0/this.sw0));
// but YOLO...
if(_bw) this.Q = this.f0/_bw;
this.precalc();
}
// process multiple values as a single vector;
// n.b. filter will retain memory... use a clear()
// beforehand if you want the filter zeroed.
p5.Filt.prototype.process = function(_x)
{
var _y; // output
// figure out input type
if(Array.isArray(_x)) _y = new Array(_x.length);
if(_x.constructor == Float32Array) _y = new Float32Array(_x.length);
if(_x.constructor == Float64Array) _y = new Float64Array(_x.length);
for(var i in _x)
{
_y[i] = this.tick(_x[i]);
}
// output
return(_y);
}
// process sample-by-sample, STK style.
p5.Filt.prototype.tick = function(_x)
{
// input
this.xn = _x;
// biquad - the only line in this whole situation that really matters:
this.yn = (this.b0/this.a0)*this.xn + (this.b1/this.a0)*this.xpn + (this.b2/this.a0)*this.xppn - (this.a1/this.a0)*this.ypn - (this.a2/this.a0)*this.yppn;
// shift
this.xppn = this.xpn;
this.xpn = this.xn;
this.yppn = this.ypn;
this.ypn = this.yn;
// output
return(this.yn);
}
// clear biquad memory -
// useful if the filter becomes unstable and you start getting NaNs as output.
p5.Filt.prototype.clear = function()
{
// clear samples
this.xn = 0; // x[n] (input)
this.yn = 0; // y[n] (output)
this.xpn = 0; // x[n-1]
this.ypn = 0; // y[n-1]
this.xppn = 0; // x[n-2]
this.yppn = 0; // y[n-2]
}
// set coefficients 'by hand' -
// useful for cascade (butterworth / chebyshev) filtering
p5.Filt.prototype.coeffs = function(_a0, _b0, _b1, _b2, _a1, _a2)
{
if(arguments.length!=6)
{
console.log("p5.Filt needs six coefficients for raw biquad:");
console.log(" a0 -> denominator gain for filter (y[n] term).");
console.log(" b0 -> gain for current input (x[n] term).");
console.log(" b1 -> gain for previous input (x[n-1] term).");
console.log(" b2 -> gain for previous previous input (x[n-2] term).");
console.log(" a1 -> gain for previous output (y[n-1] term).");
console.log(" a2 -> gain for previous previous output (y[n-2] term).");
console.log("when working with 5-coefficient biquad formulae set a0 to 1.0.");
console.log("n.b. some systems will refer to y terms as 'b' and x terms as 'a'.");
}
else
{
this.a0 = _a0; // y[n] (overall gain)
this.b0 = _b0; // x[n]
this.b1 = _b1; // x[n-1]
this.b2 = _b2; // x[n-2]
this.a1 = _a1; // y[n-1]
this.a2 = _a2; // y[n-2]
}
}
// calculate filter coefficients from parameters
p5.Filt.prototype.precalc = function()
{
// intermediates
this.A = sqrt(pow(10, this.dB/20)); // amplitude
this.w0 = 2*PI*this.f0/this.fs; // filter increment in radians
this.cw0 = cos(this.w0); // cosine of w0 - precompute
this.sw0 = sin(this.w0); // sine of w0 - precompute
this.alpha = sin(this.w0)/(2*this.Q); // alpha term - precompute
this.soff = 2*sqrt(this.A)*this.alpha; // shelving offset - precompute
switch(this.type) {
case "LPF":
case "lowpass":
this.b0 = (1 - this.cw0)/2;
this.b1 = 1 - this.cw0;
this.b2 = (1 - this.cw0)/2;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "HPF":
case "highpass":
this.b0 = (1 + this.cw0)/2;
this.b1 = -(1 + this.cw0);
this.b2 = (1 + this.cw0)/2;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "BPF":
case "bandpass":
this.b0 = this.sw0/2;
this.b1 = 0;
this.b2 = -this.sw0/2;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "BPF0": // constant 0 peak gain
case "resonant":
this.b0 = this.alpha;
this.b1 = 0;
this.b2 = -this.alpha;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "notch":
case "bandreject":
case "bandstop":
this.b0 = 1;
this.b1 = -2 * this.cw0;
this.b2 = 1;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "APF":
case "allpass":
this.b0 = 1 - this.alpha;
this.b1 = -2 * this.cw0;
this.b2 = 1 + this.alpha;
this.a0 = 1 + this.alpha;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha;
break;
case "peakingEQ":
case "peaknotch":
this.b0 = 1 + this.alpha*this.A;
this.b1 = -2 * this.cw0;
this.b2 = 1 - this.alpha*this.A;
this.a0 = 1 + this.alpha/this.A;
this.a1 = -2 * this.cw0;
this.a2 = 1 - this.alpha/this.A;
break;
case "lowShelf":
case "lowshelf":
this.b0 = this.A*((this.A+1) - (this.A-1)*this.cw0 + this.soff);
this.b1 = 2*this.A*((this.A-1) - (this.A+1)*this.cw0);
this.b2 = this.A*((this.A+1) - (this.A-1)*this.cw0 - this.soff);
this.a0 = (this.A+1) + (this.A-1)*this.cw0 + this.soff;
this.a1 = -2*((this.A-1) + (this.A+1)*this.cw0);
this.a2 = (this.A+1) + (this.A-1)*this.cw0 - this.soff;
break;
case "highShelf":
case "highshelf":
this.b0 = this.A*((this.A+1) + (this.A-1)*this.cw0 + this.soff);
this.b1 = -2*this.A*((this.A-1) + (this.A+1)*this.cw0);
this.b2 = this.A*((this.A+1) + (this.A-1)*this.cw0 - this.soff);
this.a0 = (this.A+1) - (this.A-1)*this.cw0 + this.soff;
this.a1 = 2*((this.A-1) - (this.A+1)*this.cw0);
this.a2 = (this.A+1) - (this.A-1)*this.cw0 - this.soff;
break;
default: // pass through
this.b0 = 1.;
this.b1 = 0.;
this.b2 = 0.;
this.a0 = 1.;
this.a1 = 0.;
this.a2 = 0.;
break;
}
}
// =============================================================================
// p5.FastFourierTransform
// =============================================================================
/**
* Base class for an FFT (non-signal) module
*
* @class p5.FastFourierTranform
* @constructor
*/
p5.FastFourierTransform = function(_bufsize, _fs, _hopsize) {
//
// this object implements a simple FFT (fast fourier transform)
// module using the 1965 cooley-tukey FFT algorithm:
// http://www.ams.org/journals/mcom/1965-19-090/S0025-5718-1965-0178586-1/S0025-5718-1965-0178586-1.pdf
//
// there's a great breakdown of how the FFT algorithm works here:
// https://www.cs.cmu.edu/afs/andrew/scs/cs/15-463/2001/pub/www/notes/fourier/fourier.pdf
//
// the code below is adapted from the FFT module in dsp.js written by @corbanbrook :
// https://github.com/corbanbrook/dsp.js/
// Copyright (c) 2010 Corban Brook, released under the MIT license
//
// p5.FastFourierTransform runs completely independent of the Web Audio
// framework used by p5.sound / Tone.js, which allows you to analyze
// and synthesize frequency-domain data regardless of whether it counts
// as 'sound' or runs at audio rate.
//
// how many samples are we analyzing?
// should be a power of 2.
this.bufferSize = _bufsize ? _bufsize : 512;
// what's our hopsize?
// if nothing's there, set it to the FFT size.
this.hopSize = _hopsize ? _hopsize : this.bufferSize;
// fourier transforms are 'rate' agnostic...
// the algorithm doesn't care how fast the signal is, so
// the sampling rate here is simply to calculate
// getBandFrequency() as a utility function so we can
// find out, e.g. the center frequency of a specific FFT bin.
this.sampleRate = _fs ? _fs : 60;
// FFT fundamental / bandwidth: used for
// getBandFrequency() and calculateFrequency()
this.bandwidth = this.sampleRate / this.bufferSize;
// data arrays for the raw real/imaginary FFT data.
this.real = new Float64Array(this.bufferSize);
this.imag = new Float64Array(this.bufferSize);
// spectrum compute flag and data arrays for the magnitude / phase.
// note that the spectrum (correctly) only needs a half frame of
// data, as the FFT output is mirrored for bins above nyquist (SR/2).
this.doSpectrum = true;
this.magnitude = new Float64Array(this.bufferSize/2);
this.phase = new Float64Array(this.bufferSize/2);
// compute flag and data arrays for instantaneous frequency estimation
this.doFrequency = false;
this.runningphase = new Float64Array(this.bufferSize/2);
this.previousphase = new Float64Array(this.bufferSize/2);
this.frequency = new Float64Array(this.bufferSize/2);
// the calculateSpectrum() method will stash the 'loudest'
// bin, as well as its value.
this.peakBand = 0; // peak band (FFT bin)
this.peak = 0.; // peak value.
// calculate the FFT 'reverse table'.
// the reverse table is a super groovy hack that helps put the
// 'fast' in fast fourier transform.
//
// to quote jim noxon at texas instruments :
// "The purpose of having this table is due to a quirk of the FFT algorithm.
// As it turns out, the indexing done in the FFT algorithm (and the IFFT too)
// relates the input index to the output index in a manner where reversing
// the bits of the input index creates the appropriate index for the output.
// As you can see the inner for() loop would have to be run for every
// input to output index operation of the FFT algorithm so by creating a table
// up front, the FFT algorithm can be run multiple times and only needs to
// be calculated once. Further, if this table is calculated at compile time,
// then there is no dynamic initialization necessary at all. Now, it is
// simply a look up into the table using the input index to generate the
// output index. Some DSPs have a special addressing mode that does this
// automatically eliminating the need for the table all together."
//
this.reverseTable = new Uint32Array(this.bufferSize);
var limit = 1;
var bit = this.bufferSize >> 1;
var i;
while (limit < this.bufferSize) {
for (i = 0; i < limit; i++) {
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
}
limit = limit << 1;
bit = bit >> 1;
}
// precompute sine and cosine sampling increment (SI) arrays.
this.sinTable = new Float64Array(this.bufferSize);
this.cosTable = new Float64Array(this.bufferSize);
for (i = 0; i < this.bufferSize; i++) {
// we never call index 0, which is NaN
this.sinTable[i] = sin(-PI/i);
this.cosTable[i] = cos(-PI/i);
}
}; // end p5.FastFourierTransform constructor
// query the center frequency of a specific FFT band (e.g. the peakBand).
// remember that this is the frequency of the *filter*, not necessarily
// the signal that is actuating the filter. to find that out you would
// compute running phase off of sequential frames of data to see whether
// the phase in the bin is rising or falling, and use that to compute
// the frequency differential between the band and the actuating signal
// (see below... calculateFrequency(), for an implementation).
p5.FastFourierTransform.prototype.getBandFrequency = function(_index) {
return this.bandwidth * _index;
}
// calculate the spectrum (magnitude / phase) from the cartesian
// (real / imaginary - x / y) raw FFT output. this is basically a
// pythagorean transformation, with the magnitudes scaled to ranges
// based on the FFT size.
p5.FastFourierTransform.prototype.calculateSpectrum = function() {
var rval, ival, mag, phase;
var bSi = 2 / this.bufferSize; // scaling factor for magnitudes
this.peakBand = 0; // reset each spectral frame
this.peak = 0; // reset each spectral frame
for (var i = 0, N = this.bufferSize/2; i < N; i++) {
rval = this.real[i]; // x
ival = this.imag[i]; // y
mag = bSi * sqrt(rval * rval + ival * ival);
phase = atan2(ival, rval);
if (mag > this.peak) {
this.peakBand = i;
this.peak = mag;
}
this.magnitude[i] = mag;
this.phase[i] = phase;
}
if(this.doFrequency) this.calculateFrequency();
}
// computes instantaneous frequency based on running phase.
p5.FastFourierTransform.prototype.calculateFrequency = function() {
var temp = Array.from(this.phase);
this.runningphase = subtractArray(temp, this.previousphase); // compute running phase
this.runningphase = addArray(this.runningphase,TWO_PI+PI);
this.runningphase = moduloArray(this.runningphase, TWO_PI);
this.runningphase = subtractArray(this.runningphase, PI);
this.previousphase = temp;
// compute frequencies:
for(i in this.frequency)
{
this.frequency[i] = this.bandwidth*i + this.runningphase[i]*this.sampleRate/(TWO_PI*this.hopSize);
}
}
// performs a forward FFT transform on a sample buffer.
// this converts the data from the time domain into the frequency domain.
// fills up the real and imag buffers in the object's data structure,
// and also runs calculateSpectrum() to get the magnitude and phase.
p5.FastFourierTransform.prototype.forward = function(_buffer) {
var k = floor(log(this.bufferSize) / Math.LN2);
if (pow(2, k) !== this.bufferSize) { throw "buffer size must be a power of 2."; }
if (this.bufferSize !== _buffer.length) { throw "buffer is not the same size as defined FFT. FFT: " + bufferSize + " buffer: " + buffer.length; }
var halfSize = 1;
var phaseShiftStepReal, phaseShiftStepImag;
var currentPhaseShiftReal, currentPhaseShiftImag;
var tr, ti;
var tmpReal;
var i, o;
// STEP 1 - fill up the 'real' array with the signal according to the reverseTable ordering
// makes it faster for memory access later as it's already copied in there and we can adjustable
// iterate through it.
for (i = 0; i < this.bufferSize; i++) {
this.real[i] = _buffer[this.reverseTable[i]];
this.imag[i] = 0;
}
// STEP 2 - do the actual discrete fourier transform (DFT).
// halfSize will increment in powers of two up to half of the FFT size (nyquist)
// so for a 1024-sample FFT, we're doing 10 outer loops (1, 2, 4, 8, 16, 32, 64, 128, 256, 512).
while (halfSize < this.bufferSize) {
// figure out the phase increment necessary for each sample size
phaseShiftStepReal = this.cosTable[halfSize];
phaseShiftStepImag = this.sinTable[halfSize];
// starting x,y positions
currentPhaseShiftReal = 1;
currentPhaseShiftImag = 0;
// intermediate loop - fftStep will increment from 0 to halfSize-1,
// i.e. number of fftStep loops equals to halfSize each time.
// each one of these passes is a DFT.
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
i = fftStep;
// inner loop - i and o will integrate the convolution of the input signal
// with cosine and sine functions at a period equal to the fftStep
while (i < this.bufferSize) {
o = i + halfSize;
// uncomment the line below to see what's going on:
// console.log('halfSize : ' + halfSize + ', fftStep : ' + fftStep + ', i : ' + i + ', o : ' + o + ', psr : ' + currentPhaseShiftReal + ', psi : ' + currentPhaseShiftImag);
tr = (currentPhaseShiftReal * this.real[o]) - (currentPhaseShiftImag * this.imag[o]);
ti = (currentPhaseShiftReal * this.imag[o]) + (currentPhaseShiftImag * this.real[o]);
this.real[o] = this.real[i] - tr;
this.imag[o] = this.imag[i] - ti;
this.real[i] += tr;
this.imag[i] += ti;
i += halfSize << 1;
}
// increment the sampling interval for the next DFT in the loop:
tmpReal = currentPhaseShiftReal;
currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
}
// shift up halfSize for next outer loop
halfSize = halfSize << 1;
}
if(this.doSpectrum) this.calculateSpectrum(); // calculate mag/phase from real/imag
}
// performs an inverse FFT transform (an IFFT) on either real/imag
// data passed into the function or, if called without arguments,
// the current spectral frame stored in the object.
// this converts the data from the frequency domain into the time domain.
// the function returns a buffer containing the time-domain signal.
p5.FastFourierTransform.prototype.inverse = function(_real, _imag) {
_real = _real || this.real;
_imag = _imag || this.imag;
var halfSize = 1;
var phaseShiftStepReal, phaseShiftStepImag;
var currentPhaseShiftReal, currentPhaseShiftImag;
var off;
var tr, ti;
var tmpReal;
var i;
for (i = 0; i < this.bufferSize; i++) {
_imag[i] *= -1;
}
var revReal = new Float64Array(this.bufferSize);
var revImag = new Float64Array(this.bufferSize);
for (i = 0; i < _real.length; i++) {
revReal[i] = _real[this.reverseTable[i]];
revImag[i] = _imag[this.reverseTable[i]];
}
_real = revReal;
_imag = revImag;
while (halfSize < this.bufferSize) {
phaseShiftStepReal = this.cosTable[halfSize];
phaseShiftStepImag = this.sinTable[halfSize];
currentPhaseShiftReal = 1;
currentPhaseShiftImag = 0;
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
i = fftStep;
while (i < this.bufferSize) {
off = i + halfSize;
tr = (currentPhaseShiftReal * _real[off]) - (currentPhaseShiftImag * _imag[off]);
ti = (currentPhaseShiftReal * _imag[off]) + (currentPhaseShiftImag * _real[off]);
_real[off] = _real[i] - tr;
_imag[off] = _imag[i] - ti;
_real[i] += tr;
_imag[i] += ti;
i += halfSize << 1;
}
tmpReal = currentPhaseShiftReal;
currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
}
halfSize = halfSize << 1;
}
var buffer = new Float64Array(this.bufferSize); // this should be reused instead
for (i = 0; i < this.bufferSize; i++) {
buffer[i] = _real[i] / this.bufferSize;
}
return buffer;
}
// =============================================================================
// Luke's Misc. Utilities (extends p5.js)
// =============================================================================
// constrained integer mapping function (useful for array lookup).
// similar to the Max [zmap] object when used with integers.
// syntactically equivalent to the p5.js / processing map() function.
p5.prototype.imap = function(_x, _a, _b, _c, _d) {
return(constrain(floor(map(_x, _a, _b, _c, _d)), min(_c,_d), max(_c, _d)-1));
}
// number wrapping (courtesy of @pd-l2ork puredata [pong])
p5.prototype.wrap = function(_x, _min, _max) {
_a = min(_min, _max);
_b = max(_min, _max);
var _y;
var _r = _b-_a; // range
if(_x < _b && _x >= _a) { // normal
return(_x);
}
else if(_a==_b) { // catch
return(_a);
}
else {
if(_x < _a) {
_y = _x;
while(_y < _a){
_y += _r;
};
}
else {
_y = ((_x-_a)%_r) + _a;
}
}
return(_y);
}
// number folding (courtesy of @pd-l2ork puredata [pong])
p5.prototype.fold = function(_x, _min, _max) {
_a = min(_min, _max);
_b = max(_min, _max);
var _y;
var _r = _b-_a; // range
if(_x < _b && _x >= _a) { // normal
return(_x);
}
else if(_a==_b) { // catch
return(_a);
}
else {
if(_x < _a) {
var _d = _a - _x; // diff between input and minimum (positive)
var _m = floor(_d/_r); // case where input is more than a range away from minval
if(_m % 2 == 0) { // even number of ranges away = counting up from min
_d = _d - _m*_r;
_y = _d + _a;
}
else { // odd number of ranges away = counting down from max
_d = _d - _m*_r;
_y = _b - _d;
}
}
else { // input > maxval
var _d = _x - _b; // diff between input and max (positive)
var _m = floor(_d/_r); // case where input is more than a range away from maxval
if(_m % 2 == 0) { // even number of ranges away = counting down from max
_d = _d - _m*_r;
_y = _b - _d;
}
else { //odd number of ranges away = counting up from min
_d = _d - _m*_r;
_y = _d + _a;
}
}
}
return(_y);
}
// create n-dimensional arrays
p5.prototype.createArray = function(_len)
{
var _arr = new Array(_len || 0).fill(0),
i = _len;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while(i--) _arr[_len-1 - i] = this.createArray.apply(this, args);
}
return _arr;
}
// normalize a numerical array to absmax=1.0 without shifting DC
p5.prototype.normalizeArray = function(_array) {
var _max = max(max(_array), abs(min(_array)));
return(_array.map(function(_v) { return _v/_max; }));
}
// resize a numerical array to a new size with linear interpolation
p5.prototype.resizeArray = function(_array, _newlen) {
var _out = [];
for(var i = 0;i<_newlen;i++)
{
var aptr = map(i, 0, _newlen-1, 0, _array.length-1);
var a = floor(aptr);
var b = ceil(aptr);
var l = aptr%1.0;
_out[i] = lerp(_array[a], _array[b], l);
}
return(_out);
}
// multiply two arrays
p5.prototype.multiplyArray = function(_a1, _a2) {
if(!Array.isArray(_a2)) _a2 = [_a2]; // allow scalars
var _out = [];
if(_a1.length!=_a2.length) _a2 = resizeArray(_a2, _a1.length);
for(var i = 0;i<_a1.length;i++)
{
_out[i] = _a1[i] * _a2[i];
}
return(_out);
}
// add two arrays
p5.prototype.addArray = function(_a1, _a2) {
if(!Array.isArray(_a2)) _a2 = [_a2]; // allow scalars
var _out = [];
if(_a1.length!=_a2.length) _a2 = resizeArray(_a2, _a1.length);
for(var i = 0;i<_a1.length;i++)
{
_out[i] = _a1[i] + _a2[i];
}
return(_out);
}
// subtract two arrays
p5.prototype.subtractArray = function(_a1, _a2) {
if(!Array.isArray(_a2)) _a2 = [_a2]; // allow scalars
var _out = [];
if(_a1.length!=_a2.length) _a2 = resizeArray(_a2, _a1.length);
for(var i = 0;i<_a1.length;i++)
{
_out[i] = _a1[i] - _a2[i];
}
return(_out);
}
// divide two arrays
p5.prototype.divideArray = function(_a1, _a2) {
if(!Array.isArray(_a2)) _a2 = [_a2]; // allow scalars
var _out = [];
if(_a1.length!=_a2.length) _a2 = resizeArray(_a2, _a1.length);
for(var i = 0;i<_a1.length;i++)
{
_out[i] = _a1[i] / _a2[i];
}
return(_out);
}
// modulo two arrays
p5.prototype.moduloArray = function(_a1, _a2) {
if(!Array.isArray(_a2)) _a2 = [_a2]; // allow scalars
var _out = [];
if(_a1.length!=_a2.length) _a2 = resizeArray(_a2, _a1.length);
for(var i = 0;i<_a1.length;i++)
{
_out[i] = _a1[i] % _a2[i];
}
return(_out);
}
// return the sum of an array
p5.prototype.sumArray = function(_a) {
var _s = _a.reduce(function(_acc, _val) {
return(_acc+_val);
});
return(_s);
}
// Java Float.floatToIntBits() IEEE 754 / 32-bit (h/t @mattdesl):
p5.prototype.f2ib = function(_x)
{
var int8 = new Int8Array(4);
var int32 = new Int32Array(int8.buffer, 0, 1);
var float32 = new Float32Array(int8.buffer, 0, 1);
float32[0] = _x;
return(int32[0]);
}
// Java Float.intBitstoFloat() IEEE 754 / 32-bit (h/t @mattdesl):
p5.prototype.ib2f = function(_x)
{
var int8 = new Int8Array(4);
var int32 = new Int32Array(int8.buffer, 0, 1);
var float32 = new Float32Array(int8.buffer, 0, 1);
int32[0] = _x;
return(float32[0]);
}
// normalized sinc function (integral equals 1, not PI)
// the normalized sinc is the FT of the rectangular function.
// 'sinc' is short for sinus cardinalis (woodward '52):
// http://www.norbertwiener.umd.edu/crowds/documents/Woodward52.pdf
p5.prototype.sinc = function(_x) {
return(sin(PI*_x)/(PI*_x));
}
// besselI0 - regular modified cylindrical Bessel function (Bessel I)
// https://en.wikipedia.org/wiki/Bessel_function
// ported from kbdwindow.cpp by craig stuart sapp @ CCRMA ca. 2001
p5.prototype.besselI0 = function(_x) {
var denominator;
var numerator;
var z;
if (_x == 0.0) {
return(1.0);
} else {
z = _x * _x;
numerator = (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z*
(z* 0.210580722890567e-22 + 0.380715242345326e-19 ) +
0.479440257548300e-16) + 0.435125971262668e-13 ) +
0.300931127112960e-10) + 0.160224679395361e-7 ) +
0.654858370096785e-5) + 0.202591084143397e-2 ) +
0.463076284721000e0) + 0.754337328948189e2 ) +
0.830792541809429e4) + 0.571661130563785e6 ) +
0.216415572361227e8) + 0.356644482244025e9 ) +
0.144048298227235e10);
denominator = (z*(z*(z-0.307646912682801e4)+
0.347626332405882e7)-0.144048298227235e10);
}
return(-numerator/denominator);
}
// plot an array to the console as if it were a VT100 terminal.
// ported from a copy of fplot.c found on luke's NeXTstation.
// fplot.c seems rewritten from FORTRAN, presumably by
// paul lansky, while porting MIX to C in 83/84.
// man page last troff'ed january 31, 1987, 6:56PM by paul lansky.
// c code last modified october 18, 1990, 2:26PM by brad garton.
p5.prototype.fplot = function(_array, _css) {
var a;
if(!Array.isArray(_array)) a = [_array]; // single value
if(Array.isArray(_array)) a = _array; // normal array
if(_array.constructor == Float32Array) a = Array.prototype.slice.call(_array);
if(_array.constructor == Float64Array) a = Array.prototype.slice.call(_array);
var TERMWIDTH = 80; // columns (1 additional will be used for left margin)
var TERMHEIGHT = 23; // VT100 is 24 rows ('take back one kadam...')
var out = [];
var si, phase;
var i, j, k, len, wave;
var line = '';
len = _array.length;
// decimate or interpolate array to TERMWIDTH values, scale to absmax=1.
out = resizeArray(a, TERMWIDTH);
out = normalizeArray(out);
// plot the fucker
si = 1./((TERMHEIGHT-1)/2.);
phase = 1.;
for(i = 0; i < TERMHEIGHT; i++) {
k = 0;
// add alternator to left margin of line - prevents browser consoles
// from interpreting duplicate lines and only printing them once:
if(i%2) line= '~'; else line='|';
// format line based on function being within phase boundary
for(j = 0; j < TERMWIDTH-1; j++) {
if(isNaN(out[j])) out[j] = 0; // filter out garbage
if((out[j]>=phase) && (out[j]<phase+si)) {
line+= (out[j+1] > phase+si) ? '/' : '-';
if(out[j+1] < phase) line+= '\\';
k = j;
}
else if (((out[j]<phase)&&(out[j+1]>phase+si)) ||
((out[j]>phase+si)&&(out[j+1]<phase))) {
line+= '|';
k = j;
}
else line+= ' '; // function isn't within range... fill with space
}
// center line
if ((0>=phase) && (0<phase+si)) {
line = '~'; // alternator
for(j = 0; j < TERMWIDTH; j++) line+= '-';
k = TERMWIDTH-2;
}
console.log('%c'+line, _css); // print, including CSS
phase-= si; // decrement phase
}
return(0);
}
}));
/*
todo:
*/
// EOF
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment