PS1 MDDN 342 2016
A clone of an early experiment of PS1.
Generate template faces then draw on top using the mouse.
Middle mouse -> to add a new face at the current mouse position. Left click -> draw lines SPACE -> clear current drawing
| license: mit |
| // note: this file is poorly named - it can generally be ignored. | |
| // helper functions below for supporting blocks/purview | |
| function saveBlocksImages() { | |
| // generate 960x500 preview.jpg of entire canvas | |
| // TODO: should this be recycled? | |
| var offscreenCanvas = document.createElement('canvas'); | |
| offscreenCanvas.width = 960; | |
| offscreenCanvas.height = 500; | |
| var context = offscreenCanvas.getContext('2d'); | |
| // background is flat white | |
| context.fillStyle="#FFFFFF"; | |
| context.fillRect(0, 0, 960, 500); | |
| context.drawImage(this.canvas, 0, 0, 960, 500); | |
| // save to browser | |
| var downloadMime = 'image/octet-stream'; | |
| var imageData = offscreenCanvas.toDataURL('image/jpeg'); | |
| imageData = imageData.replace('image/jpeg', downloadMime); | |
| p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg'); | |
| // generate 230x120 thumbnail.png centered on mouse | |
| offscreenCanvas.width = 230; | |
| offscreenCanvas.height = 120; | |
| // background is flat white | |
| context = offscreenCanvas.getContext('2d'); | |
| context.fillStyle="#FFFFFF"; | |
| context.fillRect(0, 0, 230, 120); | |
| // pixelDensity does the right thing on retina displays | |
| var pd = this._pixelDensity; | |
| var sx = pd * mouseX - pd * 230/2; | |
| var sy = pd * mouseY - pd * 120/2; | |
| var sw = pd * 230; | |
| var sh = pd * 120; | |
| // bounds checking - just displace if necessary | |
| if (sx < 0) { | |
| sx = 0; | |
| } | |
| if (sx > this.canvas.width - sw) { | |
| sx = this.canvas.width - sw; | |
| } | |
| if (sy < 0) { | |
| sy = 0; | |
| } | |
| if (sy > this.canvas.height - sh) { | |
| sy = this.canvas.height - sh; | |
| } | |
| // save to browser | |
| context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120); | |
| imageData = offscreenCanvas.toDataURL('image/png'); | |
| imageData = imageData.replace('image/png', downloadMime); | |
| p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png'); | |
| } |
| <head> | |
| <script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.1/p5.js"></script> | |
| <script language="javascript" type="text/javascript" src="readme.purview_helper.js"></script> | |
| <script language="javascript" type="text/javascript" src="sketch.js"></script> | |
| <style> body {padding: 0; margin: 0;} </style> | |
| </head> | |
| <body style="background-color:white"> | |
| </body> |
| var WIDTH = 960, | |
| HEIGHT = 500; | |
| var colors; | |
| var currentColor; | |
| var faces = []; | |
| //parts | |
| //var myEye; | |
| function setup () { | |
| //initialise global variables | |
| colors = { | |
| green: color(78, 255, 156), | |
| blue: color(65, 253, 255), | |
| black: color(0) | |
| }; | |
| currentColor = colors.black; | |
| //myEye = eye("left",1,2); | |
| createCanvas(WIDTH, HEIGHT); | |
| //cover the background | |
| fill(0); | |
| rect(0,0,WIDTH,HEIGHT); | |
| stroke(255); | |
| faces.push(createFace(createVector(WIDTH / 2, HEIGHT / 2), createVector(175, 250), color(255), random(0, 1))); | |
| } | |
| var SIZE = 80; | |
| var time = 0; | |
| var lastMouseX; | |
| var lastMouseY; | |
| var centerPressed = false; | |
| function draw() { | |
| var funkAmt = mouseX / WIDTH; | |
| var pos = createVector(mouseX, mouseY); | |
| //draw things on top | |
| if(mouseIsPressed){ | |
| if(mouseButton == LEFT){ | |
| if(lastMouseX != 0 || lastMouseY != 0){ | |
| line(lastMouseX,lastMouseY,mouseX,mouseY); | |
| } | |
| lastMouseX = mouseX; | |
| lastMouseY = mouseY; | |
| } | |
| if(mouseButton == CENTER){ | |
| if(!centerPressed){ | |
| var f = createFace(createVector(mouseX, mouseY), createVector(175, 250), color(255), random(0, 1)); | |
| faces.push(f); | |
| centerPressed = true; | |
| } | |
| } | |
| } else { | |
| lastMouseX = lastMouseY = 0; | |
| centerPressed = false; | |
| } | |
| //draw faces | |
| faces.forEach(function(elem){ | |
| if(!elem.isDrawn){ | |
| elem.draw(); | |
| elem.isDrawn = true; | |
| } | |
| }); | |
| } | |
| function keyTyped() { | |
| if (key == '!') { | |
| saveBlocksImages(); | |
| } else if (key == '1'){ | |
| currentColor = color.black; | |
| } else if (key == '2'){ | |
| currentColor = color.blue; | |
| } else if (key == '3'){ | |
| currentColor = color.green; | |
| } else if (key == ' '){ | |
| rect(0,0,WIDTH,HEIGHT); | |
| faces = []; | |
| } | |
| } | |
| function createFace(position, dimensions, colour, featureOffset){ | |
| featureOffset = constrain(featureOffset,0,1.0); | |
| var faceSize = (dimensions.x + dimensions.y) / 2; | |
| //new face object | |
| var f = { | |
| pos: position, | |
| dims: dimensions, | |
| mouthPos: {}, | |
| mouthDims: {}, | |
| lEyePos: {}, | |
| lEyeDims: {}, | |
| rEyePos: {}, | |
| rEyeDims: {}, | |
| nosePos: {}, | |
| noseDims: {}, | |
| col: colour, | |
| funk: random(), | |
| draw : "drawfunction" | |
| }; | |
| //calculate mouth positions | |
| var mX = position.x + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| var mY = position.y + (dimensions.y / 3) + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| f.mouthPos = createVector(mX, mY); | |
| f.mouthDims = createVector(faceSize/5, faceSize/15); | |
| //calculate eye positions | |
| var lEX = position.x - (dimensions.x / 5) + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| var lEY = position.y - (dimensions.y / 7) + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| f.lEyePos = createVector(lEX, lEY); | |
| f.lEyeDims = createVector(faceSize/8, faceSize/15); | |
| //r eye | |
| var rEX = position.x + (dimensions.x / 5) + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| var rEY = position.y - (dimensions.y / 7) + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| f.rEyePos = createVector(rEX, rEY); | |
| f.rEyeDims = createVector(faceSize/8, faceSize/15); | |
| //nose | |
| var nX = position.x + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| var nY = position.y + (featureOffset * random(-1,1) * (faceSize / 10)); | |
| f.nosePos = createVector(nX, nY); | |
| f.noseDims = createVector(faceSize/8 + random(-1,1) * (faceSize/30), faceSize/8 + random(-1,1) * (faceSize/30)); | |
| f.draw = function(){ | |
| // head | |
| sketchyEllipse( | |
| this.pos.x, | |
| this.pos.y, | |
| this.dims.x, | |
| this.dims.y, | |
| this.funk | |
| ); | |
| // mouth | |
| sketchyEllipse( | |
| this.mouthPos.x, | |
| this.mouthPos.y, | |
| this.mouthDims.x, | |
| this.mouthDims.y, | |
| this.funk | |
| ); | |
| // left eye | |
| sketchyEllipse( | |
| this.lEyePos.x, | |
| this.lEyePos.y, | |
| this.lEyeDims.x, | |
| this.lEyeDims.y, | |
| this.funk | |
| ); | |
| // right eye | |
| sketchyEllipse( | |
| this.rEyePos.x, | |
| this.rEyePos.y, | |
| this.rEyeDims.x, | |
| this.rEyeDims.y, | |
| this.funk | |
| ); | |
| //nose | |
| sketchyEllipse( | |
| this.nosePos.x, | |
| this.nosePos.y, | |
| this.noseDims.x, | |
| this.noseDims.y, | |
| this.funk | |
| ); | |
| }; | |
| return f; | |
| } | |
| function sketchyEllipse(xOrig, yOrig, wid, hei, funkAmt){ | |
| wid = wid * 0.5; | |
| hei = hei * 0.5; | |
| //noise seed based on position | |
| noiseSeed(funkAmt*20); | |
| //set the max funkyness of the ellipse based on size & funk amt | |
| var avgSizeOffset = ((wid + hei) * (constrain(funkAmt, 0, 1.0) * 0.5)); | |
| var numPoints = 50; | |
| var x = xOrig + sin(0) * (wid + (noise(0) - 0.5) * avgSizeOffset); | |
| var y = yOrig + cos(0) * (hei + (noise(0) - 0.5) * avgSizeOffset); | |
| var originalX = x, | |
| originalY = y; | |
| for(var i = 0; i < numPoints; i++){ | |
| var amt = (i/numPoints) * TWO_PI; | |
| var noiseAmt = noise(amt) - 0.5; | |
| var nextX = xOrig + sin(amt) * (wid + noiseAmt * avgSizeOffset); | |
| var nextY = yOrig + cos(amt) * (hei + noiseAmt * avgSizeOffset); | |
| line(x, y, nextX, nextY); | |
| x = nextX; | |
| y = nextY; | |
| } | |
| //join the start and end | |
| line(x, y, (originalX + x) * 0.5, (originalY + y) * 0.5); | |
| line((originalX + x) * 0.5,(originalY + y) * 0.5, originalX, originalY); | |
| } | |
| /*Maps values 0 -> 1 to 0 -> 1 -> 0 in a zigzag pattern*/ | |
| function saw(val){ | |
| val = abs(val) % 1.0; | |
| val = val * 2; | |
| if(val > 1.0){ | |
| val = 2.0 - val; | |
| } | |
| console.log(val); | |
| return val; | |
| } |