package shapes; import java.util.ArrayList; import processing.core.PApplet; import mekstension.Mekstension; import toxi.color.TColor; import toxi.geom.Vec3D; import toxi.math.noise.SimplexNoise; public class Shape { protected Mekstension p; public String label; private int id; private float inc = 0; // color, draw style public TColor fg, bg, stroke; public boolean enableFill = true; public boolean enableStroke = true; public float strokeWeight = 2; // position, shape private Vec3D pos, dest; private float objScale = 0; public float scale = 50, destScale = 50; public float depth = -500, destDepth = -500; public float angle = 0, destAngle = 0; public float rot = 0, destRot = 0; public float zScale = 1, destZScale = 0; // mesh ArrayList> shapeSegments = new ArrayList>(); ArrayList segments = new ArrayList (); final public static int MAX_SIDES = 64; final public static int MAX_SEGMENTS = 1000; public int numSegments = 20; public int sides = 4; // animation private boolean lerpVars = true; private float lerpSpeed = 0.15f; private float noiseOffset = 0; public float modX = 0.5f, modXFreq = 1f, destModXFreq = 0.05f, ampx = 100f, destxAmp = 100f; public float modY = 0.5f, modYFreq = 1f, destModYFreq = 0.05f, ampy = 100f, destyAmp = 100f; /** * Constructor * * @param p_ Parent Mekstension class. Extended from PApplet * @param sides_ Number of sides * @param label_ Label * @see PApplet */ public Shape(Mekstension p_, int sides_, String label_, int id_) { p = p_; id = id_; label = label_; pos = new Vec3D(p.width / 2, p.height / 2, 0); dest = new Vec3D(pos); sides = sides_; setSegments(numSegments); } /** * update mesh */ private void updateMesh() { inc = (float) (2 * Math.PI) / sides; shapeSegments.clear(); for ( int j = 1; j <= numSegments; j++ ) { ArrayList seg = new ArrayList(); float depthMul = PApplet.map(j, 1, numSegments, 0, 1); for ( int k = 0; k < sides; k ++ ) { float x = (float) ( scale * Math.cos( inc * k + rot ) + ( depth * depthMul ) * Math.cos( angle ) ); float y = (float) ( scale * Math.sin( inc * k + rot ) + ( depth * depthMul ) * Math.sin( angle ) ); float z = depth * depthMul; seg.add(new Vec3D(x, y, z)); } shapeSegments.add( seg ); } } /** * Update Loop */ public void update() { objScale = PApplet.lerp(objScale, 1.0f, lerpSpeed); if( lerpVars ) { pos.x = PApplet.lerp(pos.x, dest.x, lerpSpeed); pos.y = PApplet.lerp(pos.y, dest.y, lerpSpeed); pos.z = PApplet.lerp(pos.z, dest.z, lerpSpeed); depth = PApplet.lerp(depth, destDepth, lerpSpeed); angle = PApplet.lerp(angle, destAngle, lerpSpeed); rot = PApplet.lerp(rot, destRot, lerpSpeed); zScale = PApplet.lerp(zScale, destZScale, lerpSpeed); scale = PApplet.lerp(scale, destScale, lerpSpeed); ampx = PApplet.lerp(ampx, destxAmp, lerpSpeed); modXFreq = PApplet.lerp(ampx, destModXFreq, lerpSpeed); ampy = PApplet.lerp(ampy, destyAmp, lerpSpeed); modYFreq = PApplet.lerp(ampy, destModYFreq, lerpSpeed); } else { pos.x = dest.x; pos.y = dest.y; pos.z = dest.z; depth = destDepth; angle = destAngle; rot = destRot; zScale = destZScale; scale = destScale; ampx = destxAmp; modXFreq = destModXFreq; ampy = destyAmp; modYFreq = destModYFreq; } updateSegments(); updateMesh(); } /** * Draw loop */ public void draw() { p.pushMatrix(); p.translate(pos.x, pos.y, pos.z); p.scale(objScale, objScale, zScale); drawSegments(); //drawMesh(); p.popMatrix(); } /** * update segments with 3D noisefield */ private void updateSegments() { Vec3D change = new Vec3D(); float freq = 100f; float NS = 0.1f; for ( int i = 1; i < segments.size(); i++) { float noiseValX = (float) SimplexNoise.noise(NS + noiseOffset + (-1 * i), NS + noiseOffset + (-1 * i)); float noiseValY = (float) SimplexNoise.noise(NS + noiseOffset + 100 + (-1 * i), NS + noiseOffset + 100 + (-1 * i)); float scalar = i * 0.1f; change.x = (float) ( noiseValX * ampx * scalar ); change.y = (float) ( noiseValY * ampy * scalar ); Vec3D seg = segments.get(i); Vec3D pseg = new Vec3D(segments.get(i - 1)); pseg.z = ( depth / numSegments ) * i; seg.addSelf( change ); seg.interpolateToSelf( pseg, 0.8f ); } noiseOffset += NS / freq; } /** * draw mesh */ void drawMesh() { p.stroke(stroke.toARGB()); if(enableStroke && stroke.alpha > 0) p.strokeWeight( strokeWeight ); else p.noStroke(); p.beginShape(PApplet.QUAD_STRIP); for( int j = 1; j < numSegments; j++) { TColor c1 = new TColor(fg); TColor c2 = new TColor(bg); float colMul1 = PApplet.map(j, 1, numSegments, 0, 1); float colMul2 = PApplet.map(j, 0, numSegments - 1, 1, 0); c1.blend( bg, colMul1 ); c2.blend( fg, colMul2 ); ArrayList seg = shapeSegments.get(j); ArrayList seg2 = shapeSegments.get(j - 1); for ( int i = 0; i < seg.size(); i++ ) { Vec3D v = (Vec3D) seg.get(i); Vec3D v2 = (Vec3D) seg2.get(i); p.fill(c2.toARGB()); p.vertex(v.x, v.y, v.z); p.fill(c1.toARGB()); p.vertex(v2.x, v2.y, v2.z); if(i == seg.size() - 1) { v = (Vec3D) seg.get(0); v2 = (Vec3D) seg2.get(0); p.fill(c2.toARGB()); p.vertex(v.x, v.y, v.z); p.fill(c1.toARGB()); p.vertex(v2.x, v2.y, v2.z); } } } p.endShape(PApplet.CLOSE); } /** * draw all segments * @param segs the segment vectors */ void drawSegments() { p.strokeWeight(5); p.stroke(255,0,255); p.fill(255, 0, 0); p.ellipse(0, 0, 10, 10); p.beginShape(PApplet.LINES); p.vertex(0, 0, 0); p.vertex(segments.get(1).x, segments.get(1).y, segments.get(1).z); for ( int i = 1; i < numSegments; i++) { // color blending TColor c1 = new TColor(fg); TColor c2 = new TColor(bg); float colMul1 = PApplet.map(i, 1, numSegments, 0, 1); float colMul2 = PApplet.map(i, 0, numSegments - 1, 1, 0); c1.blend( bg, colMul1 ); c2.blend( fg, colMul2 ); Vec3D s = segments.get( i ); Vec3D prev = segments.get( i - 1 ); p.fill(c1.toARGB()); p.stroke(c1.toARGB()); p.vertex(s.x, s.y, s.z); p.fill(c2.toARGB()); p.stroke(c2.toARGB()); p.vertex(prev.x, prev.y, prev.z); } p.endShape(); } /** * set number of segments * @param segments number of segments */ public void setSegments ( int segments_ ) { numSegments = PApplet.constrain(segments_, 2, Shape.MAX_SEGMENTS); segments.clear(); for ( int i = 0; i < numSegments; i++) segments.add(new Vec3D( 0, 0, ( depth / numSegments ) * i )); } /** * set zscale, which simulates focal length * @param zScale z scale */ public void setZScale(float zScale_) { destZScale = zScale_; } /** * set new shape depth, and build new mesh * @param depth_ depth */ public void setDepth(float depth_) { destDepth = depth_; } /** * set shape rotation * @param newRot the rotation amount */ public void setRot(float rot_) { destRot = rot_; } /** * the new position * @param newX x position * @param newY y position */ public void setPos(float x_, float y_, float z_) { dest.x = x_; dest.y = y_; dest.z = z_; } /** * get position * @return */ public Vec3D getPos() { return dest; } /** * add side */ public void addSide() { sides = sides < Shape.MAX_SIDES ? sides += 1 : Shape.MAX_SIDES; } /** * subtract side */ public void subtractSide() { sides = sides > 2 ? sides -= 1 : 2; } /** * set shape scale * @param scale_ new scale */ public void setScale(float scale_) { destScale = scale_; } /** * set mod x freq * @param freq_ */ public void setModFreqX(float freq_) { destModXFreq = freq_; } /** * set mod y freq * @param freq_ */ public void setModFreqY(float freq_) { destModYFreq = freq_; } /** * set mod x amp * @param amp_ */ public void setModAmpX(float amp_) { destxAmp = amp_; } /** * set mod Y amp * @param amp_ */ public void setModAmpY(float amp_) { destyAmp = amp_; } /** * Set angle * @param ang the angle in Radians */ public void setAngle(float ang) { destAngle = ang; } /** * set overall alpha */ public void setAlpha (float alpha_) { fg.alpha = alpha_; bg.alpha = alpha_; stroke.alpha = alpha_; } /** * get id * @return the id */ public int getID() { return id; } }