From 2eb7188d14855ee1d943ed764132e34b9d4a42dd Mon Sep 17 00:00:00 2001 From: Yong Bakos Date: Fri, 1 Mar 2013 13:07:11 -0700 Subject: [PATCH 01/25] Adding javadoc for randomGaussian. References processing/processing-web#42 --- core/src/processing/core/PApplet.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 4d2b3e4bc..8918f8723 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -5185,7 +5185,23 @@ public class PApplet extends Applet return value; } - + /** + * ( begin auto-generated from randomGaussian.xml ) + * + * Returns a float from a random series of numbers having a mean of 0 + * and standard deviation of 1. Each time the randomGaussian() + * function is called, it returns a number fitting a Gaussian, or + * normal, distribution. There is theoretically no minimum or maximum + * value that randomGaussian() might return. Rather, there is + * just a very low probability that values far from the mean will be + * returned; and a higher probability that numbers near the mean will + * be returned. + * + * ( end auto-generated ) + * @webref math:random + * @see PApplet#random(float,float) + * @see PApplet#noise(float, float, float) + */ public final float randomGaussian() { if (internalRandom == null) { internalRandom = new Random(); From 6b5eb6ae5584823329437ccc64dd8e46814e14cb Mon Sep 17 00:00:00 2001 From: Casey Reas Date: Tue, 5 Mar 2013 10:42:50 -0800 Subject: [PATCH 02/25] New keywords for next release --- java/keywords.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/keywords.txt b/java/keywords.txt index d8a124018..7710ab920 100644 --- a/java/keywords.txt +++ b/java/keywords.txt @@ -158,6 +158,7 @@ SUBTRACT LITERAL2 blend_ SVIDEO LITERAL2 TAB LITERAL2 keyCode TARGA LITERAL2 +TAU LITERAL2 TAU TEXT LITERAL2 cursor_ TFF LITERAL2 THIRD_PI LITERAL2 @@ -530,7 +531,6 @@ beginDraw FUNCTION2 PGraphics_beginDraw_ endDraw FUNCTION2 PGraphics_endDraw_ PI LITERAL2 PI PImage KEYWORD5 PImage -alpha FUNCTION2 PImage_alpha_ blend FUNCTION2 PImage_blend_ copy FUNCTION2 PImage_copy_ filter FUNCTION2 PImage_filter_ @@ -563,7 +563,7 @@ beginContour FUNCTION2 PShape_beginContour_ disableStyle FUNCTION2 PShape_disableStyle_ enableStyle FUNCTION2 PShape_enableStyle_ endContour FUNCTION2 PShape_endContour_ -end FUNCTION2 PShape_endShape_ +endShape FUNCTION2 PShape_endShape_ getChild FUNCTION2 PShape_getChild_ getVertex FUNCTION2 PShape_getVertex_ getVertexCount FUNCTION2 PShape_getVertexCount_ @@ -608,6 +608,7 @@ quadraticVertex FUNCTION1 quadraticVertex_ QUARTER_PI LITERAL2 QUARTER_PI radians FUNCTION1 radians_ random FUNCTION1 random_ +randomGaussian FUNCTION1 randomGaussian_ randomSeed FUNCTION1 randomSeed_ rect FUNCTION1 rect_ rectMode FUNCTION1 rectMode_ @@ -667,6 +668,7 @@ strokeWeight FUNCTION1 strokeWeight_ subset FUNCTION1 subset_ Table KEYWORD5 Table tan FUNCTION1 tan_ +TAU LITERAL2 TAU text FUNCTION1 text_ textAlign FUNCTION1 textAlign_ textAscent FUNCTION1 textAscent_ From 1ee4d922e3f01d317085e438657dc839edc51ec7 Mon Sep 17 00:00:00 2001 From: Casey Reas Date: Tue, 5 Mar 2013 12:53:13 -0800 Subject: [PATCH 03/25] Updates for video capture examples, new keywords.txt --- java/keywords.txt | 2 +- .../Capture/AsciiVideo/AsciiVideo.pde | 8 ++++-- .../BackgroundSubtraction.pde | 14 +++++++--- .../BrightnessThresholding.pde | 9 +++++-- .../Capture/ColorSorting/ColorSorting.pde | 9 ++++--- .../FrameDifferencing/FrameDifferencing.pde | 9 +++++-- .../Capture/Framingham/Framingham.pde | 8 +++--- .../GettingStartedCapture.pde | 27 ++++++++++++------- .../examples/Capture/HsvSpace/HsvSpace.pde | 13 ++++++--- .../examples/Capture/LivePocky/LivePocky.pde | 7 +++-- .../video/examples/Capture/Mirror/Mirror.pde | 10 +++---- .../examples/Capture/Mirror2/Mirror2.pde | 7 +++-- .../Capture/RadialPocky/RadialPocky.pde | 12 ++++++--- .../examples/Capture/SlitScan/SlitScan.pde | 11 +++++--- .../Capture/Spatiotemporal/Spatiotemporal.pde | 9 +++++-- .../TimeDisplacement/TimeDisplacement.pde | 25 ++++++++++------- 16 files changed, 122 insertions(+), 58 deletions(-) diff --git a/java/keywords.txt b/java/keywords.txt index 7710ab920..4cf38720c 100644 --- a/java/keywords.txt +++ b/java/keywords.txt @@ -526,7 +526,7 @@ parseXML FUNCTION1 parseXML_ perspective FUNCTION1 perspective_ PFont KEYWORD5 PFont list FUNCTION1 PFont_list_ -PGraphics FUNCTION1 PGraphics_ +PGraphics KEYWORD5 PGraphics beginDraw FUNCTION2 PGraphics_beginDraw_ endDraw FUNCTION2 PGraphics_endDraw_ PI LITERAL2 PI diff --git a/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde b/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde index b332e59e3..01188fa0b 100644 --- a/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde +++ b/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde @@ -29,11 +29,15 @@ float fontSize = 1.5; void setup() { size(640, 480, P2D); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 160, 120); + + // Start capturing the images from the camera video.start(); + int count = video.width * video.height; - println(count); + //println(count); font = loadFont("UniversLTStd-Light-48.vlw"); diff --git a/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde b/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde index 859a6af63..dfcedd525 100644 --- a/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde +++ b/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde @@ -15,9 +15,15 @@ Capture video; void setup() { size(640, 480, P2D); - // Uses the default video input, see the reference if this causes an error + + // This the default video input, see the GettingStartedCapture + // example if it creates an error + video = new Capture(this, 160, 120); video = new Capture(this, width, height); + + // Start capturing the images from the camera video.start(); + numPixels = video.width * video.height; // Create array to store the background image backgroundPixels = new int[numPixels]; @@ -36,11 +42,11 @@ void draw() { // of the background in that spot color currColor = video.pixels[i]; color bkgdColor = backgroundPixels[i]; - // Extract the red, green, and blue components of the current pixel�s color + // Extract the red, green, and blue components of the current pixel's color int currR = (currColor >> 16) & 0xFF; int currG = (currColor >> 8) & 0xFF; int currB = currColor & 0xFF; - // Extract the red, green, and blue components of the background pixel�s color + // Extract the red, green, and blue components of the background pixel's color int bkgdR = (bkgdColor >> 16) & 0xFF; int bkgdG = (bkgdColor >> 8) & 0xFF; int bkgdB = bkgdColor & 0xFF; @@ -61,7 +67,7 @@ void draw() { } // When a key is pressed, capture the background image into the backgroundPixels -// buffer, by copying each of the current frame�s pixels into it. +// buffer, by copying each of the current frame's pixels into it. void keyPressed() { video.loadPixels(); arraycopy(video.pixels, backgroundPixels); diff --git a/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde b/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde index 0de1b4f98..f2ee1a0bc 100644 --- a/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde +++ b/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde @@ -17,9 +17,14 @@ Capture video; void setup() { size(640, 480, P2D); // Change size to 320 x 240 if too slow at 640 x 480 strokeWeight(5); - // Uses the default video input, see the reference if this causes an error + + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, width, height); - video.start(); + + // Start capturing the images from the camera + video.start(); + numPixels = video.width * video.height; noCursor(); smooth(); diff --git a/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde b/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde index f84e63571..34be988ba 100644 --- a/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde +++ b/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde @@ -19,13 +19,14 @@ int[] bright; // How many pixels to skip in either direction int increment = 5; - void setup() { size(800, 600, P2D); - - noCursor(); - // Uses the default video input, see the reference if this causes an error + + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 160, 120); + + // Start capturing the images from the camera video.start(); int count = (video.width * video.height) / (increment * increment); diff --git a/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde b/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde index e85dc4a9b..0350ab080 100644 --- a/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde +++ b/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde @@ -14,9 +14,14 @@ Capture video; void setup() { size(640, 480, P2D); - // Uses the default video input, see the reference if this causes an error + + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, width, height); - video.start(); + + // Start capturing the images from the camera + video.start(); + numPixels = video.width * video.height; // Create an array to store the previously captured frame previousFrame = new int[numPixels]; diff --git a/java/libraries/video/examples/Capture/Framingham/Framingham.pde b/java/libraries/video/examples/Capture/Framingham/Framingham.pde index a53b94321..8fcb8b1e8 100644 --- a/java/libraries/video/examples/Capture/Framingham/Framingham.pde +++ b/java/libraries/video/examples/Capture/Framingham/Framingham.pde @@ -20,10 +20,12 @@ int[] scoot; void setup() { size(640, 480, P2D); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 160, 120); - video.start(); - // Also try with other video sizes + + // Start capturing the images from the camera + video.start(); column = 0; columnCount = width / video.width; diff --git a/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde b/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde index 9d5c2a1c8..22012c7b4 100644 --- a/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde +++ b/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde @@ -2,8 +2,8 @@ * Getting Started with Capture. * * Reading and displaying an image from an attached Capture device. - */ - + */ + import processing.video.*; Capture cam; @@ -12,21 +12,26 @@ void setup() { size(640, 480, P2D); String[] cameras = Capture.list(); - + if (cameras.length == 0) { println("There are no cameras available for capture."); exit(); - } else { + } + else { println("Available cameras:"); for (int i = 0; i < cameras.length; i++) { println(cameras[i]); } - + // The camera can be initialized directly using an element // from the array returned by list(): cam = new Capture(this, cameras[0]); - cam.start(); - } + // Or, the settings can be defined based on the text in the list + //cam = new Capture(this, 640, 480, "Built-in iSight", 30); + + // Start capturing the images from the camera + cam.start(); + } } void draw() { @@ -34,7 +39,9 @@ void draw() { cam.read(); } image(cam, 0, 0); - // The following does the same, and is faster when just drawing the image - // without any additional resizing, transformations, or tint. + // The following does the same as the above image() line, but + // is faster when just drawing the image without any additional + // resizing, transformations, or tint. //set(0, 0, cam); -} \ No newline at end of file +} + diff --git a/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde b/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde index 9faf65dcd..9f72fe96f 100644 --- a/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde +++ b/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde @@ -37,8 +37,13 @@ boolean blobby = false; void setup() { size(640, 480, P3D); + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 160, 120); - video.start(); + + // Start capturing the images from the camera + video.start(); + count = video.width * video.height; sphereDetail(60); @@ -63,8 +68,10 @@ void setup() { void draw() { background(0); - if (!blobby) lights(); - + if (!blobby) { + lights(); + } + pushMatrix(); translate(width/2, height/2); scale(min(width, height) / 10.0); diff --git a/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde b/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde index 1e6395419..3425caad8 100644 --- a/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde +++ b/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde @@ -18,9 +18,12 @@ int buffer[]; void setup() { size(600, 400, P2D); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 320, 240); - video.start(); + + // Start capturing the images from the camera + video.start(); maxRows = height * 2; buffer = new int[width * maxRows]; diff --git a/java/libraries/video/examples/Capture/Mirror/Mirror.pde b/java/libraries/video/examples/Capture/Mirror/Mirror.pde index 5ef7520a2..abd69f7f9 100644 --- a/java/libraries/video/examples/Capture/Mirror/Mirror.pde +++ b/java/libraries/video/examples/Capture/Mirror/Mirror.pde @@ -23,9 +23,12 @@ void setup() { rows = height / cellSize; colorMode(RGB, 255, 255, 255, 100); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, width, height); - video.start(); + + // Start capturing the images from the camera + video.start(); background(0); } @@ -35,9 +38,6 @@ void draw() { if (video.available()) { video.read(); video.loadPixels(); - - // Not bothering to clear background - // background(0); // Begin loop for columns for (int i = 0; i < cols; i++) { diff --git a/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde b/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde index 4c565fa2b..da415c8c1 100644 --- a/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde +++ b/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde @@ -23,9 +23,12 @@ void setup() { colorMode(RGB, 255, 255, 255, 100); rectMode(CENTER); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, width, height); - video.start(); + + // Start capturing the images from the camera + video.start(); background(0); } diff --git a/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde b/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde index a4e640204..df41a9065 100644 --- a/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde +++ b/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde @@ -21,9 +21,13 @@ void setup() { // size must be set to video.width*video.height*2 in both directions size(600, 600, P2D); - // Uses the default video input, see the reference if this causes an error + // This the default video input, see the GettingStartedCapture + // example if it creates an error video = new Capture(this, 160, 120); - video.start(); + + // Start capturing the images from the camera + video.start(); + videoCount = video.width * video.height; pixelCount = width*height; @@ -70,6 +74,8 @@ void draw() { updatePixels(); currentAngle++; - if (currentAngle == angleCount) currentAngle = 0; + if (currentAngle == angleCount) { + currentAngle = 0; + } } } diff --git a/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde b/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde index f33927317..c58189245 100644 --- a/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde +++ b/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde @@ -7,6 +7,8 @@ * consider using the image copy() function rather than the * direct pixel-accessing approach I have used here. */ + + import processing.video.*; Capture video; @@ -17,9 +19,12 @@ int drawPositionX; void setup() { size(600, 240, P2D); - // Uses the default video input, see the reference if this causes an error - video = new Capture(this, 320, 240); - video.start(); + // This the default video input, see the GettingStartedCapture + // example if it creates an error + video = new Capture(this,320, 240); + + // Start capturing the images from the camera + video.start(); videoSliceX = video.width / 2; drawPositionX = width - 1; diff --git a/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde b/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde index 0eb682bcd..24a1a83d4 100644 --- a/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde +++ b/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde @@ -24,8 +24,13 @@ int currentX = 0; void setup() { size(640, 480); - video = new Capture(this, width, height, 30); - video.start(); + + // This the default video input, see the GettingStartedCapture + // example if it creates an error + video = new Capture(this, width, height); + + // Start capturing the images from the camera + video.start(); } void captureEvent(Capture c) { diff --git a/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde b/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde index cf2847845..460f8adcf 100644 --- a/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde +++ b/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde @@ -16,42 +16,47 @@ ArrayList frames = new ArrayList(); void setup() { size(640, 480); - video = new Capture(this, width, height, 30); - video.start(); + + // This the default video input, see the GettingStartedCapture + // example if it creates an error + video = new Capture(this, width, height); + + // Start capturing the images from the camera + video.start(); } void captureEvent(Capture camera) { camera.read(); - //copy the current video frame into an image, so it can be stored in the buffer + // Copy the current video frame into an image, so it can be stored in the buffer PImage img = createImage(width, height, RGB); video.loadPixels(); arrayCopy(video.pixels, img.pixels); frames.add(img); - //once there are enough frames, remove the oldest one when adding a new one + // Once there are enough frames, remove the oldest one when adding a new one if (frames.size() > height/4) { frames.remove(0); } } void draw() { - //set the image counter to 0 + // Set the image counter to 0 int currentImage = 0; loadPixels(); - //begin a loop for displaying pixel rows of 4 pixels height + // Begin a loop for displaying pixel rows of 4 pixels height for (int y = 0; y < video.height; y+=4) { - //go through the frame buffer and pick an image, starting with the oldest one + // Go through the frame buffer and pick an image, starting with the oldest one if (currentImage < frames.size()) { PImage img = (PImage)frames.get(currentImage); if (img != null) { img.loadPixels(); - //put 4 rows of pixels on the screen + // Put 4 rows of pixels on the screen for (int x = 0; x < video.width; x++) { pixels[x + y * width] = img.pixels[x + y * video.width]; pixels[x + (y + 1) * width] = img.pixels[x + (y + 1) * video.width]; @@ -60,7 +65,7 @@ void draw() { } } - //increase the image counter + // Increase the image counter currentImage++; } else { @@ -70,7 +75,7 @@ void draw() { updatePixels(); - //for recording an image sequence + // For recording an image sequence //saveFrame("frame-####.jpg"); } From 5d09d85a78dc9a8a5402e26a8f8c89c3e762af04 Mon Sep 17 00:00:00 2001 From: Casey Reas Date: Tue, 5 Mar 2013 14:09:11 -0800 Subject: [PATCH 04/25] Modified color coding for 2.0b9 --- build/shared/lib/preferences.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt index 0575ba4a9..9c9222918 100644 --- a/build/shared/lib/preferences.txt +++ b/build/shared/lib/preferences.txt @@ -236,23 +236,23 @@ editor.token.function2.style = #006699,plain editor.token.function3.style = #669900,plain editor.token.function4.style = #006699,bold -editor.token.keyword1.style = #72a7c2,plain -editor.token.keyword2.style = #72a7c2,plain +editor.token.keyword1.style = #33997e,plain +editor.token.keyword2.style = #33997e,plain editor.token.keyword3.style = #669900,plain -editor.token.keyword4.style = #ff6699,plain -editor.token.keyword5.style = #e37139,plain +editor.token.keyword4.style = #d94a7a,plain +editor.token.keyword5.style = #e2661a,plain editor.token.literal1.style = #7D4793,plain -editor.token.literal2.style = #617952,plain +editor.token.literal2.style = #718a62,plain editor.token.operator.style = #006699,plain -editor.token.label.style = #7e7e7e,bold +editor.token.label.style = #666666,bold -editor.token.comment1.style = #7e7e7e,plain -editor.token.comment2.style = #7e7e7e,plain +editor.token.comment1.style = #666666,plain +editor.token.comment2.style = #666666,plain -editor.token.invalid.style = #7e7e7e,bold +editor.token.invalid.style = #666666,bold # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! From c951d4a31bde46ba61810e96c477e1f1e5ff6648 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 16:46:31 -0500 Subject: [PATCH 05/25] fixing up smoke particle system --- .../Simulate/SmokeParticleSystem/Particle.pde | 15 +++++----- .../SmokeParticleSystem/ParticleSystem.pde | 28 +++++-------------- .../SmokeParticleSystem.pde | 3 -- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/java/examples/Topics/Simulate/SmokeParticleSystem/Particle.pde b/java/examples/Topics/Simulate/SmokeParticleSystem/Particle.pde index a8802c2f2..3351e144c 100644 --- a/java/examples/Topics/Simulate/SmokeParticleSystem/Particle.pde +++ b/java/examples/Topics/Simulate/SmokeParticleSystem/Particle.pde @@ -10,8 +10,8 @@ class Particle { Particle(PVector l,PImage img_) { acc = new PVector(0,0); - float vx = (float) generator.nextGaussian()*0.3; - float vy = (float) generator.nextGaussian()*0.3 - 1.0; + float vx = randomGaussian()*0.3; + float vy = randomGaussian()*0.3 - 1.0; vel = new PVector(vx,vy); loc = l.get(); lifespan = 100.0; @@ -33,8 +33,8 @@ class Particle { void update() { vel.add(acc); loc.add(vel); - acc.mult(0); // clear Acceleration lifespan -= 2.5; + acc.mult(0); // clear Acceleration } // Method to display @@ -42,10 +42,14 @@ class Particle { imageMode(CENTER); tint(255,lifespan); image(img,loc.x,loc.y); + // Drawing a circle instead + // fill(255,lifespan); + // noStroke(); + // ellipse(loc.x,loc.y,img.width,img.height); } // Is the particle still useful? - boolean dead() { + boolean isDead() { if (lifespan <= 0.0) { return true; } else { @@ -54,6 +58,3 @@ class Particle { } } - - - diff --git a/java/examples/Topics/Simulate/SmokeParticleSystem/ParticleSystem.pde b/java/examples/Topics/Simulate/SmokeParticleSystem/ParticleSystem.pde index b0e2ed439..5c2d5bcab 100644 --- a/java/examples/Topics/Simulate/SmokeParticleSystem/ParticleSystem.pde +++ b/java/examples/Topics/Simulate/SmokeParticleSystem/ParticleSystem.pde @@ -4,25 +4,24 @@ class ParticleSystem { ArrayList particles; // An arraylist for all the particles - PVector origin; // An origin point for where particles are birthed + PVector origin; // An origin point for where particles are birthed PImage img; ParticleSystem(int num, PVector v, PImage img_) { particles = new ArrayList(); // Initialize the arraylist - origin = v.get(); // Store the origin point + origin = v.get(); // Store the origin point img = img_; for (int i = 0; i < num; i++) { - particles.add(new Particle(origin, img)); // Add "num" amount of particles to the arraylist + particles.add(new Particle(origin, img)); // Add "num" amount of particles to the arraylist } } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); - if (p.dead()) { - it.remove(); + if (p.isDead()) { + particles.remove(i); } } } @@ -40,19 +39,6 @@ class ParticleSystem { particles.add(new Particle(origin,img)); } - void addParticle(Particle p) { - particles.add(p); - } - - // A method to test if the particle system still has particles - boolean dead() { - if (particles.isEmpty()) { - return true; - } else { - return false; - } - } - } diff --git a/java/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pde b/java/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pde index 7941208a1..23be99484 100644 --- a/java/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pde +++ b/java/examples/Topics/Simulate/SmokeParticleSystem/SmokeParticleSystem.pde @@ -11,14 +11,11 @@ /* @pjs preload="texture.png"; */ ParticleSystem ps; -Random generator; void setup() { size(640,360); - generator = new Random(); PImage img = loadImage("texture.png"); ps = new ParticleSystem(0,new PVector(width/2,height-60),img); - smooth(); } void draw() { From c41905d3f1d9b4f7482e337e847f3c4218f89e0f Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 16:52:08 -0500 Subject: [PATCH 06/25] adding a new example for randomGaussian --- .../Math/RandomGaussian/RandomGaussian.pde | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 java/examples/Basics/Math/RandomGaussian/RandomGaussian.pde diff --git a/java/examples/Basics/Math/RandomGaussian/RandomGaussian.pde b/java/examples/Basics/Math/RandomGaussian/RandomGaussian.pde new file mode 100644 index 000000000..d71501dba --- /dev/null +++ b/java/examples/Basics/Math/RandomGaussian/RandomGaussian.pde @@ -0,0 +1,28 @@ +/** + * Random Gaussian. + * + * This sketch draws ellipses with x and y locations tied to a gaussian distribution of random numbers. + */ + +void setup() { + size(640, 360); + background(0); +} + +void draw() { + + // Get a gaussian random number w/ mean of 0 and standard deviation of 1.0 + float val = randomGaussian(); + + float sd = 60; // Define a standard deviation + float mean = width/2; // Define a mean value (middle of the screen along the x-axis) + float x = ( val * sd ) + mean; // Scale the gaussian random number by standard deviation and mean + + noStroke(); + fill(255, 10); + noStroke(); + ellipse(x, height/2, 32, 32); // Draw an ellipse at our "normal" random location +} + + + From 2b3333318236876450bbf6bf6ce318cbf7e6e711 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 22:33:56 -0500 Subject: [PATCH 07/25] fixing up ArrayLists for generics, also Kock curve updates --- .../Fractals and L-Systems/Koch/Koch.pde | 135 ------------------ .../Koch/KochFractal.pde | 67 +++++++++ .../Fractals and L-Systems/Koch/KochLine.pde | 74 ++++++++++ .../SimpleParticleSystem/ParticleSystem.pde | 7 +- .../SimpleParticleSystem.pde | 1 - 5 files changed, 144 insertions(+), 140 deletions(-) create mode 100644 java/examples/Topics/Fractals and L-Systems/Koch/KochFractal.pde create mode 100644 java/examples/Topics/Fractals and L-Systems/Koch/KochLine.pde diff --git a/java/examples/Topics/Fractals and L-Systems/Koch/Koch.pde b/java/examples/Topics/Fractals and L-Systems/Koch/Koch.pde index 377c35b67..4299f06f8 100644 --- a/java/examples/Topics/Fractals and L-Systems/Koch/Koch.pde +++ b/java/examples/Topics/Fractals and L-Systems/Koch/Koch.pde @@ -11,7 +11,6 @@ KochFractal k; void setup() { size(640, 360); - background(0); frameRate(1); // Animate slowly k = new KochFractal(); } @@ -29,137 +28,3 @@ void draw() { } -// A class to manage the list of line segments in the snowflake pattern - -class KochFractal { - Point start; // A point for the start - Point end; // A point for the end - ArrayList lines; // A list to keep track of all the lines - int count; - - KochFractal() { - start = new Point(0, height/2 + height/4); - end = new Point(width, height/2 + height/4); - lines = new ArrayList(); - restart(); - } - - void nextLevel() { - // For every line that is in the arraylist - // create 4 more lines in a new arraylist - lines = iterate(lines); - count++; - } - - void restart() { - count = 0; // Reset count - lines.clear(); // Empty the array list - lines.add(new KochLine(start,end)); // Add the initial line (from one end point to the other) - } - - int getCount() { - return count; - } - - // This is easy, just draw all the lines - void render() { - for(int i = 0; i < lines.size(); i++) { - KochLine l = (KochLine)lines.get(i); - l.render(); - } - } - - // This is where the **MAGIC** happens - // Step 1: Create an empty arraylist - // Step 2: For every line currently in the arraylist - // - calculate 4 line segments based on Koch algorithm - // - add all 4 line segments into the new arraylist - // Step 3: Return the new arraylist and it becomes the list of line segments for the structure - - // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . - ArrayList iterate(ArrayList before) { - ArrayList now = new ArrayList(); //Create emtpy list - for (int i = 0; i < before.size(); i++) { - KochLine l = (KochLine)lines.get(i); // A line segment inside the list - // Calculate 5 koch points (done for us by the line object) - Point a = l.start(); - Point b = l.kochleft(); - Point c = l.kochmiddle(); - Point d = l.kochright(); - Point e = l.end(); - // Make line segments between all the points and add them - now.add(new KochLine(a,b)); - now.add(new KochLine(b,c)); - now.add(new KochLine(c,d)); - now.add(new KochLine(d,e)); - } - return now; - } - -} - - -// A class to describe one line segment in the fractal -// Includes methods to calculate midpoints along the line according to the Koch algorithm - -class KochLine { - - // Two points, - // a is the "left" point and - // b is the "right point - Point a, b; - - KochLine(Point a_, Point b_) { - a = a_.copy(); - b = b_.copy(); - } - - void render() { - stroke(255); - line(a.x, a.y, b.x, b.y); - } - - Point start() { - return a.copy(); - } - - Point end() { - return b.copy(); - } - - // This is easy, just 1/3 of the way - Point kochleft() { - float x = a.x + (b.x - a.x) / 3f; - float y = a.y + (b.y - a.y) / 3f; - return new Point(x,y); - } - - // More complicated, have to use a little trig to figure out where this point is! - Point kochmiddle() { - float x = a.x + 0.5f * (b.x - a.x) + (sin(radians(60))*(b.y-a.y)) / 3; - float y = a.y + 0.5f * (b.y - a.y) - (sin(radians(60))*(b.x-a.x)) / 3; - return new Point(x,y); - } - - // Easy, just 2/3 of the way - Point kochright() { - float x = a.x + 2*(b.x - a.x) / 3f; - float y = a.y + 2*(b.y - a.y) / 3f; - return new Point(x,y); - } - -} - -class Point { - float x,y; - - Point(float x_, float y_) { - x = x_; - y = y_; - } - - Point copy() { - return new Point(x,y); - } -} - diff --git a/java/examples/Topics/Fractals and L-Systems/Koch/KochFractal.pde b/java/examples/Topics/Fractals and L-Systems/Koch/KochFractal.pde new file mode 100644 index 000000000..b538959ab --- /dev/null +++ b/java/examples/Topics/Fractals and L-Systems/Koch/KochFractal.pde @@ -0,0 +1,67 @@ +// Koch Curve +// A class to manage the list of line segments in the snowflake pattern + +class KochFractal { + PVector start; // A PVector for the start + PVector end; // A PVector for the end + ArrayList lines; // A list to keep track of all the lines + int count; + + public KochFractal() { + start = new PVector(0,height-20); + end = new PVector(width,height-20); + lines = new ArrayList(); + restart(); + } + + void nextLevel() { + // For every line that is in the arraylist + // create 4 more lines in a new arraylist + lines = iterate(lines); + count++; + } + + void restart() { + count = 0; // Reset count + lines.clear(); // Empty the array list + lines.add(new KochLine(start,end)); // Add the initial line (from one end PVector to the other) + } + + int getCount() { + return count; + } + + // This is easy, just draw all the lines + void render() { + for(KochLine l : lines) { + l.display(); + } + } + + // This is where the **MAGIC** happens + // Step 1: Create an empty arraylist + // Step 2: For every line currently in the arraylist + // - calculate 4 line segments based on Koch algorithm + // - add all 4 line segments into the new arraylist + // Step 3: Return the new arraylist and it becomes the list of line segments for the structure + + // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . + ArrayList iterate(ArrayList before) { + ArrayList now = new ArrayList(); // Create emtpy list + for(KochLine l : before) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.start(); + PVector b = l.kochleft(); + PVector c = l.kochmiddle(); + PVector d = l.kochright(); + PVector e = l.end(); + // Make line segments between all the PVectors and add them + now.add(new KochLine(a,b)); + now.add(new KochLine(b,c)); + now.add(new KochLine(c,d)); + now.add(new KochLine(d,e)); + } + return now; + } + +} diff --git a/java/examples/Topics/Fractals and L-Systems/Koch/KochLine.pde b/java/examples/Topics/Fractals and L-Systems/Koch/KochLine.pde new file mode 100644 index 000000000..b9eafc012 --- /dev/null +++ b/java/examples/Topics/Fractals and L-Systems/Koch/KochLine.pde @@ -0,0 +1,74 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector a; + PVector b; + + KochLine(PVector start, PVector end) { + a = start.get(); + b = end.get(); + } + + void display() { + stroke(255); + line(a.x, a.y, b.x, b.y); + } + + PVector start() { + return a.get(); + } + + PVector end() { + return b.get(); + } + + // This is easy, just 1/3 of the way + PVector kochleft() { + PVector v = PVector.sub(b, a); + v.div(3); + v.add(a); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochmiddle() { + PVector v = PVector.sub(b, a); + v.div(3); + + PVector p = a.get(); + p.add(v); + + rotate(v,-radians(60)); + p.add(v); + + return p; + } + + + // Easy, just 2/3 of the way + PVector kochright() { + PVector v = PVector.sub(a, b); + v.div(3); + v.add(b); + return v; + } +} + + public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*cos(theta) - v.y*sin(theta); + v.y = xTemp*sin(theta) + v.y*cos(theta); + } + + diff --git a/java/examples/Topics/Simulate/SimpleParticleSystem/ParticleSystem.pde b/java/examples/Topics/Simulate/SimpleParticleSystem/ParticleSystem.pde index 4c4f02ab5..bd5937e77 100644 --- a/java/examples/Topics/Simulate/SimpleParticleSystem/ParticleSystem.pde +++ b/java/examples/Topics/Simulate/SimpleParticleSystem/ParticleSystem.pde @@ -15,12 +15,11 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } diff --git a/java/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pde b/java/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pde index 5b55db150..9b46822f1 100644 --- a/java/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pde +++ b/java/examples/Topics/Simulate/SimpleParticleSystem/SimpleParticleSystem.pde @@ -12,7 +12,6 @@ ParticleSystem ps; void setup() { size(640,360); - smooth(); ps = new ParticleSystem(new PVector(width/2,50)); } From e67dfcf8abef809394b3266b8b3cd2f8b7062555 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 22:36:05 -0500 Subject: [PATCH 08/25] fixing up directory list example date import, ArrayList generics --- .../Topics/File IO/DirectoryList/DirectoryList.pde | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java/examples/Topics/File IO/DirectoryList/DirectoryList.pde b/java/examples/Topics/File IO/DirectoryList/DirectoryList.pde index 426421511..2bf64b991 100644 --- a/java/examples/Topics/File IO/DirectoryList/DirectoryList.pde +++ b/java/examples/Topics/File IO/DirectoryList/DirectoryList.pde @@ -10,6 +10,7 @@ * of files in a directory and all subdirectories (using recursion) */ +import java.util.Date; void setup() { @@ -33,10 +34,9 @@ void setup() { } println("\nListing info about all files in a directory and all subdirectories: "); - ArrayList allFiles = listFilesRecursive(path); + ArrayList allFiles = listFilesRecursive(path); - for (int i = 0; i < allFiles.size(); i++) { - File f = (File) allFiles.get(i); + for (File f: allFiles) { println("Name: " + f.getName()); println("Full path: " + f.getAbsolutePath()); println("Is directory: " + f.isDirectory()); @@ -81,14 +81,14 @@ File[] listFiles(String dir) { } // Function to get a list of all files in a directory and all subdirectories -ArrayList listFilesRecursive(String dir) { - ArrayList fileList = new ArrayList(); +ArrayList listFilesRecursive(String dir) { + ArrayList fileList = new ArrayList(); recurseDir(fileList,dir); return fileList; } // Recursive function to traverse subdirectories -void recurseDir(ArrayList a, String dir) { +void recurseDir(ArrayList a, String dir) { File file = new File(dir); if (file.isDirectory()) { // If you want to include directories in the list From 95abed351f387cb8684158812e010cbacf2e647e Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 22:38:01 -0500 Subject: [PATCH 09/25] remove iterator from particle system --- .../MultipleParticleSystems.pde | 1 - .../MultipleParticleSystems/ParticleSystem.pde | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/java/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pde b/java/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pde index 5acfc96e6..5bc038e7d 100644 --- a/java/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pde +++ b/java/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pde @@ -15,7 +15,6 @@ ArrayList systems; void setup() { size(640, 360); systems = new ArrayList(); - smooth(); } void draw() { diff --git a/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde b/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde index d387e8444..570551009 100644 --- a/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde +++ b/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde @@ -1,6 +1,5 @@ // An ArrayList is used to manage the list of Particles // An Iterator is used to remove "dead" particles while iterating over the list -import java.util.Iterator; class ParticleSystem { @@ -15,14 +14,14 @@ class ParticleSystem { } } + void run() { - // Cycle through the ArrayList using Iterator, because we are deleting while iterating - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + // Cycle through the ArrayList backwards, because we are deleting while iterating + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } @@ -32,7 +31,8 @@ class ParticleSystem { // Add either a Particle or CrazyParticle to the system if (int(random(0, 2)) == 0) { p = new Particle(origin); - } else { + } + else { p = new CrazyParticle(origin); } particles.add(p); @@ -46,5 +46,5 @@ class ParticleSystem { boolean dead() { return particles.isEmpty(); } +} -} \ No newline at end of file From 82c677ef331c3a624c2ceb130f13a9a97c839d3d Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 22:57:58 -0500 Subject: [PATCH 10/25] removing comment about iterator --- .../Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde | 1 - 1 file changed, 1 deletion(-) diff --git a/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde b/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde index 570551009..7b5586835 100644 --- a/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde +++ b/java/examples/Topics/Simulate/MultipleParticleSystems/ParticleSystem.pde @@ -1,5 +1,4 @@ // An ArrayList is used to manage the list of Particles -// An Iterator is used to remove "dead" particles while iterating over the list class ParticleSystem { From 6b5521af3c5435e0e0216ddc73a134084d847cb0 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 22:59:57 -0500 Subject: [PATCH 11/25] update of Nature of Code examples, need to do one more before 2.0 --- .../NOC_10_02_SeekingNeural/Vehicle.pde | 30 +- .../Extra_instantforce/Extra_instantforce.pde | 57 + .../chp2_forces/Extra_instantforce/Mover.pde | 69 + .../NOC_2_1_forces/NOC_2_1_forces.pde | 2 +- .../NOC_2_6_attraction/NOC_2_6_attraction.pde | 2 +- .../Crawler.pde | 18 +- .../Exercise_3_03_cannon/CannonBall.pde | 44 + .../Exercise_3_03_cannon.pde | 54 + .../Exercise_3_05_asteroids.pde | 2 +- .../Exercise_3_16_springs.pde | 57 + .../Exercise_3_16_springs/Mover.pde | 78 + .../Exercise_3_16_springs/Spring.pde | 52 + .../Exercise_3_16_springs_array.pde | 50 + .../Exercise_3_16_springs_array/Mover.pde | 78 + .../Exercise_3_16_springs_array/Spring.pde | 52 + .../ExtraOscillatingBody/Attractor.pde | 78 + .../ExtraOscillatingBody.pde | 40 + .../ExtraOscillatingBody/Mover.pde | 64 + .../ExtraOscillatingUpAndDown.pde | 15 + .../MultipleOscillations.pde | 34 + .../NOC_3_03_pointing_velocity/Mover.pde | 6 +- .../NOC_3_11_spring/NOC_3_11_spring.pde | 2 +- .../NOC_3_11_spring/sketch.properties | 2 - .../Exercise_4_03_MovingParticleSystem.pde | 26 + .../Particle.pde | 50 + .../ParticleSystem.pde | 36 + .../Exercise_4_04_asteroids.pde | 41 + .../Exercise_4_04_asteroids/Particle.pde | 49 + .../ParticleSystem.pde | 30 + .../Exercise_4_04_asteroids/Spaceship.pde | 110 + .../Exercise_4_06_Shatter.pde | 21 + .../Exercise_4_06_Shatter/Particle.pde | 54 + .../Exercise_4_06_Shatter/ParticleSystem.pde | 45 + .../Exercise_4_10_particleintersection.pde | 18 + .../Particle.pde | 73 + .../ParticleSystem.pde | 43 + .../Exercise_4_10_particlerepel.pde | 21 + .../Exercise_4_10_particlerepel/Particle.pde | 70 + .../ParticleSystem.pde | 48 + .../Exercise_4_12_ArrayofImages.pde | 39 + .../Exercise_4_12_ArrayofImages/Particle.pde | 59 + .../ParticleSystem.pde | 55 + .../data/texture.psd | Bin 0 -> 26028 bytes .../NOC_4_02_ArrayListParticles.pde | 12 +- .../NOC_4_03_ParticleSystemClass.pde | 2 +- .../ParticleSystem.pde | 8 +- .../NOC_4_04_SystemofSystems.pde | 3 +- .../ParticleSystem.pde | 17 +- ..._ParticleSystemInheritancePolymorphism.pde | 2 +- .../ParticleSystem.pde | 11 +- .../NOC_4_06_ParticleSystemForces.pde | 2 +- .../ParticleSystem.pde | 8 +- .../NOC_4_07_ParticleSystemForcesRepeller.pde | 2 +- .../ParticleSystem.pde | 8 +- .../NOC_4_08_ParticleSystemSmoke.pde | 13 +- .../NOC_4_08_ParticleSystemSmoke/Particle.pde | 6 +- .../ParticleSystem.pde | 30 +- .../NOC_4_08_ParticleSystemSmoke_b.pde | 12 +- .../Particle.pde | 2 +- .../ParticleSystem.pde | 13 +- .../NOC_4_09_AdditiveBlending.pde | 17 +- .../NOC_4_09_AdditiveBlending/Particle.pde | 2 +- .../ParticleSystem.pde | 16 +- .../ParticleSystem.pde | 11 +- ... => ParticleSystemInheritance_pushpop.pde} | 2 +- .../flight404_particles_1_simple/NOC_gl.pde | 0 .../flight404_particles_1_simple/emitter.pde | 2 +- .../flight404_particles_1_simple.pde | 26 +- .../flight404_particles_1_simple/particle.pde | 0 .../flight404_particles_2_simple/NOC_gl.pde | 0 .../flight404_particles_2_simple/cursor.pde | 0 .../flight404_particles_2_simple/emitter.pde | 4 +- .../flight404_particles_2_simple.pde | 25 +- .../flight404_particles_2_simple/images.pde | 0 .../flight404_particles_2_simple/nebula.pde | 0 .../flight404_particles_2_simple/particle.pde | 0 .../flight404_particles_2_simple/pov.pde | 0 .../CollisionsEqualMass/drawVector.pde | 2 +- .../NOC_5_1_box2d_exercise.pde | 2 +- .../NOC_5_1_box2d_exercise_solved.pde | 2 +- .../box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde | 2 +- .../NOC_5_3_ChainShape_Simple.pde | 2 +- .../NOC_5_3_ChainShape_Simple/Surface.pde | 2 +- .../NOC_5_4_Polygons/NOC_5_4_Polygons.pde | 2 +- .../NOC_5_5_MultiShapes.pde | 4 +- .../NOC_5_6_DistanceJoint.pde | 2 +- .../NOC_5_7_RevoluteJoint.pde | 2 +- .../NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde | 2 +- .../NOC_5_9_CollisionListening.pde | 2 +- .../Exercise_5_13_SoftBodySquareAdapted.pde | 2 +- .../Exercise_5_15_ForceDirectedGraph.pde | 4 +- .../NOC_5_10_SimpleSpring.pde | 7 +- .../NOC_5_11_SoftStringPendulum.pde | 4 +- .../NOC_5_12_SimpleCluster.pde | 3 +- .../NOC_5_13_AttractRepel.pde | 2 +- .../CrowdPathFollowing/sketch.properties | 1 - .../Exercise_6_04_Wander/Vehicle.pde | 12 +- .../Exercise_6_09_AngleBetween.pde | 6 +- .../NOC_6_01_Seek/NOC_6_01_Seek.pde | 3 +- .../chp6_agents/NOC_6_01_Seek/Vehicle.pde | 14 +- .../NOC_6_01_Seek_trail/Vehicle.pde | 18 +- .../NOC_6_02_Arrive/NOC_6_02_Arrive.pde | 3 +- .../chp6_agents/NOC_6_02_Arrive/Vehicle.pde | 12 +- .../NOC_6_03_StayWithinWalls/Vehicle.pde | 14 +- .../Vehicle.pde | 20 +- .../NOC_6_04_Flow_Figures/FlowField.pde | 4 +- .../NOC_6_04_Flow_Figures/Vehicle.pde | 2 +- .../NOC_6_04_Flowfield/FlowField.pde | 2 +- .../NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde | 2 +- .../NOC_6_04_Flowfield/Vehicle.pde | 2 +- .../NOC_6_04_Flowfield/sketch.properties | 0 .../NOC_6_05_PathFollowingSimple.pde | 2 +- .../NOC_6_05_PathFollowingSimple/Vehicle.pde | 2 +- .../sketch.properties | 1 - .../NOC_6_06_PathFollowing.pde | 2 +- .../NOC_6_06_PathFollowing/Vehicle.pde | 2 +- .../NOC_6_07_Separation.pde | 2 +- .../NOC_6_08_SeparationAndSeek.pde | 2 +- .../NOC_6_08_SeparationAndSeek/Vehicle.pde | 2 +- .../sketch.properties | 1 - .../chp6_agents/NOC_6_09_Flocking/Boid.pde | 4 +- .../NOC_6_09_Flocking/NOC_6_09_Flocking.pde | 2 +- .../chp6_agents/StayWithinCircle/Vehicle.pde | 14 +- .../chp6_agents/flocking_sliders/Boid.pde | 4 +- .../NOC_7_02_GameOfLifeOOP.pde | 2 +- .../GOL.pde | 0 .../NOC_7_02_GameOfLifeSimple.pde} | 2 +- .../chp7_CA/NOC_7_03_GameOfLifeOOP/Cell.pde | 40 + .../chp7_CA/NOC_7_03_GameOfLifeOOP/GOL.pde | 73 + .../NOC_7_03_GameOfLifeOOP.pde | 27 + .../NOC_8_01_Recursion/NOC_8_01_Recursion.pde | 3 +- .../NOC_8_02_Recursion/NOC_8_02_Recursion.pde | 2 +- .../NOC_8_03_KochSimple/KochLine.pde | 72 - .../NOC_8_03_KochSimple.pde | 51 - .../NOC_8_03_Recursion/NOC_8_03_Recursion.pde | 2 +- .../NOC_8_05_Koch/sketch.properties | 4 +- .../web-export/NOC_8_05_Koch.pde | 176 + .../NOC_8_05_Koch/web-export/processing.js | 10203 ++++++++++++++++ .../chp8_fractals/Tree2/Branch.pde | 12 +- .../chp8_fractals/Tree3/Branch.pde | 6 +- .../chp9_ga/EvolveFlowField/Rocket.pde | 8 +- .../Rocket.pde | 6 +- .../chp9_ga/NOC_9_03_SmartRockets/Rocket.pde | 6 +- .../NOC_I_4_Gaussian/NOC_I_4_Gaussian.pde | 12 +- .../NoiseWalk_Many/NoiseWalk_Many.pde | 35 + .../introduction/NoiseWalk_Many/Walker.pde | 34 + .../RandomWalkTrailCurve.pde | 20 + .../RandomWalkTrailCurve/Walker.pde | 42 + .../SelfAvoidingWalk/SelfAvoidingWalk.pde | 20 + .../introduction/SelfAvoidingWalk/Walker.pde | 73 + .../introduction/SelfAvoidingWalk/goal.svg | 2353 ++++ 151 files changed, 15068 insertions(+), 449 deletions(-) create mode 100644 java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Extra_instantforce.pde create mode 100644 java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Mover.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/CannonBall.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/Exercise_3_03_cannon.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Exercise_3_16_springs.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Mover.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Spring.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Exercise_3_16_springs_array.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Mover.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Spring.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Attractor.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/ExtraOscillatingBody.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Mover.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingUpAndDown/ExtraOscillatingUpAndDown.pde create mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/MultipleOscillations/MultipleOscillations.pde delete mode 100644 java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Exercise_4_03_MovingParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Exercise_4_04_asteroids.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Spaceship.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Exercise_4_06_Shatter.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Exercise_4_10_particleintersection.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Exercise_4_10_particlerepel.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Exercise_4_12_ArrayofImages.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Particle.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/ParticleSystem.pde create mode 100644 java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/data/texture.psd rename java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/{NOC_04_6ParticleSystemInheritance_pushpop.pde => ParticleSystemInheritance_pushpop.pde} (93%) mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde mode change 100644 => 100755 java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde delete mode 100644 java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties delete mode 100644 java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/sketch.properties delete mode 100644 java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties delete mode 100644 java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties rename java/examples/Books/Nature of Code/chp7_CA/{NOC_7_03_GameOfLifeSimple => NOC_7_02_GameOfLifeSimple}/GOL.pde (100%) rename java/examples/Books/Nature of Code/chp7_CA/{NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde => NOC_7_02_GameOfLifeSimple/NOC_7_02_GameOfLifeSimple.pde} (96%) create mode 100644 java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/Cell.pde create mode 100644 java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/GOL.pde create mode 100644 java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/NOC_7_03_GameOfLifeOOP.pde delete mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde delete mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde create mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde create mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js create mode 100644 java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/NoiseWalk_Many.pde create mode 100644 java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/Walker.pde create mode 100644 java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/RandomWalkTrailCurve.pde create mode 100644 java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/Walker.pde create mode 100644 java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/SelfAvoidingWalk.pde create mode 100644 java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/Walker.pde create mode 100644 java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/goal.svg diff --git a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde index fc6a83b6c..efd9bf287 100644 --- a/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp10_nn/NOC_10_02_SeekingNeural/Vehicle.pde @@ -4,10 +4,10 @@ // The "Vehicle" class class Vehicle { - + // Vehicle now has a brain! Perceptron brain; - + PVector location; PVector velocity; PVector acceleration; @@ -34,7 +34,7 @@ class Vehicle { location.add(velocity); // Reset accelerationelertion to 0 each cycle acceleration.mult(0); - + location.x = constrain(location.x,0,width); location.y = constrain(location.y,0,height); } @@ -43,48 +43,48 @@ class Vehicle { // We could add mass here if we want A = F / M acceleration.add(force); } - + // Here is where the brain processes everything void steer(ArrayList targets) { // Make an array of forces PVector[] forces = new PVector[targets.size()]; - + // Steer towards all targets for (int i = 0; i < forces.length; i++) { forces[i] = seek(targets.get(i)); } - + // That array of forces is the input to the brain PVector result = brain.feedforward(forces); - + // Use the result to steer the vehicle applyForce(result); - + // Train the brain according to the error PVector error = PVector.sub(desired, location); brain.train(forces,error); - + } - + // A method that calculates a steering force towards a target // STEER = DESIRED MINUS VELOCITY PVector seek(PVector target) { PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target - + // Normalize desired and scale to maximum speed desired.normalize(); desired.mult(maxspeed); // Steering = Desired minus velocity PVector steer = PVector.sub(desired,velocity); steer.limit(maxforce); // Limit to maximum steering force - + return steer; } - + void display() { - + // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(175); stroke(0); strokeWeight(1); diff --git a/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Extra_instantforce.pde b/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Extra_instantforce.pde new file mode 100644 index 000000000..ac2636abd --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Extra_instantforce.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover m; + +float t = 0.0; + +void setup() { + size(640, 360); + m = new Mover(); +} + +void draw() { + background(255); + + // Perlin noise wind + float wx = map(noise(t),0,1,-1,1); + PVector wind = new PVector(wx, 0); + t += 0.01; + line(width/2,height/2,width/2+wind.x*100,height/2+wind.y*100); + m.applyForce(wind); + + // Gravity + PVector gravity = new PVector(0, 0.1); + //m.applyForce(gravity); + + // Shake force + //m.shake(); + + // Boundary force + if (m.location.x > width - 50) { + PVector boundary = new PVector(-1,0); + m.applyForce(boundary); + } else if (m.location.x < 50) { + PVector boundary = new PVector(1,0); + m.applyForce(boundary); + } + + + + + m.update(); + m.display(); + //m.checkEdges(); +} + +// Instant Force +void mousePressed() { + PVector cannon = PVector.random2D(); + cannon.mult(5); + m.applyForce(cannon); +} + + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Mover.pde b/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Mover.pde new file mode 100644 index 000000000..681cfed16 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp2_forces/Extra_instantforce/Mover.pde @@ -0,0 +1,69 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover() { + location = new PVector(width/2,height/2); + velocity = new PVector(0,0); + acceleration = new PVector(0,0); + mass = 1; + } + + void shake() { + PVector force = PVector.random2D(); + force.mult(0.7); + applyForce(force); + + + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + + // Simple friction + velocity.mult(0.95); + + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + ellipse(location.x,location.y,48,48); + } + + void checkEdges() { + + if (location.x > width) { + location.x = width; + velocity.x *= -1; + } else if (location.x < 0) { + velocity.x *= -1; + location.x = 0; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde index 0972f6e9a..92713efaa 100644 --- a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_1_forces/NOC_2_1_forces.pde @@ -5,7 +5,7 @@ Mover m; void setup() { - size(800,200); + size(640,360); m = new Mover(); } diff --git a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde index d747ee9b3..d2ab1284a 100644 --- a/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde +++ b/java/examples/Books/Nature of Code/chp2_forces/NOC_2_6_attraction/NOC_2_6_attraction.pde @@ -6,7 +6,7 @@ Mover m; Attractor a; void setup() { - size(800,200); + size(640,360); m = new Mover(); a = new Attractor(); } diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde index 5739cd300..7c03641ee 100644 --- a/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde +++ b/java/examples/Books/Nature of Code/chp3_oscillation/AttractionArrayWithOscillation/Crawler.pde @@ -12,9 +12,9 @@ class Crawler { PVector vel; PVector acc; float mass; - + Oscillator osc; - + Crawler() { acc = new PVector(); vel = new PVector(random(-1,1),random(-1,1)); @@ -22,9 +22,9 @@ class Crawler { mass = random(8,16); osc = new Oscillator(mass*2); } - + void applyForce(PVector force) { - PVector f = force.get(); + PVector f = force.get(); f.div(mass); acc.add(f); } @@ -35,13 +35,13 @@ class Crawler { loc.add(vel); // Multiplying by 0 sets the all the components to 0 acc.mult(0); - + osc.update(vel.mag()/10); } - + // Method to display void display() { - float angle = vel.heading(); + float angle = vel.heading2D(); pushMatrix(); translate(loc.x,loc.y); rotate(angle); @@ -49,10 +49,10 @@ class Crawler { stroke(0); fill(175,100); ellipse(0,0,mass*2,mass*2); - + osc.display(loc); popMatrix(); - + } } diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/CannonBall.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/CannonBall.pde new file mode 100644 index 000000000..80a9ca8ba --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/CannonBall.pde @@ -0,0 +1,44 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class CannonBall { + // All of our regular motion stuff + PVector location; + PVector velocity; + PVector acceleration; + + // Size + float r = 8; + + float topspeed = 10; + + CannonBall(float x, float y) { + location = new PVector(x,y); + velocity = new PVector(); + acceleration = new PVector(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.limit(topspeed); + location.add(velocity); + acceleration.mult(0); + } + + void applyForce(PVector force) { + acceleration.add(force); + } + + + void display() { + stroke(0); + strokeWeight(2); + pushMatrix(); + translate(location.x,location.y); + ellipse(0,0,r*2,r*2); + popMatrix(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/Exercise_3_03_cannon.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/Exercise_3_03_cannon.pde new file mode 100644 index 000000000..72313eaa9 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_03_cannon/Exercise_3_03_cannon.pde @@ -0,0 +1,54 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + + +// All of this stuff should go into a Cannon class +float angle = -PI/4; +PVector location = new PVector(50, 300); +boolean shot = false; + +CannonBall ball; + +void setup() { + size(640, 360); + ball = new CannonBall(location.x, location.y); +} + +void draw() { + background(255); + + pushMatrix(); + translate(location.x, location.y); + rotate(angle); + rect(0, -5, 50, 10); + popMatrix(); + + if (shot) { + PVector gravity = new PVector(0, 0.2); + ball.applyForce(gravity); + ball.update(); + } + ball.display(); + + if (ball.location.y > height) { + ball = new CannonBall(location.x, location.y); + shot = false; + } +} + +void keyPressed() { + if (key == CODED && keyCode == RIGHT) { + angle += 0.1; + } + else if (key == CODED && keyCode == LEFT) { + angle -= 0.1; + } + else if (key == ' ') { + shot = true; + PVector force = PVector.fromAngle(angle); + force.mult(10); + ball.applyForce(force); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde index 8f031f272..d0340916f 100644 --- a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_05_asteroids/Exercise_3_05_asteroids.pde @@ -8,7 +8,7 @@ Spaceship ship; void setup() { - size(750, 200); + size(640, 360); ship = new Spaceship(); } diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Exercise_3_16_springs.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Exercise_3_16_springs.pde new file mode 100644 index 000000000..9f0d74795 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Exercise_3_16_springs.pde @@ -0,0 +1,57 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Mover object +Bob b1; +Bob b2; +Bob b3; + +Spring s1; +Spring s2; +Spring s3; + +void setup() { + size(640, 360); + // Create objects at starting location + // Note third argument in Spring constructor is "rest length" + b1 = new Bob(width/2, 100); + b2 = new Bob(width/2, 200); + b3 = new Bob(width/2, 300); + + s1 = new Spring(b1,b2,100); + s2 = new Spring(b2,b3,100); + s3 = new Spring(b1,b3,100); +} + +void draw() { + background(255); + + s1.update(); + s2.update(); + s3.update(); + + s1.display(); + s2.display(); + s3.display(); + + b1.update(); + b1.display(); + b2.update(); + b2.display(); + b3.update(); + b3.display(); + + b1.drag(mouseX, mouseY); +} + + + +void mousePressed() { + b1.clicked(mouseX, mouseY); +} + +void mouseReleased() { + b1.stopDragging(); +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Mover.pde new file mode 100644 index 000000000..368aa20d2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Mover.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Bob class, just like our regular Mover (location, velocity, acceleration, mass) + +class Bob { + PVector location; + PVector velocity; + PVector acceleration; + float mass = 12; + + // Arbitrary damping to simulate friction / drag + float damping = 0.95; + + // For mouse interaction + PVector dragOffset; + boolean dragging = false; + + // Constructor + Bob(float x, float y) { + location = new PVector(x,y); + velocity = new PVector(); + acceleration = new PVector(); + dragOffset = new PVector(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.mult(damping); + location.add(velocity); + acceleration.mult(0); + } + + // Newton's law: F = M * A + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acceleration.add(f); + } + + + // Draw the bob + void display() { + stroke(0); + strokeWeight(2); + fill(175); + if (dragging) { + fill(50); + } + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + + // This checks to see if we clicked on the mover + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void stopDragging() { + dragging = false; + } + + void drag(int mx, int my) { + if (dragging) { + location.x = mx + dragOffset.x; + location.y = my + dragOffset.y; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Spring.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Spring.pde new file mode 100644 index 000000000..0f4060e13 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs/Spring.pde @@ -0,0 +1,52 @@ +// Nature of Code 2011 +// Daniel Shiffman +// Chapter 3: Oscillation + +// Class to describe an anchor point that can connect to "Bob" objects via a spring +// Thank you: http://www.myphysicslab.com/spring2d.html + +class Spring { + + // Location + PVector anchor; + + // Rest length and spring constant + float len; + float k = 0.2; + + Bob a; + Bob b; + + // Constructor + Spring(Bob a_, Bob b_, int l) { + a = a_; + b = b_; + len = l; + } + + // Calculate spring force + void update() { + // Vector pointing from anchor to bob location + PVector force = PVector.sub(a.location, b.location); + // What is distance + float d = force.mag(); + // Stretch is difference between current distance and rest length + float stretch = d - len; + + // Calculate force according to Hooke's Law + // F = k * stretch + force.normalize(); + force.mult(-1 * k * stretch); + a.applyForce(force); + force.mult(-1); + b.applyForce(force); + } + + + void display() { + strokeWeight(2); + stroke(0); + line(a.location.x, a.location.y, b.location.x, b.location.y); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Exercise_3_16_springs_array.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Exercise_3_16_springs_array.pde new file mode 100644 index 000000000..01a0bcad4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Exercise_3_16_springs_array.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Mover object +Bob[] bobs = new Bob[5]; + +Spring[] springs = new Spring[4]; + +void setup() { + size(640, 360); + // Create objects at starting location + // Note third argument in Spring constructor is "rest length" + for (int i = 0; i < bobs.length; i++) { + bobs[i] = new Bob(width/2, i*40); + } + for (int i = 0; i < springs.length; i++) { + springs[i] = new Spring(bobs[i], bobs[i+1],40); + } +} + +void draw() { + background(255); + + for (Spring s : springs) { + s.update(); + s.display(); + } + + for (Bob b : bobs) { + b.update(); + b.display(); + b.drag(mouseX, mouseY); + } +} + + + +void mousePressed() { + for (Bob b : bobs) { + b.clicked(mouseX, mouseY); + } +} + +void mouseReleased() { + for (Bob b : bobs) { + b.stopDragging(); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Mover.pde new file mode 100644 index 000000000..7f5e0fcc5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Mover.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Bob class, just like our regular Mover (location, velocity, acceleration, mass) + +class Bob { + PVector location; + PVector velocity; + PVector acceleration; + float mass = 8; + + // Arbitrary damping to simulate friction / drag + float damping = 0.95; + + // For mouse interaction + PVector dragOffset; + boolean dragging = false; + + // Constructor + Bob(float x, float y) { + location = new PVector(x,y); + velocity = new PVector(); + acceleration = new PVector(); + dragOffset = new PVector(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.mult(damping); + location.add(velocity); + acceleration.mult(0); + } + + // Newton's law: F = M * A + void applyForce(PVector force) { + PVector f = force.get(); + f.div(mass); + acceleration.add(f); + } + + + // Draw the bob + void display() { + stroke(0); + strokeWeight(2); + fill(175,120); + if (dragging) { + fill(50); + } + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + + // This checks to see if we clicked on the mover + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void stopDragging() { + dragging = false; + } + + void drag(int mx, int my) { + if (dragging) { + location.x = mx + dragOffset.x; + location.y = my + dragOffset.y; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Spring.pde b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Spring.pde new file mode 100644 index 000000000..0f4060e13 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/Exercise_3_16_springs_array/Spring.pde @@ -0,0 +1,52 @@ +// Nature of Code 2011 +// Daniel Shiffman +// Chapter 3: Oscillation + +// Class to describe an anchor point that can connect to "Bob" objects via a spring +// Thank you: http://www.myphysicslab.com/spring2d.html + +class Spring { + + // Location + PVector anchor; + + // Rest length and spring constant + float len; + float k = 0.2; + + Bob a; + Bob b; + + // Constructor + Spring(Bob a_, Bob b_, int l) { + a = a_; + b = b_; + len = l; + } + + // Calculate spring force + void update() { + // Vector pointing from anchor to bob location + PVector force = PVector.sub(a.location, b.location); + // What is distance + float d = force.mag(); + // Stretch is difference between current distance and rest length + float stretch = d - len; + + // Calculate force according to Hooke's Law + // F = k * stretch + force.normalize(); + force.mult(-1 * k * stretch); + a.applyForce(force); + force.mult(-1); + b.applyForce(force); + } + + + void display() { + strokeWeight(2); + stroke(0); + line(a.location.x, a.location.y, b.location.x, b.location.y); + } +} + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Attractor.pde b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Attractor.pde new file mode 100644 index 000000000..556605cb7 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Attractor.pde @@ -0,0 +1,78 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class for a draggable attractive body in our world + +class Attractor { + float mass; // Mass, tied to size + float G; // Gravitational Constant + PVector location; // Location + boolean dragging = false; // Is the object being dragged? + boolean rollover = false; // Is the mouse over the ellipse? + PVector dragOffset; // holds the offset for when object is clicked on + + Attractor() { + location = new PVector(width/2,height/2); + mass = 20; + G = 1; + dragOffset = new PVector(0.0,0.0); + } + + PVector attract(Mover m) { + PVector force = PVector.sub(location,m.location); // Calculate direction of force + float d = force.mag(); // Distance between objects + d = constrain(d,5.0,25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects + force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) + float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude + force.mult(strength); // Get force vector --> magnitude * direction + return force; + } + + // Method to display + void display() { + ellipseMode(CENTER); + strokeWeight(4); + stroke(0); + if (dragging) fill (50); + else if (rollover) fill(100); + else fill(175,200); + ellipse(location.x,location.y,mass*2,mass*2); + } + + // The methods below are for mouse interaction + void clicked(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + dragging = true; + dragOffset.x = location.x-mx; + dragOffset.y = location.y-my; + } + } + + void hover(int mx, int my) { + float d = dist(mx,my,location.x,location.y); + if (d < mass) { + rollover = true; + } + else { + rollover = false; + } + } + + void stopDragging() { + dragging = false; + } + + + + void drag() { + if (dragging) { + location.x = mouseX + dragOffset.x; + location.y = mouseY + dragOffset.y; + } + } + +} + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/ExtraOscillatingBody.pde b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/ExtraOscillatingBody.pde new file mode 100644 index 000000000..25f1b1ca5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/ExtraOscillatingBody.pde @@ -0,0 +1,40 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Mover m; +Attractor a; + +void setup() { + size(640,360); + m = new Mover(); + a = new Attractor(); +} + +void draw() { + background(255); + + PVector force = a.attract(m); + m.applyForce(force); + m.update(); + + a.drag(); + a.hover(mouseX,mouseY); + + a.display(); + m.display(); + +} + +void mousePressed() { + a.clicked(mouseX,mouseY); +} + +void mouseReleased() { + a.stopDragging(); +} + + + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Mover.pde new file mode 100644 index 000000000..00850bc1c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingBody/Mover.pde @@ -0,0 +1,64 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Mover { + + PVector location; + PVector velocity; + PVector acceleration; + float mass; + + Mover() { + location = new PVector(400,50); + velocity = new PVector(1,0); + acceleration = new PVector(0,0); + mass = 1; + } + + void applyForce(PVector force) { + PVector f = PVector.div(force,mass); + acceleration.add(f); + } + + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + } + + void display() { + stroke(0); + strokeWeight(2); + fill(127); + pushMatrix(); + translate(location.x,location.y); + float heading = velocity.heading(); + rotate(heading); + ellipse(0,0,16,16); + rectMode(CENTER); + // "20" should be a variable that is oscillating + // with sine function + rect(20,0,10,10); + popMatrix(); + } + + void checkEdges() { + + if (location.x > width) { + location.x = 0; + } else if (location.x < 0) { + location.x = width; + } + + if (location.y > height) { + velocity.y *= -1; + location.y = height; + } + + } + +} + + + diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingUpAndDown/ExtraOscillatingUpAndDown.pde b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingUpAndDown/ExtraOscillatingUpAndDown.pde new file mode 100644 index 000000000..68b1b2074 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/ExtraOscillatingUpAndDown/ExtraOscillatingUpAndDown.pde @@ -0,0 +1,15 @@ +float angle = 0; +void setup() { + size(400,400); +} + +void draw() { + background(255); + float y = 100*sin(angle); + angle += 0.02; + + fill(127); + translate(width/2,height/2); + line(0,0,0,y); + ellipse(0,y,16,16); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/MultipleOscillations/MultipleOscillations.pde b/java/examples/Books/Nature of Code/chp3_oscillation/MultipleOscillations/MultipleOscillations.pde new file mode 100644 index 000000000..4a53d917f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp3_oscillation/MultipleOscillations/MultipleOscillations.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +float angle1 = 0; +float aVelocity1 = 0.01; +float amplitude1 = 300; + +float angle2 = 0; +float aVelocity2 = 0.3; +float amplitude2 = 10; + + +void setup() { + size(640,360); +} + +void draw() { + background(255); + + float x = 0; + x += amplitude1 * cos(angle1); + x += amplitude2 * sin(angle2); + + angle1 += aVelocity1; + angle2 += aVelocity2; + + ellipseMode(CENTER); + stroke(0); + fill(175); + translate(width/2,height/2); + line(0,0,x,0); + ellipse(x,0,20,20); +} diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde index e5a951a56..399d93a4d 100644 --- a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_03_pointing_velocity/Mover.pde @@ -35,7 +35,7 @@ class Mover { } void display() { - float theta = velocity.heading(); + float theta = velocity.heading2D(); stroke(0); strokeWeight(2); @@ -52,14 +52,14 @@ class Mover { if (location.x > width) { location.x = 0; - } + } else if (location.x < 0) { location.x = width; } if (location.y > height) { location.y = 0; - } + } else if (location.y < 0) { location.y = height; } diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde index 06532f8c9..ff09a0a9a 100644 --- a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde +++ b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/NOC_3_11_spring.pde @@ -9,7 +9,7 @@ Bob bob; Spring spring; void setup() { - size(800,200); + size(640,360); // Create objects at starting location // Note third argument in Spring constructor is "rest length" spring = new Spring(width/2,10,100); diff --git a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties b/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties deleted file mode 100644 index b3cbe600e..000000000 --- a/java/examples/Books/Nature of Code/chp3_oscillation/NOC_3_11_spring/sketch.properties +++ /dev/null @@ -1,2 +0,0 @@ -mode.id=processing.mode.java.JavaMode -mode=Standard diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Exercise_4_03_MovingParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Exercise_4_03_MovingParticleSystem.pde new file mode 100644 index 000000000..3e26041b4 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Exercise_4_03_MovingParticleSystem.pde @@ -0,0 +1,26 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(640,360); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + + // Option #1 (move the Particle System origin) + ps.origin.set(mouseX,mouseY,0); + + ps.addParticle(); + ps.run(); + + // Option #2 (move the Particle System origin) + // ps.addParticle(mouseX,mouseY); + + + +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Particle.pde new file mode 100644 index 000000000..12d1ef02a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/Particle.pde @@ -0,0 +1,50 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l) { + acceleration = new PVector(0,0.05); + velocity = new PVector(random(-1,1),random(-2,0)); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0,lifespan); + strokeWeight(2); + fill(127,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/ParticleSystem.pde new file mode 100644 index 000000000..264df8539 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_03_MovingParticleSystem/ParticleSystem.pde @@ -0,0 +1,36 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + PVector origin; + + ParticleSystem(PVector location) { + origin = location.get(); + particles = new ArrayList(); + } + + void addParticle() { + particles.add(new Particle(origin)); + } + + void addParticle(float x, float y) { + particles.add(new Particle(new PVector(x, y))); + } + + void run() { + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.run(); + if (p.isDead()) { + particles.remove(i); + } + } + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Exercise_4_04_asteroids.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Exercise_4_04_asteroids.pde new file mode 100644 index 000000000..d0340916f --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Exercise_4_04_asteroids.pde @@ -0,0 +1,41 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Chapter 3: Asteroids exercise + +// Mover object +Spaceship ship; + +void setup() { + size(640, 360); + ship = new Spaceship(); +} + +void draw() { + background(255); + + // Update location + ship.update(); + // Wrape edges + ship.wrapEdges(); + // Draw ship + ship.display(); + + + fill(0); + //text("left right arrows to turn, z to thrust",10,height-5); + + // Turn or thrust the ship depending on what key is pressed + if (keyPressed) { + if (key == CODED && keyCode == LEFT) { + ship.turn(-0.03); + } else if (key == CODED && keyCode == RIGHT) { + ship.turn(0.03); + } else if (key == 'z' || key == 'Z') { + ship.thrust(); + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Particle.pde new file mode 100644 index 000000000..e6736696e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Particle.pde @@ -0,0 +1,49 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + Particle(PVector l,PVector dir) { + acceleration = dir.get(); + velocity = PVector.random2D(); + location = l.get(); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + noStroke(); + fill(127,0,0,lifespan); + ellipse(location.x,location.y,12,12); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/ParticleSystem.pde new file mode 100644 index 000000000..0b83fa96a --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/ParticleSystem.pde @@ -0,0 +1,30 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + + ParticleSystem() { + particles = new ArrayList(); + } + + void addParticle(float x, float y, PVector force) { + particles.add(new Particle(new PVector(x, y),force)); + } + + void run() { + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.run(); + if (p.isDead()) { + particles.remove(i); + } + } + } +} + + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Spaceship.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Spaceship.pde new file mode 100644 index 000000000..bdc11f6c1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_04_asteroids/Spaceship.pde @@ -0,0 +1,110 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Chapter 3: Asteroids + +class Spaceship { + // All of our regular motion stuff + PVector location; + PVector velocity; + PVector acceleration; + + ParticleSystem ps; + + // Arbitrary damping to slow down ship + float damping = 0.995; + float topspeed = 6; + + // Variable for heading! + float heading = 0; + + // Size + float r = 16; + + // Are we thrusting (to color boosters) + boolean thrusting = false; + + Spaceship() { + location = new PVector(width/2,height/2); + velocity = new PVector(); + acceleration = new PVector(); + + ps = new ParticleSystem(); + } + + // Standard Euler integration + void update() { + velocity.add(acceleration); + velocity.mult(damping); + velocity.limit(topspeed); + location.add(velocity); + acceleration.mult(0); + + ps.run(); + } + + // Newton's law: F = M * A + void applyForce(PVector force) { + PVector f = force.get(); + //f.div(mass); // ignoring mass right now + acceleration.add(f); + } + + // Turn changes angle + void turn(float a) { + heading += a; + } + + // Apply a thrust force + void thrust() { + // Offset the angle since we drew the ship vertically + float angle = heading - PI/2; + // Polar to cartesian for force vector! + PVector force = PVector.fromAngle(angle); + force.mult(0.1); + applyForce(force); + + force.mult(-2); + ps.addParticle(location.x,location.y+r,force); + + + // To draw booster + thrusting = true; + } + + void wrapEdges() { + float buffer = r*2; + if (location.x > width + buffer) location.x = -buffer; + else if (location.x < -buffer) location.x = width+buffer; + if (location.y > height + buffer) location.y = -buffer; + else if (location.y < -buffer) location.y = height+buffer; + } + + + // Draw the ship + void display() { + stroke(0); + strokeWeight(2); + pushMatrix(); + translate(location.x,location.y+r); + rotate(heading); + fill(175); + if (thrusting) fill(255,0,0); + // Booster rockets + rect(-r/2,r,r/3,r/2); + rect(r/2,r,r/3,r/2); + fill(175); + // A triangle + beginShape(); + vertex(-r,r); + vertex(0,-r); + vertex(r,r); + endShape(CLOSE); + rectMode(CENTER); + popMatrix(); + + thrusting = false; + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Exercise_4_06_Shatter.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Exercise_4_06_Shatter.pde new file mode 100644 index 000000000..f7026ae40 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Exercise_4_06_Shatter.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(640,360); + ps = new ParticleSystem(100,100,5); +} + +void draw() { + background(255); + + ps.display(); + ps.update(); +} + +void mousePressed() { + ps.shatter(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Particle.pde new file mode 100644 index 000000000..d160a42c8 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/Particle.pde @@ -0,0 +1,54 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + float r; + + Particle(float x, float y, float r_) { + acceleration = new PVector(0,0.01); + velocity = PVector.random2D(); + velocity.mult(0.5); + location = new PVector(x,y); + lifespan = 255.0; + r = r_; + } + + void run() { + update(); + display(); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0); + fill(0); + rectMode(CENTER); + rect(location.x,location.y,r,r); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } else { + return false; + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/ParticleSystem.pde new file mode 100644 index 000000000..611b1218b --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_06_Shatter/ParticleSystem.pde @@ -0,0 +1,45 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + + int rows = 20; + int cols = 20; + + boolean intact = true; + + ParticleSystem(float x, float y, float r) { + particles = new ArrayList(); + + for (int i = 0; i < rows*cols; i++) { + addParticle(x + (i%cols)*r, y + (i/rows)*r, r); + } + } + + void addParticle(float x, float y, float r) { + particles.add(new Particle(x, y, r)); + } + + void display() { + for (Particle p : particles) { + p.display(); + } + } + + void shatter() { + intact = false; + } + + void update() { + if (!intact) { + for (Particle p : particles) { + p.update(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Exercise_4_10_particleintersection.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Exercise_4_10_particleintersection.pde new file mode 100644 index 000000000..d27427366 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Exercise_4_10_particleintersection.pde @@ -0,0 +1,18 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(640,360); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + ps.addParticle(mouseX,mouseY); + ps.update(); + ps.intersection(); + ps.display(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Particle.pde new file mode 100644 index 000000000..90c4dec0c --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/Particle.pde @@ -0,0 +1,73 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + float r = 6; + boolean highlight; + + Particle(float x, float y) { + acceleration = new PVector(0, 0.05); + velocity = new PVector(random(-1, 1), random(-2, 0)); + location = new PVector(x, y); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + void intersects(ArrayList particles) { + highlight = false; + for (Particle other : particles) { + if (other != this) { + float d = PVector.dist(other.location, location); + if (d < r + other.r) { + highlight = true; + } + } + } + } + + void applyForce(PVector f) { + acceleration.add(f); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + lifespan -= 2.0; + } + + // Method to display + void display() { + stroke(0, lifespan); + strokeWeight(2); + fill(127, lifespan); + if (highlight) { + fill(127,0,0); + } + ellipse(location.x, location.y, r*2, r*2); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/ParticleSystem.pde new file mode 100644 index 000000000..3b3367656 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particleintersection/ParticleSystem.pde @@ -0,0 +1,43 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + + ParticleSystem(PVector location) { + particles = new ArrayList(); + } + + void addParticle(float x, float y) { + particles.add(new Particle(x, y)); + } + + + void display() { + for (Particle p : particles) { + p.display(); + } + } + + void intersection() { + for (Particle p : particles) { + p.intersects(particles); + } + } + + + void update() { + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.update(); + if (p.isDead()) { + particles.remove(i); + } + } + } +} + + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Exercise_4_10_particlerepel.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Exercise_4_10_particlerepel.pde new file mode 100644 index 000000000..408ce3edd --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Exercise_4_10_particlerepel.pde @@ -0,0 +1,21 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +ParticleSystem ps; + +void setup() { + size(640,360); + ps = new ParticleSystem(new PVector(width/2,50)); +} + +void draw() { + background(255); + ps.addParticle(random(width),random(height)); + + //PVector gravity = new PVector(0,0.1); + //ps.applyForce(gravity); + ps.update(); + ps.intersection(); + ps.display(); +} diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Particle.pde new file mode 100644 index 000000000..dcd577cec --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/Particle.pde @@ -0,0 +1,70 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector location; + PVector velocity; + PVector acceleration; + float lifespan; + + float r = 6; + + + Particle(float x, float y) { + acceleration = new PVector(); + velocity = PVector.random2D(); + location = new PVector(x, y); + lifespan = 255.0; + } + + void run() { + update(); + display(); + } + + void intersects(ArrayList particles) { + for (Particle other : particles) { + if (other != this) { + PVector dir = PVector.sub(location, other.location); + if (dir.mag() < r*2) { + dir.setMag(0.5); + applyForce(dir); + } + } + } + } + + void applyForce(PVector f) { + acceleration.add(f); + } + + // Method to update location + void update() { + velocity.add(acceleration); + location.add(velocity); + acceleration.mult(0); + lifespan -= 0.5; + } + + // Method to display + void display() { + stroke(0, lifespan); + strokeWeight(2); + fill(127, lifespan); + ellipse(location.x, location.y, r*2, r*2); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan < 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/ParticleSystem.pde new file mode 100644 index 000000000..4168dc229 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_10_particlerepel/ParticleSystem.pde @@ -0,0 +1,48 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Using Generics now! comment and annotate, etc. + +class ParticleSystem { + ArrayList particles; + + ParticleSystem(PVector location) { + particles = new ArrayList(); + } + + void addParticle(float x, float y) { + particles.add(new Particle(x, y)); + } + + + void display() { + for (Particle p : particles) { + p.display(); + } + } + + void applyForce(PVector f) { + for (Particle p : particles) { + p.applyForce(f); + } + } + + void intersection() { + for (Particle p : particles) { + p.intersects(particles); + } + } + + + void update() { + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.update(); + if (p.isDead()) { + particles.remove(i); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Exercise_4_12_ArrayofImages.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Exercise_4_12_ArrayofImages.pde new file mode 100644 index 000000000..dbc8ac3c5 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Exercise_4_12_ArrayofImages.pde @@ -0,0 +1,39 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Array of Images for particle textures + +ParticleSystem ps; + +PImage[] imgs; + +void setup() { + size(640, 360, P2D); + + imgs = new PImage[5]; + imgs[0] = loadImage("corona.png"); + imgs[1] = loadImage("emitter.png"); + imgs[2] = loadImage("particle.png"); + imgs[3] = loadImage("texture.png"); + imgs[4] = loadImage("reflection.png"); + + ps = new ParticleSystem(imgs, new PVector(width/2, 50)); +} + +void draw() { + + // Additive blending! + blendMode(ADD); + + background(0); + + PVector up = new PVector(0,-0.2); + ps.applyForce(up); + + ps.run(); + for (int i = 0; i < 5; i++) { + ps.addParticle(mouseX,mouseY); + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Particle.pde new file mode 100644 index 000000000..adb3431f3 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/Particle.pde @@ -0,0 +1,59 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Simple Particle System + +class Particle { + PVector loc; + PVector vel; + PVector acc; + float lifespan; + + PImage img; + + // Another constructor (the one we are using here) + Particle(float x, float y, PImage img_) { + // Boring example with constant acceleration + acc = new PVector(0, 0); + vel = PVector.random2D(); + loc = new PVector(x, y); + lifespan = 255; + img = img_; + } + + void run() { + update(); + render(); + } + + void applyForce(PVector f) { + acc.add(f); + } + + // Method to update location + void update() { + vel.add(acc); + loc.add(vel); + acc.mult(0); + lifespan -= 2.0; + } + + // Method to display + void render() { + imageMode(CENTER); + tint(lifespan); + image(img, loc.x, loc.y, 32, 32); + } + + // Is the particle still useful? + boolean isDead() { + if (lifespan <= 0.0) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/ParticleSystem.pde new file mode 100644 index 000000000..98208b71e --- /dev/null +++ b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/ParticleSystem.pde @@ -0,0 +1,55 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A class to describe a group of Particles +// An ArrayList is used to manage the list of Particles + +class ParticleSystem { + + ArrayList particles; // An arraylist for all the particles + + PImage[] textures; + + ParticleSystem(PImage[] imgs, PVector v) { + textures = imgs; + particles = new ArrayList(); // Initialize the arraylist + } + + void run() { + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.run(); + if (p.isDead()) { + particles.remove(i); + } + } + } + + void addParticle(float x, float y) { + int r = int(random(textures.length)); + particles.add(new Particle(x,y,textures[r])); + } + + + void applyForce(PVector f) { + for (Particle p : particles) { + p.applyForce(f); + } + } + + void addParticle(Particle p) { + particles.add(p); + } + + // A method to test if the particle system still has particles + boolean dead() { + if (particles.isEmpty()) { + return true; + } + else { + return false; + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/data/texture.psd b/java/examples/Books/Nature of Code/chp4_systems/Exercise_4_12_ArrayofImages/data/texture.psd new file mode 100644 index 0000000000000000000000000000000000000000..d532f15aa97ddc346e880e6801cfa46ec60e78f1 GIT binary patch literal 26028 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 particles; void setup() { - size(800,200); + size(640,360); particles = new ArrayList(); - smooth(); } void draw() { @@ -15,13 +14,12 @@ void draw() { particles.add(new Particle(new PVector(width/2,50))); - // Using the iterator - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + // Looping through backwards to delete + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde index d3268cc8e..935a214da 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.pde @@ -5,7 +5,7 @@ ParticleSystem ps; void setup() { - size(800,200); + size(640,360); ps = new ParticleSystem(new PVector(width/2,50)); } diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde index 895e5f6aa..ffddfc873 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_03_ParticleSystemClass/ParticleSystem.pde @@ -18,12 +18,11 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } @@ -32,4 +31,3 @@ class ParticleSystem { - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde index ca95f10c5..f487e938a 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/NOC_4_04_SystemofSystems.pde @@ -11,9 +11,8 @@ ArrayList systems; void setup() { - size(800,200); + size(640,360); systems = new ArrayList(); - smooth(); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde index 3d237a8b1..ad2dfc862 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_04_SystemofSystems/ParticleSystem.pde @@ -21,21 +21,15 @@ class ParticleSystem { } void run() { - // Using the Iterator b/c we are deleting from list while iterating - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } - void addParticle() { - particles.add(new Particle(origin)); - } - void addParticle(Particle p) { particles.add(p); } @@ -44,12 +38,11 @@ class ParticleSystem { boolean dead() { if (particles.isEmpty()) { return true; - } else { + } + else { return false; } } - } - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde index d3268cc8e..935a214da 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.pde @@ -5,7 +5,7 @@ ParticleSystem ps; void setup() { - size(800,200); + size(640,360); ps = new ParticleSystem(new PVector(width/2,50)); } diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde index 33a0e6353..28fde7c2e 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/ParticleSystem.pde @@ -15,18 +15,18 @@ class ParticleSystem { float r = random(1); if (r < 0.5) { particles.add(new Particle(origin)); - } else { + } + else { particles.add(new Confetti(origin)); } } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } @@ -34,4 +34,3 @@ class ParticleSystem { - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde index 6fcac8462..eef4c0555 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.pde @@ -5,7 +5,7 @@ ParticleSystem ps; void setup() { - size(800,200); + size(640,360); ps = new ParticleSystem(new PVector(width/2,50)); } diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde index 8bf9f10ba..c840ffd5b 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_06_ParticleSystemForces/ParticleSystem.pde @@ -23,15 +23,13 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } } - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde index ac4a29c08..c7de70143 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.pde @@ -6,7 +6,7 @@ ParticleSystem ps; Repeller repeller; void setup() { - size(800,200); + size(640,360); ps = new ParticleSystem(new PVector(width/2,50)); repeller = new Repeller(width/2-20,height/2); } diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde index 34725b859..d4ad80fa7 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_07_ParticleSystemForcesRepeller/ParticleSystem.pde @@ -31,16 +31,14 @@ class ParticleSystem { void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } } - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde index d5e72c0f3..fb11356e4 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/NOC_4_08_ParticleSystemSmoke.pde @@ -10,19 +10,16 @@ /* @pjs preload="processingjs/chapter04/_4_08_ParticleSystemSmoke/data/texture.png"; */ ParticleSystem ps; -Random generator; void setup() { - size(383,200); - generator = new Random(); + size(640,360); PImage img = loadImage("texture.png"); - ps = new ParticleSystem(0,new PVector(width/2,height-25),img); - smooth(); + ps = new ParticleSystem(0,new PVector(width/2,height-75),img); } void draw() { background(0); - + // Calculate a "wind" force based on mouse horizontal position float dx = map(mouseX,0,width,-0.2,0.2); PVector wind = new PVector(dx,0); @@ -31,7 +28,7 @@ void draw() { for (int i = 0; i < 2; i++) { ps.addParticle(); } - + // Draw an arrow representing the wind force drawVector(wind, new PVector(width/2,50,0),500); @@ -45,7 +42,7 @@ void drawVector(PVector v, PVector loc, float scayl) { translate(loc.x,loc.y); stroke(255); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde index 3edc523b2..b3dce76be 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/Particle.pde @@ -11,8 +11,8 @@ class Particle { Particle(PVector l,PImage img_) { acc = new PVector(0,0); - float vx = (float) generator.nextGaussian()*0.3; - float vy = (float) generator.nextGaussian()*0.3 - 1.0; + float vx = randomGaussian()*0.3; + float vy = randomGaussian()*0.3 - 1.0; vel = new PVector(vx,vy); loc = l.get(); lifespan = 100.0; @@ -50,7 +50,7 @@ class Particle { } // Is the particle still useful? - boolean dead() { + boolean isDead() { if (lifespan <= 0.0) { return true; } else { diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde index 742306f75..93fee68fa 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke/ParticleSystem.pde @@ -12,7 +12,7 @@ class ParticleSystem { ArrayList particles; // An arraylist for all the particles PVector origin; // An origin point for where particles are birthed PImage img; - + ParticleSystem(int num, PVector v, PImage img_) { particles = new ArrayList(); // Initialize the arraylist origin = v.get(); // Store the origin point @@ -23,43 +23,27 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); - if (p.dead()) { - it.remove(); + if (p.isDead()) { + particles.remove(i); } } } - + // Method to add a force vector to all particles currently in the system void applyForce(PVector dir) { // Enhanced loop!!! for (Particle p: particles) { p.applyForce(dir); } - } void addParticle() { - particles.add(new Particle(origin,img)); - } - - void addParticle(Particle p) { - particles.add(p); - } - - // A method to test if the particle system still has particles - boolean dead() { - if (particles.isEmpty()) { - return true; - } else { - return false; - } + particles.add(new Particle(origin, img)); } } - diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde index d5e72c0f3..52e945c60 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.pde @@ -9,20 +9,22 @@ /* @pjs preload="processingjs/chapter04/_4_08_ParticleSystemSmoke/data/texture.png"; */ +import java.util.Random; + ParticleSystem ps; Random generator; void setup() { - size(383,200); + size(640,360); generator = new Random(); PImage img = loadImage("texture.png"); - ps = new ParticleSystem(0,new PVector(width/2,height-25),img); + ps = new ParticleSystem(0,new PVector(width/2,height-75),img); smooth(); } void draw() { background(0); - + // Calculate a "wind" force based on mouse horizontal position float dx = map(mouseX,0,width,-0.2,0.2); PVector wind = new PVector(dx,0); @@ -31,7 +33,7 @@ void draw() { for (int i = 0; i < 2; i++) { ps.addParticle(); } - + // Draw an arrow representing the wind force drawVector(wind, new PVector(width/2,50,0),500); @@ -45,7 +47,7 @@ void drawVector(PVector v, PVector loc, float scayl) { translate(loc.x,loc.y); stroke(255); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde index 7a06982e7..c5516d104 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/Particle.pde @@ -53,7 +53,7 @@ class Particle { } // Is the particle still useful? - boolean dead() { + boolean isDead() { if (lifespan <= 0.0) { return true; } else { diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde index ecd805fa4..43296a098 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_08_ParticleSystemSmoke_b/ParticleSystem.pde @@ -22,15 +22,14 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); - p.run(); - if (p.dead()) { - it.remove(); - } + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); + p.run(); + if (p.isDead()) { + particles.remove(i); } } + } // Method to add a force vector to all particles currently in the system void applyForce(PVector dir) { diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde index 6cecff78d..d0341315f 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.pde @@ -2,28 +2,31 @@ // Daniel Shiffman // http://natureofcode.com -// Smoke Particle System +// Additive Blending -// A basic smoke effect using a particle system -// Each particle is rendered as an alpha masked image +// This example demonstrates a "glow" like effect using +// additive blending with a Particle system. By playing +// with colors, textures, etc. you can achieve a variety +// of looks. ParticleSystem ps; PImage img; void setup() { - size(800, 200, P2D); + size(640, 360, P2D); // Create an alpha masked image to be applied as the particle's texture img = loadImage("texture.png"); ps = new ParticleSystem(0, new PVector(width/2, 50)); - } +} void draw() { - + + // Additive blending! blendMode(ADD); - + background(0); ps.run(); diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde index 9c1fbaf66..d9853841b 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/Particle.pde @@ -40,7 +40,7 @@ class Particle { } // Is the particle still useful? - boolean dead() { + boolean isDead() { if (lifespan <= 0.0) { return true; } else { diff --git a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde index 9b733792d..208bd5418 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/NOC_4_09_AdditiveBlending/ParticleSystem.pde @@ -9,7 +9,7 @@ class ParticleSystem { ArrayList particles; // An arraylist for all the particles PVector origin; // An origin point for where particles are birthed - + PImage tex; ParticleSystem(int num, PVector v) { @@ -21,12 +21,11 @@ class ParticleSystem { } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); - if (p.dead()) { - it.remove(); + if (p.isDead()) { + particles.remove(i); } } } @@ -43,12 +42,11 @@ class ParticleSystem { boolean dead() { if (particles.isEmpty()) { return true; - } else { + } + else { return false; } } - } - diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde index 22a78969f..3e439bd84 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystem.pde @@ -15,18 +15,18 @@ class ParticleSystem { float r = random(1); if (r < 0.5) { particles.add(new Particle(origin)); - } else { + } + else { particles.add(new ParticleChild(origin)); } } void run() { - Iterator it = particles.iterator(); - while (it.hasNext()) { - Particle p = it.next(); + for (int i = particles.size()-1; i >= 0; i--) { + Particle p = particles.get(i); p.run(); if (p.isDead()) { - it.remove(); + particles.remove(i); } } } @@ -34,4 +34,3 @@ class ParticleSystem { - diff --git a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystemInheritance_pushpop.pde similarity index 93% rename from java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde rename to java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystemInheritance_pushpop.pde index 348016540..935a214da 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/NOC_04_6ParticleSystemInheritance_pushpop.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/ParticleSystemInheritance_pushpop/ParticleSystemInheritance_pushpop.pde @@ -5,7 +5,7 @@ ParticleSystem ps; void setup() { - size(200,200); + size(640,360); ps = new ParticleSystem(new PVector(width/2,50)); } diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/NOC_gl.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde old mode 100644 new mode 100755 index 479138397..0e6eb38fe --- a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/emitter.pde @@ -33,7 +33,7 @@ class Emitter{ iterateListExist(); render(); - gl.glDisable( GL.GL_TEXTURE_2D ); + pgl.disable( PGL.TEXTURE_2D ); if( ALLOWTRAILS ) iterateListRenderTrails(); diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde index 6b26364bf..549c8dccc 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/flight404_particles_1_simple.pde @@ -3,10 +3,7 @@ // http://natureofcode.com // Updated version of flight404 Particle Emitter release 1 -// This works with Processing 1.0 -// All of the advanced openGL direct calls that use display lists, etc. have been stripped out -// It's my intention to redo this example using GlGraphics (http://glgraphics.sourceforge.net/) -// But for now, just want to make sure it works in principal +// This works with Processing 2.0 // February 28 2011 // Daniel Shiffman @@ -49,12 +46,9 @@ import toxi.geom.*; -import processing.opengl.*; -import javax.media.opengl.*; - -PGraphicsOpenGL pgl; -GL gl; +import java.util.*; +PGL pgl; Emitter emitter; Vec3D gravity; @@ -74,17 +68,17 @@ boolean ALLOWFLOOR; // add a floor? // slow down. void setup(){ - size( 600, 600, OPENGL ); + size( 600, 600, P3D ); + smooth(4); // Lately I have gotten into the habit of limiting the color range to be // 0.0 to 1.0. It works this way in OpenGL so I might as well get used to it. colorMode( RGB, 1.0 ); // Turn on 4X antialiasing - hint( ENABLE_OPENGL_4X_SMOOTH ); + //hint( ENABLE_OPENGL_4X_SMOOTH ); // More OpenGL necessity. - pgl = (PGraphicsOpenGL) g; - gl = pgl.gl; + pgl = ((PGraphicsOpenGL) g).pgl; // Loads in a particle image from the data folder. Image size should be a power of 2. particleImg = loadImage( "particle.png" ); @@ -101,9 +95,9 @@ void draw(){ // Turns on additive blending so we can draw a bunch of glowing images without // needing to do any depth testing. - gl.glDepthMask(false); - gl.glEnable( GL.GL_BLEND ); - gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE); + pgl.depthMask(false); + pgl.enable( PGL.BLEND ); + pgl.blendFunc(PGL.SRC_ALPHA, PGL.ONE); emitter.exist(); diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_1_simple/particle.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/NOC_gl.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/cursor.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde old mode 100644 new mode 100755 index c22f45bdf..d405be8fd --- a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/emitter.pde @@ -28,7 +28,7 @@ class Emitter{ iterateListExist(); render(); - gl.glDisable( GL.GL_TEXTURE_2D ); + pgl.disable( PGL.TEXTURE_2D ); if( ALLOWTRAILS ) iterateListRenderTrails(); @@ -51,7 +51,7 @@ class Emitter{ } void iterateListExist(){ - gl.glEnable( GL.GL_TEXTURE_2D ); + pgl.enable( PGL.TEXTURE_2D ); int mylength = particles.size(); diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/flight404_particles_2_simple.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/flight404_particles_2_simple.pde index b03034700..2d4af8e37 100644 --- a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/flight404_particles_2_simple.pde +++ b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/flight404_particles_2_simple.pde @@ -58,11 +58,9 @@ import damkjer.ocd.*; import toxi.geom.*; -import processing.opengl.*; -import javax.media.opengl.*; +import java.util.*; -PGraphicsOpenGL pgl; -GL gl; +PGL pgl; POV pov; Images images; @@ -72,9 +70,6 @@ Cursor mouse; Vec3D gravity; float floorLevel; - - - int counter; int saveCount; int xSize, ySize; @@ -90,13 +85,11 @@ boolean ALLOWFLOOR = true; void setup() { - size( 750, 750, OPENGL ); - hint( ENABLE_OPENGL_4X_SMOOTH ); + size( 750, 750, P3D ); + smooth(4); colorMode( RGB, 1.0 ); - pgl = (PGraphicsOpenGL) g; - gl = pgl.gl; - + pgl = ((PGraphicsOpenGL) g).pgl; xSize = width; ySize = height; @@ -117,13 +110,13 @@ void draw() { pov.exist(); mouse.exist(); - gl.glDepthMask(false); - gl.glEnable( GL.GL_BLEND ); - gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE); + pgl.depthMask(false); + pgl.enable( PGL.BLEND ); + pgl.blendFunc(PGL.SRC_ALPHA,PGL.ONE); emitter.exist(); - if( mousePressed && mouseButton == LEFT ) + if (mousePressed) emitter.addParticles(2); counter ++; diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/images.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/nebula.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/particle.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde b/java/examples/Books/Nature of Code/chp4_systems/flight404/flight404_particles_2_simple/pov.pde old mode 100644 new mode 100755 diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde index 3f60ddae8..141c06960 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/CollisionsEqualMass/drawVector.pde @@ -9,7 +9,7 @@ void drawVector(PVector v, PVector loc, float scayl) { translate(loc.x,loc.y); stroke(0); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde index ca8a2decc..111643b0c 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise/NOC_5_1_box2d_exercise.pde @@ -6,7 +6,7 @@ ArrayList boxes; void setup() { - size(800,200); + size(640,360); // Create ArrayLists boxes = new ArrayList(); } diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde index dce205f42..22d39e2a9 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_1_box2d_exercise_solved/NOC_5_1_box2d_exercise_solved.pde @@ -13,7 +13,7 @@ ArrayList boxes; PBox2D box2d; void setup() { - size(800, 200); + size(640, 360); // Initialize and create the Box2D world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde index 3e80aade3..23193aa97 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_2_Boxes/NOC_5_2_Boxes.pde @@ -18,7 +18,7 @@ ArrayList boundaries; ArrayList boxes; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde index a9f07c166..6269a32d1 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/NOC_5_3_ChainShape_Simple.pde @@ -21,7 +21,7 @@ ArrayList particles; Surface surface; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde index d11a18410..09da0d535 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_3_ChainShape_Simple/Surface.pde @@ -13,7 +13,7 @@ class Surface { surface = new ArrayList(); // Here we keep track of the screen coordinates of the chain surface.add(new Vec2(0, height/2)); - //surface.add(new Vec2(width/2, height/2+50)); + surface.add(new Vec2(width/2, height/2+50)); surface.add(new Vec2(width, height/2)); // This is what box2d uses to put the surface in its world diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde index 145012993..283741835 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_4_Polygons/NOC_5_4_Polygons.pde @@ -18,7 +18,7 @@ ArrayList boundaries; ArrayList polygons; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde index 4ec682f7e..132b03ba6 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_5_MultiShapes/NOC_5_5_MultiShapes.pde @@ -18,7 +18,7 @@ ArrayList boundaries; ArrayList pops; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this,20); box2d.createWorld(); @@ -40,7 +40,7 @@ void draw() { background(255); // We must always step through time! - if (mousePressed) box2d.step(); + box2d.step(); // Display all the boundaries for (Boundary wall: boundaries) { diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde index 298cf690d..489468ebb 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_6_DistanceJoint/NOC_5_6_DistanceJoint.pde @@ -25,7 +25,7 @@ ArrayList boundaries; ArrayList pairs; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde index 676df2896..74ab0e3f2 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_7_RevoluteJoint/NOC_5_7_RevoluteJoint.pde @@ -23,7 +23,7 @@ Windmill windmill; ArrayList particles; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde index b9fe8f72c..0d77536d6 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_8_MouseJoint/NOC_5_8_MouseJoint.pde @@ -25,7 +25,7 @@ Box box; Spring spring; void setup() { - size(800,200); + size(640,360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde index 18132585c..c4b1688c7 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/box2d/NOC_5_9_CollisionListening/NOC_5_9_CollisionListening.pde @@ -23,7 +23,7 @@ ArrayList particles; Boundary wall; void setup() { - size(800, 200); + size(640, 360); // Initialize box2d physics and create the world box2d = new PBox2D(this); box2d.createWorld(); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde index c41ee1126..cf2b469c7 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_13_SoftBodySquareAdapted/Exercise_5_13_SoftBodySquareAdapted.pde @@ -46,7 +46,7 @@ Blanket b; void setup() { - size(800,240); + size(640,360); physics=new VerletPhysics2D(); physics.addBehavior(new GravityBehavior(new Vec2D(0,0.1))); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde index 3cde75511..f3dd8e190 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/Exercise_5_15_ForceDirectedGraph/Exercise_5_15_ForceDirectedGraph.pde @@ -6,7 +6,7 @@ */ /* - * Copyright (c) 2010 Daniel Schiffmann + * Copyright (c) 2010 Daniel Shiffman * * This demo & library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,7 +43,7 @@ boolean showParticles = true; PFont f; void setup() { - size(800,300); + size(640,360); f = createFont("Georgia",12,true); // Initialize the physics diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde index 14ab4dd7b..eeaaf48e0 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_10_SimpleSpring/NOC_5_10_SimpleSpring.pde @@ -15,8 +15,7 @@ Particle p1; Particle p2; void setup() { - size(800,200); - frameRate(30); + size(640,360); // Initialize the physics physics=new VerletPhysics2D(); @@ -27,12 +26,12 @@ void setup() { // Make two particles p1 = new Particle(new Vec2D(width/2,20)); - p2 = new Particle(new Vec2D(width,180)); + p2 = new Particle(new Vec2D(width/2+160,20)); // Lock one in place p1.lock(); // Make a spring connecting both Particles - VerletSpring2D spring=new VerletSpring2D(p1,p2,80,0.01); + VerletSpring2D spring=new VerletSpring2D(p1,p2,160,0.01); // Anything we make, we have to add into the physics world physics.addParticle(p1); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde index cab6ace9d..1e9b6aa25 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_11_SoftStringPendulum/NOC_5_11_SoftStringPendulum.pde @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2010 Daniel Shiffmann + * Copyright (c) 2010 Daniel Shiffman * * This demo & library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,7 +35,7 @@ VerletPhysics2D physics; Chain chain; void setup() { - size(800, 200); + size(640, 360); // Initialize the physics world physics=new VerletPhysics2D(); physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.1))); diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde index 46cb7eddc..043803d67 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_12_SimpleCluster/NOC_5_12_SimpleCluster.pde @@ -22,8 +22,7 @@ boolean showParticles = true; PFont f; void setup() { - size(800, 200); - frameRate(30); + size(640, 360); f = createFont("Georgia", 12, true); // Initialize the physics diff --git a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde index 79691843b..4359d202c 100644 --- a/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde +++ b/java/examples/Books/Nature of Code/chp5_physicslibraries/toxiclibs/NOC_5_13_AttractRepel/NOC_5_13_AttractRepel.pde @@ -8,7 +8,7 @@ Attractor attractor; VerletPhysics2D physics; void setup () { - size (800, 200); + size (640, 360); physics = new VerletPhysics2D (); physics.setDrag (0.01); diff --git a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties deleted file mode 100644 index 28faa5897..000000000 --- a/java/examples/Books/Nature of Code/chp6_agents/CrowdPathFollowing/sketch.properties +++ /dev/null @@ -1 +0,0 @@ -mode=Standard diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde index 31b824b87..fb979e8c5 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_04_Wander/Vehicle.pde @@ -52,16 +52,16 @@ class Vehicle { circleloc.normalize(); // Normalize to get heading circleloc.mult(wanderD); // Multiply by distance circleloc.add(location); // Make it relative to boid's location - - float h = velocity.heading(); // We need to know the heading to offset wandertheta + + float h = velocity.heading2D(); // We need to know the heading to offset wandertheta PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h)); PVector target = PVector.add(circleloc,circleOffSet); seek(target); - // Render wandering circle, etc. + // Render wandering circle, etc. if (debug) drawWanderStuff(location,circleloc,target,wanderR); - } + } void applyForce(PVector force) { // We could add mass here if we want A = F / M @@ -86,7 +86,7 @@ class Vehicle { void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(127); stroke(0); pushMatrix(); @@ -112,7 +112,7 @@ class Vehicle { // A method just to draw the circle associated with wandering void drawWanderStuff(PVector location, PVector circle, PVector target, float rad) { - stroke(0); + stroke(0); noFill(); ellipseMode(CENTER); ellipse(circle.x,circle.y,rad*2,rad*2); diff --git a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde index 60460740d..aec7e814f 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/Exercise_6_09_AngleBetween/Exercise_6_09_AngleBetween.pde @@ -15,7 +15,7 @@ void draw() { // A "vector" (really a point) to store the mouse location and screen center location PVector mouseLoc = new PVector(mouseX, mouseY); - PVector centerLoc = new PVector(width/2, height/2); + PVector centerLoc = new PVector(width/2, height/2); // Aha, a vector to store the displacement between the mouse and center PVector v = PVector.sub(mouseLoc, centerLoc); @@ -43,10 +43,10 @@ void drawVector(PVector v, PVector loc, float scayl) { stroke(0); strokeWeight(2); // Call vector heading function to get direction (pointing up is a heading of 0) - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; - // Draw three lines to make an arrow + // Draw three lines to make an arrow line(0, 0, len, 0); line(len, 0, len-arrowsize, +arrowsize/2); line(len, 0, len-arrowsize, -arrowsize/2); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde index 1f3350be5..f06b2d10f 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/NOC_6_01_Seek.pde @@ -12,9 +12,8 @@ Vehicle v; void setup() { - size(800, 200); + size(640, 360); v = new Vehicle(width/2, height/2); - smooth(); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde index 722879b31..dfb311c92 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek/Vehicle.pde @@ -7,7 +7,7 @@ // The "Vehicle" class class Vehicle { - + PVector location; PVector velocity; PVector acceleration; @@ -44,20 +44,20 @@ class Vehicle { // STEER = DESIRED MINUS VELOCITY void seek(PVector target) { PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target - + // Normalize desired and scale to maximum speed desired.normalize(); desired.mult(maxspeed); // Steering = Desired minus velocity PVector steer = PVector.sub(desired,velocity); steer.limit(maxforce); // Limit to maximum steering force - + applyForce(steer); } - + void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(127); stroke(0); strokeWeight(1); @@ -70,8 +70,8 @@ class Vehicle { vertex(r, r*2); endShape(CLOSE); popMatrix(); - - + + } } diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde index f8f81e829..d0b33d652 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_01_Seek_trail/Vehicle.pde @@ -32,7 +32,7 @@ class Vehicle { location.add(velocity); // Reset accelerationelertion to 0 each cycle acceleration.mult(0); - + history.add(location.get()); if (history.size() > 100) { history.remove(0); @@ -48,17 +48,17 @@ class Vehicle { // STEER = DESIRED MINUS VELOCITY void seek(PVector target) { PVector desired = PVector.sub(target,location); // A vector pointing from the location to the target - + // Normalize desired and scale to maximum speed desired.normalize(); desired.mult(maxspeed); // Steering = Desired minus velocity PVector steer = PVector.sub(desired,velocity); steer.limit(maxforce); // Limit to maximum steering force - + applyForce(steer); } - + void display() { beginShape(); stroke(0); @@ -68,10 +68,10 @@ class Vehicle { vertex(v.x,v.y); } endShape(); - - + + // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(127); stroke(0); strokeWeight(1); @@ -84,8 +84,8 @@ class Vehicle { vertex(r, r*2); endShape(CLOSE); popMatrix(); - - + + } } diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde index 1267fb8ec..bd445d818 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.pde @@ -8,9 +8,8 @@ Vehicle v; void setup() { - size(800, 200); + size(640, 360); v = new Vehicle(width/2, height/2); - smooth(); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde index 512b357d1..72fe089b8 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_02_Arrive/Vehicle.pde @@ -5,7 +5,7 @@ // The "Vehicle" class class Vehicle { - + PVector location; PVector velocity; PVector acceleration; @@ -57,11 +57,11 @@ class Vehicle { steer.limit(maxforce); // Limit to maximum steering force applyForce(steer); } - + void display() { - + // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(127); stroke(0); strokeWeight(1); @@ -74,8 +74,8 @@ class Vehicle { vertex(r, r*2); endShape(CLOSE); popMatrix(); - - + + } } diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde index f815cce9a..9a507181c 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls/Vehicle.pde @@ -13,7 +13,7 @@ class Vehicle { float maxspeed; float maxforce; - + Vehicle(float x, float y) { acceleration = new PVector(0, 0); velocity = new PVector(3, -2); @@ -46,17 +46,17 @@ class Vehicle { if (location.x < d) { desired = new PVector(maxspeed, velocity.y); - } + } else if (location.x > width -d) { desired = new PVector(-maxspeed, velocity.y); - } + } if (location.y < d) { desired = new PVector(velocity.x, maxspeed); - } + } else if (location.y > height-d) { desired = new PVector(velocity.x, -maxspeed); - } + } if (desired != null) { desired.normalize(); @@ -65,7 +65,7 @@ class Vehicle { steer.limit(maxforce); applyForce(steer); } - } + } void applyForce(PVector force) { // We could add mass here if we want A = F / M @@ -75,7 +75,7 @@ class Vehicle { void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(127); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde index 1d9bac9cc..0d94054a4 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_03_StayWithinWalls_trail/Vehicle.pde @@ -14,7 +14,7 @@ class Vehicle { float maxspeed; float maxforce; - + Vehicle(float x, float y) { acceleration = new PVector(0, 0); velocity = new PVector(3, -2); @@ -39,7 +39,7 @@ class Vehicle { location.add(velocity); // Reset accelertion to 0 each cycle acceleration.mult(0); - + history.add(location.get()); if (history.size() > 500) { history.remove(0); @@ -52,17 +52,17 @@ class Vehicle { if (location.x < d) { desired = new PVector(maxspeed, velocity.y); - } + } else if (location.x > width -d) { desired = new PVector(-maxspeed, velocity.y); - } + } if (location.y < d) { desired = new PVector(velocity.x, maxspeed); - } + } else if (location.y > height-d) { desired = new PVector(velocity.x, -maxspeed); - } + } if (desired != null) { desired.normalize(); @@ -71,7 +71,7 @@ class Vehicle { steer.limit(maxforce); applyForce(steer); } - } + } void applyForce(PVector force) { // We could add mass here if we want A = F / M @@ -88,10 +88,10 @@ class Vehicle { vertex(v.x,v.y); } endShape(); - - + + // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(127); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde index b6da8c9d2..75b471b29 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/FlowField.pde @@ -49,7 +49,7 @@ class FlowField { pushMatrix(); //translate(i*resolution+arrow.width/2,j*resolution+arrow.height/2); translate(i*resolution,j*resolution); - rotate(field[i][j].heading()); + rotate(field[i][j].heading2D()); imageMode(CENTER); //scale(0.2); image(a,0,0); @@ -69,7 +69,7 @@ class FlowField { translate(x,y); stroke(0,100); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde index 82484f3ed..2326a1e7c 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flow_Figures/Vehicle.pde @@ -61,7 +61,7 @@ class Vehicle { void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde index fedf64418..08bf7eb23 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/FlowField.pde @@ -54,7 +54,7 @@ class FlowField { translate(x,y); stroke(0,100); // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate - rotate(v.heading()); + rotate(v.heading2D()); // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde index 47ce095df..86a2c4c29 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/NOC_6_04_Flowfield.pde @@ -14,7 +14,7 @@ FlowField flowfield; ArrayList vehicles; void setup() { - size(800, 200); + size(640, 360); // Make a new flow field with "resolution" of 16 flowfield = new FlowField(20); vehicles = new ArrayList(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde index 82484f3ed..2326a1e7c 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/Vehicle.pde @@ -61,7 +61,7 @@ class Vehicle { void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_04_Flowfield/sketch.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde index 7b6387c31..23a53710a 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/NOC_6_05_PathFollowingSimple.pde @@ -17,7 +17,7 @@ Vehicle car1; Vehicle car2; void setup() { - size(800, 200); + size(640, 360); path = new Path(); // Each vehicle has different maxspeed and maxforce for demo purposes diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde index 4a8fc9e72..109d7d658 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/Vehicle.pde @@ -136,7 +136,7 @@ class Vehicle { void render() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties deleted file mode 100644 index 6d28cd598..000000000 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_05_PathFollowingSimple/sketch.properties +++ /dev/null @@ -1 +0,0 @@ -mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde index 2990a9045..3c1ff9eb9 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/NOC_6_06_PathFollowing.pde @@ -16,7 +16,7 @@ Vehicle car1; Vehicle car2; void setup() { - size(800, 200); + size(640, 360); // Call a function to generate new Path object newPath(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde index 4e7e4c428..b705abaf2 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_06_PathFollowing/Vehicle.pde @@ -167,7 +167,7 @@ class Vehicle { void render() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde index 8f92a4921..d884461f2 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_07_Separation/NOC_6_07_Separation.pde @@ -9,7 +9,7 @@ ArrayList vehicles; void setup() { - size(800,200); + size(640,360); // We are now making random vehicles and storing them in an ArrayList vehicles = new ArrayList(); for (int i = 0; i < 100; i++) { diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde index afdf7f6b4..bc744a1b8 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.pde @@ -6,7 +6,7 @@ ArrayList vehicles; void setup() { - size(800,200); + size(640,360); // We are now making random vehicles and storing them in an ArrayList vehicles = new ArrayList(); for (int i = 0; i < 100; i++) { diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde index b4270972e..bf679b1b2 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/Vehicle.pde @@ -30,7 +30,7 @@ class Vehicle { void applyBehaviors(ArrayList vehicles) { PVector separateForce = separate(vehicles); PVector seekForce = seek(new PVector(mouseX,mouseY)); - separateForce.mult(2); + separateForce.mult(map(mouseX,0,width,0,2)); seekForce.mult(1); applyForce(separateForce); applyForce(seekForce); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties deleted file mode 100644 index 6d28cd598..000000000 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_08_SeparationAndSeek/sketch.properties +++ /dev/null @@ -1 +0,0 @@ -mode=JavaScript diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde index ddde2f204..194dfc362 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/Boid.pde @@ -73,10 +73,10 @@ class Boid { steer.limit(maxforce); // Limit to maximum steering force return steer; } - + void render() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde index f7d8cf42f..921f0d250 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/NOC_6_09_Flocking/NOC_6_09_Flocking.pde @@ -11,7 +11,7 @@ Flock flock; void setup() { - size(800,200); + size(640,360); flock = new Flock(); // Add an initial set of boids into the system for (int i = 0; i < 200; i++) { diff --git a/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde index d05cfda0d..7bc96d2fa 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/StayWithinCircle/Vehicle.pde @@ -11,7 +11,7 @@ class Vehicle { float maxspeed; float maxforce; - + Vehicle(float x, float y) { acceleration = new PVector(0, 0); velocity = new PVector(1,0); @@ -41,13 +41,13 @@ class Vehicle { void boundaries() { PVector desired = null; - + // Predict location 25 (arbitrary choice) frames ahead PVector predict = velocity.get(); predict.mult(25); PVector futureLocation = PVector.add(location, predict); float distance = PVector.dist(futureLocation,circleLocation); - + if (distance > circleRadius) { PVector toCenter = PVector.sub(circleLocation,location); toCenter.normalize(); @@ -62,11 +62,11 @@ class Vehicle { steer.limit(maxforce); applyForce(steer); } - + fill(255,0,0); ellipse(futureLocation.x,futureLocation.y,4,4); - - } + + } void applyForce(PVector force) { // We could add mass here if we want A = F / M @@ -76,7 +76,7 @@ class Vehicle { void display() { // Draw a triangle rotated in the direction of velocity - float theta = velocity.heading() + radians(90); + float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde index dec740f1f..808b7c6d5 100644 --- a/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde +++ b/java/examples/Books/Nature of Code/chp6_agents/flocking_sliders/Boid.pde @@ -82,10 +82,10 @@ class Boid { return steer; } - + void render() { // Draw a triangle rotated in the direction of velocity - float theta = vel.heading() + radians(90); + float theta = vel.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde index a0d0ee3f2..32227dd01 100644 --- a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeOOP/NOC_7_02_GameOfLifeOOP.pde @@ -9,7 +9,7 @@ GOL gol; void setup() { - size(400, 400); + size(640, 360); gol = new GOL(); } diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeSimple/GOL.pde similarity index 100% rename from java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/GOL.pde rename to java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeSimple/GOL.pde diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeSimple/NOC_7_02_GameOfLifeSimple.pde similarity index 96% rename from java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde rename to java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeSimple/NOC_7_02_GameOfLifeSimple.pde index 29d9843c7..bc4d80511 100644 --- a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeSimple/NOC_7_03_GameOfLifeSimple.pde +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_02_GameOfLifeSimple/NOC_7_02_GameOfLifeSimple.pde @@ -11,7 +11,7 @@ GOL gol; void setup() { - size(400, 400); + size(640, 360); gol = new GOL(); } diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/Cell.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/Cell.pde new file mode 100644 index 000000000..d18e16933 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/Cell.pde @@ -0,0 +1,40 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class Cell { + + float x, y; + float w; + + int state; + int previous; + + Cell(float x_, float y_, float w_) { + x = x_; + y = y_; + w = w_; + + state = int(random(2)); + previous = state; + } + + void savePrevious() { + previous = state; + } + + void newState(int s) { + state = s; + } + + void display() { + if (previous == 0 && state == 1) fill(0,0,255); + else if (state == 1) fill(0); + else if (previous == 1 && state == 0) fill(255,0,0); + else fill(255); + stroke(0); + rect(x, y, w, w); + } +} + + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/GOL.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/GOL.pde new file mode 100644 index 000000000..cdf3f3ad2 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/GOL.pde @@ -0,0 +1,73 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +class GOL { + + int w = 8; + int columns, rows; + + // Game of life board + Cell[][] board; + + + GOL() { + // Initialize rows, columns and set-up arrays + columns = width/w; + rows = height/w; + board = new Cell[columns][rows]; + init(); + } + + void init() { + for (int i = 0; i < columns; i++) { + for (int j = 0; j < rows; j++) { + board[i][j] = new Cell(i*w, j*w, w); + } + } + } + + // The process of creating the new generation + void generate() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].savePrevious(); + } + } + + + // Loop through every spot in our 2D array and check spots neighbors + for (int x = 0; x < columns; x++) { + for (int y = 0; y < rows; y++) { + + // Add up all the states in a 3x3 surrounding grid + int neighbors = 0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + neighbors += board[(x+i+columns)%columns][(y+j+rows)%rows].previous; + } + } + + // A little trick to subtract the current cell's state since + // we added it in the above loop + neighbors -= board[x][y].previous; + + // Rules of Life + if ((board[x][y].state == 1) && (neighbors < 2)) board[x][y].newState(0); // Loneliness + else if ((board[x][y].state == 1) && (neighbors > 3)) board[x][y].newState(0); // Overpopulation + else if ((board[x][y].state == 0) && (neighbors == 3)) board[x][y].newState(1); // Reproduction + // else do nothing! + } + } + } + + // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0' + void display() { + for ( int i = 0; i < columns;i++) { + for ( int j = 0; j < rows;j++) { + board[i][j].display(); + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/NOC_7_03_GameOfLifeOOP.pde b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/NOC_7_03_GameOfLifeOOP.pde new file mode 100644 index 000000000..32227dd01 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp7_CA/NOC_7_03_GameOfLifeOOP/NOC_7_03_GameOfLifeOOP.pde @@ -0,0 +1,27 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A basic implementation of John Conway's Game of Life CA + +// Each cell is now an object! + +GOL gol; + +void setup() { + size(640, 360); + gol = new GOL(); +} + +void draw() { + background(255); + + gol.generate(); + gol.display(); +} + +// reset board when mouse is pressed +void mousePressed() { + gol.init(); +} + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde index 9cfe2e706..84b600182 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.pde @@ -5,8 +5,7 @@ // Simple Recursion void setup() { - size(800,200); - smooth(); + size(640,360); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde index d6082e9a8..b02eda5fe 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.pde @@ -5,7 +5,7 @@ // Simple Recursion void setup() { - size(800,200); + size(640,360); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde deleted file mode 100644 index a2caee41c..000000000 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/KochLine.pde +++ /dev/null @@ -1,72 +0,0 @@ -// The Nature of Code -// Daniel Shiffman -// http://natureofcode.com - -// A class to describe one line segment in the fractal -// Includes methods to calculate midPVectors along the line according to the Koch algorithm - -class KochLine { - - // Two PVectors, - // a is the "left" PVector and - // b is the "right PVector - PVector start; - PVector end; - - KochLine(PVector a, PVector b) { - start = a.get(); - end = b.get(); - } - - void display() { - stroke(0); - line(start.x, start.y, end.x, end.y); - } - - PVector kochA() { - return start.get(); - } - - - // This is easy, just 1/3 of the way - PVector kochB() { - PVector v = PVector.sub(end, start); - v.div(3); - v.add(start); - return v; - } - - // More complicated, have to use a little trig to figure out where this PVector is! - PVector kochC() { - PVector a = start.get(); // Start at the beginning - - PVector v = PVector.sub(end, start); - v.div(3); - a.add(v); // Move to point B - - rotate(v, -radians(60)); // Rotate 60 degrees - a.add(v); // Move to point C - - return a; - } - - // Easy, just 2/3 of the way - PVector kochD() { - PVector v = PVector.sub(end, start); - v.mult(2/3.0); - v.add(start); - return v; - } - - PVector kochE() { - return end.get(); - } -} - -public void rotate(PVector v, float theta) { - float xTemp = v.x; - // Might need to check for rounding errors like with angleBetween function? - v.x = v.x*PApplet.cos(theta) - v.y*PApplet.sin(theta); - v.y = xTemp*PApplet.sin(theta) + v.y*PApplet.cos(theta); -} - diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde deleted file mode 100644 index 9b9f8be19..000000000 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_KochSimple/NOC_8_03_KochSimple.pde +++ /dev/null @@ -1,51 +0,0 @@ -// The Nature of Code -// Daniel Shiffman -// http://natureofcode.com - -// Koch Curve -// Renders a simple fractal, the Koch snowflake -// Each recursive level drawn in sequence - -ArrayList lines ; // A list to keep track of all the lines - -void setup() { - size(600, 300); - background(255); - lines = new ArrayList(); - PVector start = new PVector(0, 200); - PVector end = new PVector(width, 200); - lines.add(new KochLine(start, end)); - - for (int i = 0; i < 5; i++) { - generate(); - } - - smooth(); -} - -void draw() { - background(255); - for (KochLine l : lines) { - l.display(); - } -} - -void generate() { - ArrayList next = new ArrayList(); // Create emtpy list - for (KochLine l : lines) { - // Calculate 5 koch PVectors (done for us by the line object) - PVector a = l.kochA(); - PVector b = l.kochB(); - PVector c = l.kochC(); - PVector d = l.kochD(); - PVector e = l.kochE(); - // Make line segments between all the PVectors and add them - next.add(new KochLine(a, b)); - next.add(new KochLine(b, c)); - next.add(new KochLine(c, d)); - next.add(new KochLine(d, e)); - } - lines = next; -} - - diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde index b0e5834ed..c7257d242 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.pde @@ -5,7 +5,7 @@ // Simple Recursion void setup() { - size(800, 200); + size(640, 360); } void draw() { diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties index 140966b6e..8630fa24a 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/sketch.properties @@ -1,2 +1,2 @@ -mode.id=processing.mode.javascript.JavaScriptMode -mode=JavaScript +mode.id=processing.mode.java.JavaMode +mode=Java diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde new file mode 100644 index 000000000..63e0a2023 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde @@ -0,0 +1,176 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com +// Koch Curve + +// Renders a simple fractal, the Koch snowflake +// Each recursive level drawn in sequence + +KochFractal k; + +void setup() { + size(800,250); + background(255); + frameRate(1); // Animate slowly + k = new KochFractal(); + smooth(); +} + +void draw() { + background(255); + // Draws the snowflake! + k.render(); + // Iterate + k.nextLevel(); + // Let's not do it more than 5 times. . . + if (k.getCount() > 5) { + k.restart(); + } +} + +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to manage the list of line segments in the snowflake pattern + +class KochFractal { + PVector start; // A PVector for the start + PVector end; // A PVector for the end + ArrayList lines; // A list to keep track of all the lines + int count; + + public KochFractal() { + start = new PVector(0,height-20); + end = new PVector(width,height-20); + lines = new ArrayList(); + restart(); + } + + void nextLevel() { + // For every line that is in the arraylist + // create 4 more lines in a new arraylist + lines = iterate(lines); + count++; + } + + void restart() { + count = 0; // Reset count + lines.clear(); // Empty the array list + lines.add(new KochLine(start,end)); // Add the initial line (from one end PVector to the other) + } + + int getCount() { + return count; + } + + // This is easy, just draw all the lines + void render() { + for(KochLine l : lines) { + l.display(); + } + } + + // This is where the **MAGIC** happens + // Step 1: Create an empty arraylist + // Step 2: For every line currently in the arraylist + // - calculate 4 line segments based on Koch algorithm + // - add all 4 line segments into the new arraylist + // Step 3: Return the new arraylist and it becomes the list of line segments for the structure + + // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . + ArrayList iterate(ArrayList before) { + ArrayList now = new ArrayList(); // Create emtpy list + for(KochLine l : before) { + // Calculate 5 koch PVectors (done for us by the line object) + PVector a = l.start(); + PVector b = l.kochleft(); + PVector c = l.kochmiddle(); + PVector d = l.kochright(); + PVector e = l.end(); + // Make line segments between all the PVectors and add them + now.add(new KochLine(a,b)); + now.add(new KochLine(b,c)); + now.add(new KochLine(c,d)); + now.add(new KochLine(d,e)); + } + return now; + } + +} +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Koch Curve +// A class to describe one line segment in the fractal +// Includes methods to calculate midPVectors along the line according to the Koch algorithm + +class KochLine { + + // Two PVectors, + // a is the "left" PVector and + // b is the "right PVector + PVector a; + PVector b; + + KochLine(PVector start, PVector end) { + a = start.get(); + b = end.get(); + } + + void display() { + stroke(0); + line(a.x, a.y, b.x, b.y); + } + + PVector start() { + return a.get(); + } + + PVector end() { + return b.get(); + } + + // This is easy, just 1/3 of the way + PVector kochleft() { + PVector v = PVector.sub(b, a); + v.div(3); + v.add(a); + return v; + } + + // More complicated, have to use a little trig to figure out where this PVector is! + PVector kochmiddle() { + PVector v = PVector.sub(b, a); + v.div(3); + + PVector p = a.get(); + p.add(v); + + rotate(v,-radians(60)); + p.add(v); + + return p; + } + + + // Easy, just 2/3 of the way + PVector kochright() { + PVector v = PVector.sub(a, b); + v.div(3); + v.add(b); + return v; + } +} + + public void rotate(PVector v, float theta) { + float xTemp = v.x; + // Might need to check for rounding errors like with angleBetween function? + v.x = v.x*cos(theta) - v.y*sin(theta); + v.y = xTemp*sin(theta) + v.y*cos(theta); + } + + + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js new file mode 100644 index 000000000..d9b41d7b1 --- /dev/null +++ b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js @@ -0,0 +1,10203 @@ +/*** + + P R O C E S S I N G . J S - 1.4.1 + a port of the Processing visualization language + + Processing.js is licensed under the MIT License, see LICENSE. + For a list of copyright holders, please refer to AUTHORS. + + http://processingjs.org + +***/ + +(function(window, document, Math, undef) { + var nop = function() {}; + var debug = function() { + if ("console" in window) return function(msg) { + window.console.log("Processing.js: " + msg) + }; + return nop + }(); + var ajax = function(url) { + var xhr = new XMLHttpRequest; + xhr.open("GET", url, false); + if (xhr.overrideMimeType) xhr.overrideMimeType("text/plain"); + xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); + xhr.send(null); + if (xhr.status !== 200 && xhr.status !== 0) throw "XMLHttpRequest failed, status code " + xhr.status; + return xhr.responseText + }; + var isDOMPresent = "document" in this && !("fake" in this.document); + document.head = document.head || document.getElementsByTagName("head")[0]; + + function setupTypedArray(name, fallback) { + if (name in window) return window[name]; + if (typeof window[fallback] === "function") return window[fallback]; + return function(obj) { + if (obj instanceof Array) return obj; + if (typeof obj === "number") { + var arr = []; + arr.length = obj; + return arr + } + } + } + if (document.documentMode >= 9 && !document.doctype) throw "The doctype directive is missing. The recommended doctype in Internet Explorer is the HTML5 doctype: "; + var Float32Array = setupTypedArray("Float32Array", "WebGLFloatArray"), + Int32Array = setupTypedArray("Int32Array", "WebGLIntArray"), + Uint16Array = setupTypedArray("Uint16Array", "WebGLUnsignedShortArray"), + Uint8Array = setupTypedArray("Uint8Array", "WebGLUnsignedByteArray"); + var PConstants = { + X: 0, + Y: 1, + Z: 2, + R: 3, + G: 4, + B: 5, + A: 6, + U: 7, + V: 8, + NX: 9, + NY: 10, + NZ: 11, + EDGE: 12, + SR: 13, + SG: 14, + SB: 15, + SA: 16, + SW: 17, + TX: 18, + TY: 19, + TZ: 20, + VX: 21, + VY: 22, + VZ: 23, + VW: 24, + AR: 25, + AG: 26, + AB: 27, + DR: 3, + DG: 4, + DB: 5, + DA: 6, + SPR: 28, + SPG: 29, + SPB: 30, + SHINE: 31, + ER: 32, + EG: 33, + EB: 34, + BEEN_LIT: 35, + VERTEX_FIELD_COUNT: 36, + P2D: 1, + JAVA2D: 1, + WEBGL: 2, + P3D: 2, + OPENGL: 2, + PDF: 0, + DXF: 0, + OTHER: 0, + WINDOWS: 1, + MAXOSX: 2, + LINUX: 3, + EPSILON: 1.0E-4, + MAX_FLOAT: 3.4028235E38, + MIN_FLOAT: -3.4028235E38, + MAX_INT: 2147483647, + MIN_INT: -2147483648, + PI: Math.PI, + TWO_PI: 2 * Math.PI, + HALF_PI: Math.PI / 2, + THIRD_PI: Math.PI / 3, + QUARTER_PI: Math.PI / 4, + DEG_TO_RAD: Math.PI / 180, + RAD_TO_DEG: 180 / Math.PI, + WHITESPACE: " \t\n\r\u000c\u00a0", + RGB: 1, + ARGB: 2, + HSB: 3, + ALPHA: 4, + CMYK: 5, + TIFF: 0, + TARGA: 1, + JPEG: 2, + GIF: 3, + BLUR: 11, + GRAY: 12, + INVERT: 13, + OPAQUE: 14, + POSTERIZE: 15, + THRESHOLD: 16, + ERODE: 17, + DILATE: 18, + REPLACE: 0, + BLEND: 1 << 0, + ADD: 1 << 1, + SUBTRACT: 1 << 2, + LIGHTEST: 1 << 3, + DARKEST: 1 << 4, + DIFFERENCE: 1 << 5, + EXCLUSION: 1 << 6, + MULTIPLY: 1 << 7, + SCREEN: 1 << 8, + OVERLAY: 1 << 9, + HARD_LIGHT: 1 << 10, + SOFT_LIGHT: 1 << 11, + DODGE: 1 << 12, + BURN: 1 << 13, + ALPHA_MASK: 4278190080, + RED_MASK: 16711680, + GREEN_MASK: 65280, + BLUE_MASK: 255, + CUSTOM: 0, + ORTHOGRAPHIC: 2, + PERSPECTIVE: 3, + POINT: 2, + POINTS: 2, + LINE: 4, + LINES: 4, + TRIANGLE: 8, + TRIANGLES: 9, + TRIANGLE_STRIP: 10, + TRIANGLE_FAN: 11, + QUAD: 16, + QUADS: 16, + QUAD_STRIP: 17, + POLYGON: 20, + PATH: 21, + RECT: 30, + ELLIPSE: 31, + ARC: 32, + SPHERE: 40, + BOX: 41, + GROUP: 0, + PRIMITIVE: 1, + GEOMETRY: 3, + VERTEX: 0, + BEZIER_VERTEX: 1, + CURVE_VERTEX: 2, + BREAK: 3, + CLOSESHAPE: 4, + OPEN: 1, + CLOSE: 2, + CORNER: 0, + CORNERS: 1, + RADIUS: 2, + CENTER_RADIUS: 2, + CENTER: 3, + DIAMETER: 3, + CENTER_DIAMETER: 3, + BASELINE: 0, + TOP: 101, + BOTTOM: 102, + NORMAL: 1, + NORMALIZED: 1, + IMAGE: 2, + MODEL: 4, + SHAPE: 5, + SQUARE: "butt", + ROUND: "round", + PROJECT: "square", + MITER: "miter", + BEVEL: "bevel", + AMBIENT: 0, + DIRECTIONAL: 1, + SPOT: 3, + BACKSPACE: 8, + TAB: 9, + ENTER: 10, + RETURN: 13, + ESC: 27, + DELETE: 127, + CODED: 65535, + SHIFT: 16, + CONTROL: 17, + ALT: 18, + CAPSLK: 20, + PGUP: 33, + PGDN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + NUMLK: 144, + META: 157, + INSERT: 155, + ARROW: "default", + CROSS: "crosshair", + HAND: "pointer", + MOVE: "move", + TEXT: "text", + WAIT: "wait", + NOCURSOR: "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto", + DISABLE_OPENGL_2X_SMOOTH: 1, + ENABLE_OPENGL_2X_SMOOTH: -1, + ENABLE_OPENGL_4X_SMOOTH: 2, + ENABLE_NATIVE_FONTS: 3, + DISABLE_DEPTH_TEST: 4, + ENABLE_DEPTH_TEST: -4, + ENABLE_DEPTH_SORT: 5, + DISABLE_DEPTH_SORT: -5, + DISABLE_OPENGL_ERROR_REPORT: 6, + ENABLE_OPENGL_ERROR_REPORT: -6, + ENABLE_ACCURATE_TEXTURES: 7, + DISABLE_ACCURATE_TEXTURES: -7, + HINT_COUNT: 10, + SINCOS_LENGTH: 720, + PRECISIONB: 15, + PRECISIONF: 1 << 15, + PREC_MAXVAL: (1 << 15) - 1, + PREC_ALPHA_SHIFT: 24 - 15, + PREC_RED_SHIFT: 16 - 15, + NORMAL_MODE_AUTO: 0, + NORMAL_MODE_SHAPE: 1, + NORMAL_MODE_VERTEX: 2, + MAX_LIGHTS: 8 + }; + + function virtHashCode(obj) { + if (typeof obj === "string") { + var hash = 0; + for (var i = 0; i < obj.length; ++i) hash = hash * 31 + obj.charCodeAt(i) & 4294967295; + return hash + } + if (typeof obj !== "object") return obj & 4294967295; + if (obj.hashCode instanceof Function) return obj.hashCode(); + if (obj.$id === undef) obj.$id = Math.floor(Math.random() * 65536) - 32768 << 16 | Math.floor(Math.random() * 65536); + return obj.$id + } + function virtEquals(obj, other) { + if (obj === null || other === null) return obj === null && other === null; + if (typeof obj === "string") return obj === other; + if (typeof obj !== "object") return obj === other; + if (obj.equals instanceof Function) return obj.equals(other); + return obj === other + } + var ObjectIterator = function(obj) { + if (obj.iterator instanceof + Function) return obj.iterator(); + if (obj instanceof Array) { + var index = -1; + this.hasNext = function() { + return ++index < obj.length + }; + this.next = function() { + return obj[index] + } + } else throw "Unable to iterate: " + obj; + }; + var ArrayList = function() { + function Iterator(array) { + var index = 0; + this.hasNext = function() { + return index < array.length + }; + this.next = function() { + return array[index++] + }; + this.remove = function() { + array.splice(index, 1) + } + } + function ArrayList(a) { + var array; + if (a instanceof ArrayList) array = a.toArray(); + else { + array = []; + if (typeof a === "number") array.length = a > 0 ? a : 0 + } + this.get = function(i) { + return array[i] + }; + this.contains = function(item) { + return this.indexOf(item) > -1 + }; + this.indexOf = function(item) { + for (var i = 0, len = array.length; i < len; ++i) if (virtEquals(item, array[i])) return i; + return -1 + }; + this.lastIndexOf = function(item) { + for (var i = array.length - 1; i >= 0; --i) if (virtEquals(item, array[i])) return i; + return -1 + }; + this.add = function() { + if (arguments.length === 1) array.push(arguments[0]); + else if (arguments.length === 2) { + var arg0 = arguments[0]; + if (typeof arg0 === "number") if (arg0 >= 0 && arg0 <= array.length) array.splice(arg0, 0, arguments[1]); + else throw arg0 + " is not a valid index"; + else throw typeof arg0 + " is not a number"; + } else throw "Please use the proper number of parameters."; + }; + this.addAll = function(arg1, arg2) { + var it; + if (typeof arg1 === "number") { + if (arg1 < 0 || arg1 > array.length) throw "Index out of bounds for addAll: " + arg1 + " greater or equal than " + array.length; + it = new ObjectIterator(arg2); + while (it.hasNext()) array.splice(arg1++, 0, it.next()) + } else { + it = new ObjectIterator(arg1); + while (it.hasNext()) array.push(it.next()) + } + }; + this.set = function() { + if (arguments.length === 2) { + var arg0 = arguments[0]; + if (typeof arg0 === "number") if (arg0 >= 0 && arg0 < array.length) array.splice(arg0, 1, arguments[1]); + else throw arg0 + " is not a valid index."; + else throw typeof arg0 + " is not a number"; + } else throw "Please use the proper number of parameters."; + }; + this.size = function() { + return array.length + }; + this.clear = function() { + array.length = 0 + }; + this.remove = function(item) { + if (typeof item === "number") return array.splice(item, 1)[0]; + item = this.indexOf(item); + if (item > -1) { + array.splice(item, 1); + return true + } + return false + }; + this.removeAll = function(c) { + var i, x, item, newList = new ArrayList; + newList.addAll(this); + this.clear(); + for (i = 0, x = 0; i < newList.size(); i++) { + item = newList.get(i); + if (!c.contains(item)) this.add(x++, item) + } + if (this.size() < newList.size()) return true; + return false + }; + this.isEmpty = function() { + return !array.length + }; + this.clone = function() { + return new ArrayList(this) + }; + this.toArray = function() { + return array.slice(0) + }; + this.iterator = function() { + return new Iterator(array) + } + } + return ArrayList + }(); + var HashMap = function() { + function HashMap() { + if (arguments.length === 1 && arguments[0] instanceof HashMap) return arguments[0].clone(); + var initialCapacity = arguments.length > 0 ? arguments[0] : 16; + var loadFactor = arguments.length > 1 ? arguments[1] : 0.75; + var buckets = []; + buckets.length = initialCapacity; + var count = 0; + var hashMap = this; + + function getBucketIndex(key) { + var index = virtHashCode(key) % buckets.length; + return index < 0 ? buckets.length + index : index + } + function ensureLoad() { + if (count <= loadFactor * buckets.length) return; + var allEntries = []; + for (var i = 0; i < buckets.length; ++i) if (buckets[i] !== undef) allEntries = allEntries.concat(buckets[i]); + var newBucketsLength = buckets.length * 2; + buckets = []; + buckets.length = newBucketsLength; + for (var j = 0; j < allEntries.length; ++j) { + var index = getBucketIndex(allEntries[j].key); + var bucket = buckets[index]; + if (bucket === undef) buckets[index] = bucket = []; + bucket.push(allEntries[j]) + } + } + function Iterator(conversion, removeItem) { + var bucketIndex = 0; + var itemIndex = -1; + var endOfBuckets = false; + var currentItem; + + function findNext() { + while (!endOfBuckets) { + ++itemIndex; + if (bucketIndex >= buckets.length) endOfBuckets = true; + else if (buckets[bucketIndex] === undef || itemIndex >= buckets[bucketIndex].length) { + itemIndex = -1; + ++bucketIndex + } else return + } + } + this.hasNext = function() { + return !endOfBuckets + }; + this.next = function() { + currentItem = conversion(buckets[bucketIndex][itemIndex]); + findNext(); + return currentItem + }; + this.remove = function() { + if (currentItem !== undef) { + removeItem(currentItem); + --itemIndex; + findNext() + } + }; + findNext() + } + function Set(conversion, isIn, removeItem) { + this.clear = function() { + hashMap.clear() + }; + this.contains = function(o) { + return isIn(o) + }; + this.containsAll = function(o) { + var it = o.iterator(); + while (it.hasNext()) if (!this.contains(it.next())) return false; + return true + }; + this.isEmpty = function() { + return hashMap.isEmpty() + }; + this.iterator = function() { + return new Iterator(conversion, removeItem) + }; + this.remove = function(o) { + if (this.contains(o)) { + removeItem(o); + return true + } + return false + }; + this.removeAll = function(c) { + var it = c.iterator(); + var changed = false; + while (it.hasNext()) { + var item = it.next(); + if (this.contains(item)) { + removeItem(item); + changed = true + } + } + return true + }; + this.retainAll = function(c) { + var it = this.iterator(); + var toRemove = []; + while (it.hasNext()) { + var entry = it.next(); + if (!c.contains(entry)) toRemove.push(entry) + } + for (var i = 0; i < toRemove.length; ++i) removeItem(toRemove[i]); + return toRemove.length > 0 + }; + this.size = function() { + return hashMap.size() + }; + this.toArray = function() { + var result = []; + var it = this.iterator(); + while (it.hasNext()) result.push(it.next()); + return result + } + } + function Entry(pair) { + this._isIn = function(map) { + return map === hashMap && pair.removed === undef + }; + this.equals = function(o) { + return virtEquals(pair.key, o.getKey()) + }; + this.getKey = function() { + return pair.key + }; + this.getValue = function() { + return pair.value + }; + this.hashCode = function(o) { + return virtHashCode(pair.key) + }; + this.setValue = function(value) { + var old = pair.value; + pair.value = value; + return old + } + } + this.clear = function() { + count = 0; + buckets = []; + buckets.length = initialCapacity + }; + this.clone = function() { + var map = new HashMap; + map.putAll(this); + return map + }; + this.containsKey = function(key) { + var index = getBucketIndex(key); + var bucket = buckets[index]; + if (bucket === undef) return false; + for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) return true; + return false + }; + this.containsValue = function(value) { + for (var i = 0; i < buckets.length; ++i) { + var bucket = buckets[i]; + if (bucket === undef) continue; + for (var j = 0; j < bucket.length; ++j) if (virtEquals(bucket[j].value, value)) return true + } + return false + }; + this.entrySet = function() { + return new Set(function(pair) { + return new Entry(pair) + }, + + + function(pair) { + return pair instanceof Entry && pair._isIn(hashMap) + }, + + + function(pair) { + return hashMap.remove(pair.getKey()) + }) + }; + this.get = function(key) { + var index = getBucketIndex(key); + var bucket = buckets[index]; + if (bucket === undef) return null; + for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) return bucket[i].value; + return null + }; + this.isEmpty = function() { + return count === 0 + }; + this.keySet = function() { + return new Set(function(pair) { + return pair.key + }, + + + function(key) { + return hashMap.containsKey(key) + }, + + + function(key) { + return hashMap.remove(key) + }) + }; + this.values = function() { + return new Set(function(pair) { + return pair.value + }, + + + function(value) { + return hashMap.containsValue(value) + }, + + function(value) { + return hashMap.removeByValue(value) + }) + }; + this.put = function(key, value) { + var index = getBucketIndex(key); + var bucket = buckets[index]; + if (bucket === undef) { + ++count; + buckets[index] = [{ + key: key, + value: value + }]; + ensureLoad(); + return null + } + for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) { + var previous = bucket[i].value; + bucket[i].value = value; + return previous + }++count; + bucket.push({ + key: key, + value: value + }); + ensureLoad(); + return null + }; + this.putAll = function(m) { + var it = m.entrySet().iterator(); + while (it.hasNext()) { + var entry = it.next(); + this.put(entry.getKey(), entry.getValue()) + } + }; + this.remove = function(key) { + var index = getBucketIndex(key); + var bucket = buckets[index]; + if (bucket === undef) return null; + for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) { + --count; + var previous = bucket[i].value; + bucket[i].removed = true; + if (bucket.length > 1) bucket.splice(i, 1); + else buckets[index] = undef; + return previous + } + return null + }; + this.removeByValue = function(value) { + var bucket, i, ilen, pair; + for (bucket in buckets) if (buckets.hasOwnProperty(bucket)) for (i = 0, ilen = buckets[bucket].length; i < ilen; i++) { + pair = buckets[bucket][i]; + if (pair.value === value) { + buckets[bucket].splice(i, 1); + return true + } + } + return false + }; + this.size = function() { + return count + } + } + return HashMap + }(); + var PVector = function() { + function PVector(x, y, z) { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0 + } + PVector.dist = function(v1, v2) { + return v1.dist(v2) + }; + PVector.dot = function(v1, v2) { + return v1.dot(v2) + }; + PVector.cross = function(v1, v2) { + return v1.cross(v2) + }; + PVector.angleBetween = function(v1, v2) { + return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag())) + }; + PVector.prototype = { + set: function(v, y, z) { + if (arguments.length === 1) this.set(v.x || v[0] || 0, v.y || v[1] || 0, v.z || v[2] || 0); + else { + this.x = v; + this.y = y; + this.z = z + } + }, + get: function() { + return new PVector(this.x, this.y, this.z) + }, + mag: function() { + var x = this.x, + y = this.y, + z = this.z; + return Math.sqrt(x * x + y * y + z * z) + }, + add: function(v, y, z) { + if (arguments.length === 1) { + this.x += v.x; + this.y += v.y; + this.z += v.z + } else { + this.x += v; + this.y += y; + this.z += z + } + }, + sub: function(v, y, z) { + if (arguments.length === 1) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z + } else { + this.x -= v; + this.y -= y; + this.z -= z + } + }, + mult: function(v) { + if (typeof v === "number") { + this.x *= v; + this.y *= v; + this.z *= v + } else { + this.x *= v.x; + this.y *= v.y; + this.z *= v.z + } + }, + div: function(v) { + if (typeof v === "number") { + this.x /= v; + this.y /= v; + this.z /= v + } else { + this.x /= v.x; + this.y /= v.y; + this.z /= v.z + } + }, + dist: function(v) { + var dx = this.x - v.x, + dy = this.y - v.y, + dz = this.z - v.z; + return Math.sqrt(dx * dx + dy * dy + dz * dz) + }, + dot: function(v, y, z) { + if (arguments.length === 1) return this.x * v.x + this.y * v.y + this.z * v.z; + return this.x * v + this.y * y + this.z * z + }, + cross: function(v) { + var x = this.x, + y = this.y, + z = this.z; + return new PVector(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y) + }, + normalize: function() { + var m = this.mag(); + if (m > 0) this.div(m) + }, + limit: function(high) { + if (this.mag() > high) { + this.normalize(); + this.mult(high) + } + }, + heading2D: function() { + return -Math.atan2(-this.y, this.x) + }, + toString: function() { + return "[" + this.x + ", " + this.y + ", " + this.z + "]" + }, + array: function() { + return [this.x, this.y, this.z] + } + }; + + function createPVectorMethod(method) { + return function(v1, v2) { + var v = v1.get(); + v[method](v2); + return v + } + } + for (var method in PVector.prototype) if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) PVector[method] = createPVectorMethod(method); + return PVector + }(); + + function DefaultScope() {} + DefaultScope.prototype = PConstants; + var defaultScope = new DefaultScope; + defaultScope.ArrayList = ArrayList; + defaultScope.HashMap = HashMap; + defaultScope.PVector = PVector; + defaultScope.ObjectIterator = ObjectIterator; + defaultScope.PConstants = PConstants; + defaultScope.defineProperty = function(obj, name, desc) { + if ("defineProperty" in Object) Object.defineProperty(obj, name, desc); + else { + if (desc.hasOwnProperty("get")) obj.__defineGetter__(name, desc.get); + if (desc.hasOwnProperty("set")) obj.__defineSetter__(name, desc.set) + } + }; + + function overloadBaseClassFunction(object, name, basefn) { + if (!object.hasOwnProperty(name) || typeof object[name] !== "function") { + object[name] = basefn; + return + } + var fn = object[name]; + if ("$overloads" in fn) { + fn.$defaultOverload = basefn; + return + } + if (! ("$overloads" in basefn) && fn.length === basefn.length) return; + var overloads, defaultOverload; + if ("$overloads" in basefn) { + overloads = basefn.$overloads.slice(0); + overloads[fn.length] = fn; + defaultOverload = basefn.$defaultOverload + } else { + overloads = []; + overloads[basefn.length] = basefn; + overloads[fn.length] = fn; + defaultOverload = fn + } + var hubfn = function() { + var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$methodArgsIndex] : null) || hubfn.$defaultOverload; + return fn.apply(this, arguments) + }; + hubfn.$overloads = overloads; + if ("$methodArgsIndex" in basefn) hubfn.$methodArgsIndex = basefn.$methodArgsIndex; + hubfn.$defaultOverload = defaultOverload; + hubfn.name = name; + object[name] = hubfn + } + function extendClass(subClass, baseClass) { + function extendGetterSetter(propertyName) { + defaultScope.defineProperty(subClass, propertyName, { + get: function() { + return baseClass[propertyName] + }, + set: function(v) { + baseClass[propertyName] = v + }, + enumerable: true + }) + } + var properties = []; + for (var propertyName in baseClass) if (typeof baseClass[propertyName] === "function") overloadBaseClassFunction(subClass, propertyName, baseClass[propertyName]); + else if (propertyName.charAt(0) !== "$" && !(propertyName in subClass)) properties.push(propertyName); + while (properties.length > 0) extendGetterSetter(properties.shift()); + subClass.$super = baseClass + } + defaultScope.extendClassChain = function(base) { + var path = [base]; + for (var self = base.$upcast; self; self = self.$upcast) { + extendClass(self, base); + path.push(self); + base = self + } + while (path.length > 0) path.pop().$self = base + }; + defaultScope.extendStaticMembers = function(derived, base) { + extendClass(derived, base) + }; + defaultScope.extendInterfaceMembers = function(derived, base) { + extendClass(derived, base) + }; + defaultScope.addMethod = function(object, name, fn, hasMethodArgs) { + var existingfn = object[name]; + if (existingfn || hasMethodArgs) { + var args = fn.length; + if ("$overloads" in existingfn) existingfn.$overloads[args] = fn; + else { + var hubfn = function() { + var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$methodArgsIndex] : null) || hubfn.$defaultOverload; + return fn.apply(this, arguments) + }; + var overloads = []; + if (existingfn) overloads[existingfn.length] = existingfn; + overloads[args] = fn; + hubfn.$overloads = overloads; + hubfn.$defaultOverload = existingfn || fn; + if (hasMethodArgs) hubfn.$methodArgsIndex = args; + hubfn.name = name; + object[name] = hubfn + } + } else object[name] = fn + }; + + function isNumericalJavaType(type) { + if (typeof type !== "string") return false; + return ["byte", "int", "char", "color", "float", "long", "double"].indexOf(type) !== -1 + } + defaultScope.createJavaArray = function(type, bounds) { + var result = null, + defaultValue = null; + if (typeof type === "string") if (type === "boolean") defaultValue = false; + else if (isNumericalJavaType(type)) defaultValue = 0; + if (typeof bounds[0] === "number") { + var itemsCount = 0 | bounds[0]; + if (bounds.length <= 1) { + result = []; + result.length = itemsCount; + for (var i = 0; i < itemsCount; ++i) result[i] = defaultValue + } else { + result = []; + var newBounds = bounds.slice(1); + for (var j = 0; j < itemsCount; ++j) result.push(defaultScope.createJavaArray(type, newBounds)) + } + } + return result + }; + var colors = { + aliceblue: "#f0f8ff", + antiquewhite: "#faebd7", + aqua: "#00ffff", + aquamarine: "#7fffd4", + azure: "#f0ffff", + beige: "#f5f5dc", + bisque: "#ffe4c4", + black: "#000000", + blanchedalmond: "#ffebcd", + blue: "#0000ff", + blueviolet: "#8a2be2", + brown: "#a52a2a", + burlywood: "#deb887", + cadetblue: "#5f9ea0", + chartreuse: "#7fff00", + chocolate: "#d2691e", + coral: "#ff7f50", + cornflowerblue: "#6495ed", + cornsilk: "#fff8dc", + crimson: "#dc143c", + cyan: "#00ffff", + darkblue: "#00008b", + darkcyan: "#008b8b", + darkgoldenrod: "#b8860b", + darkgray: "#a9a9a9", + darkgreen: "#006400", + darkkhaki: "#bdb76b", + darkmagenta: "#8b008b", + darkolivegreen: "#556b2f", + darkorange: "#ff8c00", + darkorchid: "#9932cc", + darkred: "#8b0000", + darksalmon: "#e9967a", + darkseagreen: "#8fbc8f", + darkslateblue: "#483d8b", + darkslategray: "#2f4f4f", + darkturquoise: "#00ced1", + darkviolet: "#9400d3", + deeppink: "#ff1493", + deepskyblue: "#00bfff", + dimgray: "#696969", + dodgerblue: "#1e90ff", + firebrick: "#b22222", + floralwhite: "#fffaf0", + forestgreen: "#228b22", + fuchsia: "#ff00ff", + gainsboro: "#dcdcdc", + ghostwhite: "#f8f8ff", + gold: "#ffd700", + goldenrod: "#daa520", + gray: "#808080", + green: "#008000", + greenyellow: "#adff2f", + honeydew: "#f0fff0", + hotpink: "#ff69b4", + indianred: "#cd5c5c", + indigo: "#4b0082", + ivory: "#fffff0", + khaki: "#f0e68c", + lavender: "#e6e6fa", + lavenderblush: "#fff0f5", + lawngreen: "#7cfc00", + lemonchiffon: "#fffacd", + lightblue: "#add8e6", + lightcoral: "#f08080", + lightcyan: "#e0ffff", + lightgoldenrodyellow: "#fafad2", + lightgrey: "#d3d3d3", + lightgreen: "#90ee90", + lightpink: "#ffb6c1", + lightsalmon: "#ffa07a", + lightseagreen: "#20b2aa", + lightskyblue: "#87cefa", + lightslategray: "#778899", + lightsteelblue: "#b0c4de", + lightyellow: "#ffffe0", + lime: "#00ff00", + limegreen: "#32cd32", + linen: "#faf0e6", + magenta: "#ff00ff", + maroon: "#800000", + mediumaquamarine: "#66cdaa", + mediumblue: "#0000cd", + mediumorchid: "#ba55d3", + mediumpurple: "#9370d8", + mediumseagreen: "#3cb371", + mediumslateblue: "#7b68ee", + mediumspringgreen: "#00fa9a", + mediumturquoise: "#48d1cc", + mediumvioletred: "#c71585", + midnightblue: "#191970", + mintcream: "#f5fffa", + mistyrose: "#ffe4e1", + moccasin: "#ffe4b5", + navajowhite: "#ffdead", + navy: "#000080", + oldlace: "#fdf5e6", + olive: "#808000", + olivedrab: "#6b8e23", + orange: "#ffa500", + orangered: "#ff4500", + orchid: "#da70d6", + palegoldenrod: "#eee8aa", + palegreen: "#98fb98", + paleturquoise: "#afeeee", + palevioletred: "#d87093", + papayawhip: "#ffefd5", + peachpuff: "#ffdab9", + peru: "#cd853f", + pink: "#ffc0cb", + plum: "#dda0dd", + powderblue: "#b0e0e6", + purple: "#800080", + red: "#ff0000", + rosybrown: "#bc8f8f", + royalblue: "#4169e1", + saddlebrown: "#8b4513", + salmon: "#fa8072", + sandybrown: "#f4a460", + seagreen: "#2e8b57", + seashell: "#fff5ee", + sienna: "#a0522d", + silver: "#c0c0c0", + skyblue: "#87ceeb", + slateblue: "#6a5acd", + slategray: "#708090", + snow: "#fffafa", + springgreen: "#00ff7f", + steelblue: "#4682b4", + tan: "#d2b48c", + teal: "#008080", + thistle: "#d8bfd8", + tomato: "#ff6347", + turquoise: "#40e0d0", + violet: "#ee82ee", + wheat: "#f5deb3", + white: "#ffffff", + whitesmoke: "#f5f5f5", + yellow: "#ffff00", + yellowgreen: "#9acd32" + }; + (function(Processing) { + var unsupportedP5 = ("open() createOutput() createInput() BufferedReader selectFolder() " + "dataPath() createWriter() selectOutput() beginRecord() " + "saveStream() endRecord() selectInput() saveBytes() createReader() " + "beginRaw() endRaw() PrintWriter delay()").split(" "), + count = unsupportedP5.length, + prettyName, p5Name; + + function createUnsupportedFunc(n) { + return function() { + throw "Processing.js does not support " + n + "."; + } + } + while (count--) { + prettyName = unsupportedP5[count]; + p5Name = prettyName.replace("()", ""); + Processing[p5Name] = createUnsupportedFunc(prettyName) + } + })(defaultScope); + defaultScope.defineProperty(defaultScope, "screenWidth", { + get: function() { + return window.innerWidth + } + }); + defaultScope.defineProperty(defaultScope, "screenHeight", { + get: function() { + return window.innerHeight + } + }); + defaultScope.defineProperty(defaultScope, "online", { + get: function() { + return true + } + }); + var processingInstances = []; + var processingInstanceIds = {}; + var removeInstance = function(id) { + processingInstances.splice(processingInstanceIds[id], 1); + delete processingInstanceIds[id] + }; + var addInstance = function(processing) { + if (processing.externals.canvas.id === undef || !processing.externals.canvas.id.length) processing.externals.canvas.id = "__processing" + processingInstances.length; + processingInstanceIds[processing.externals.canvas.id] = processingInstances.length; + processingInstances.push(processing) + }; + + function computeFontMetrics(pfont) { + var emQuad = 250, + correctionFactor = pfont.size / emQuad, + canvas = document.createElement("canvas"); + canvas.width = 2 * emQuad; + canvas.height = 2 * emQuad; + canvas.style.opacity = 0; + var cfmFont = pfont.getCSSDefinition(emQuad + "px", "normal"), + ctx = canvas.getContext("2d"); + ctx.font = cfmFont; + var protrusions = "dbflkhyjqpg"; + canvas.width = ctx.measureText(protrusions).width; + ctx.font = cfmFont; + var leadDiv = document.createElement("div"); + leadDiv.style.position = "absolute"; + leadDiv.style.opacity = 0; + leadDiv.style.fontFamily = '"' + pfont.name + '"'; + leadDiv.style.fontSize = emQuad + "px"; + leadDiv.innerHTML = protrusions + "
" + protrusions; + document.body.appendChild(leadDiv); + var w = canvas.width, + h = canvas.height, + baseline = h / 2; + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, w, h); + ctx.fillStyle = "black"; + ctx.fillText(protrusions, 0, baseline); + var pixelData = ctx.getImageData(0, 0, w, h).data; + var i = 0, + w4 = w * 4, + len = pixelData.length; + while (++i < len && pixelData[i] === 255) nop(); + var ascent = Math.round(i / w4); + i = len - 1; + while (--i > 0 && pixelData[i] === 255) nop(); + var descent = Math.round(i / w4); + pfont.ascent = correctionFactor * (baseline - ascent); + pfont.descent = correctionFactor * (descent - baseline); + if (document.defaultView.getComputedStyle) { + var leadDivHeight = document.defaultView.getComputedStyle(leadDiv, null).getPropertyValue("height"); + leadDivHeight = correctionFactor * leadDivHeight.replace("px", ""); + if (leadDivHeight >= pfont.size * 2) pfont.leading = Math.round(leadDivHeight / 2) + } + document.body.removeChild(leadDiv); + if (pfont.caching) return ctx + } + function PFont(name, size) { + if (name === undef) name = ""; + this.name = name; + if (size === undef) size = 0; + this.size = size; + this.glyph = false; + this.ascent = 0; + this.descent = 0; + this.leading = 1.2 * size; + var illegalIndicator = name.indexOf(" Italic Bold"); + if (illegalIndicator !== -1) name = name.substring(0, illegalIndicator); + this.style = "normal"; + var italicsIndicator = name.indexOf(" Italic"); + if (italicsIndicator !== -1) { + name = name.substring(0, italicsIndicator); + this.style = "italic" + } + this.weight = "normal"; + var boldIndicator = name.indexOf(" Bold"); + if (boldIndicator !== -1) { + name = name.substring(0, boldIndicator); + this.weight = "bold" + } + this.family = "sans-serif"; + if (name !== undef) switch (name) { + case "sans-serif": + case "serif": + case "monospace": + case "fantasy": + case "cursive": + this.family = name; + break; + default: + this.family = '"' + name + '", sans-serif'; + break + } + this.context2d = computeFontMetrics(this); + this.css = this.getCSSDefinition(); + if (this.context2d) this.context2d.font = this.css + } + PFont.prototype.caching = true; + PFont.prototype.getCSSDefinition = function(fontSize, lineHeight) { + if (fontSize === undef) fontSize = this.size + "px"; + if (lineHeight === undef) lineHeight = this.leading + "px"; + var components = [this.style, "normal", this.weight, fontSize + "/" + lineHeight, this.family]; + return components.join(" ") + }; + PFont.prototype.measureTextWidth = function(string) { + return this.context2d.measureText(string).width + }; + PFont.prototype.measureTextWidthFallback = function(string) { + var canvas = document.createElement("canvas"), + ctx = canvas.getContext("2d"); + ctx.font = this.css; + return ctx.measureText(string).width + }; + PFont.PFontCache = { + length: 0 + }; + PFont.get = function(fontName, fontSize) { + fontSize = (fontSize * 10 + 0.5 | 0) / 10; + var cache = PFont.PFontCache, + idx = fontName + "/" + fontSize; + if (!cache[idx]) { + cache[idx] = new PFont(fontName, fontSize); + cache.length++; + if (cache.length === 50) { + PFont.prototype.measureTextWidth = PFont.prototype.measureTextWidthFallback; + PFont.prototype.caching = false; + var entry; + for (entry in cache) if (entry !== "length") cache[entry].context2d = null; + return new PFont(fontName, fontSize) + } + if (cache.length === 400) { + PFont.PFontCache = {}; + PFont.get = PFont.getFallback; + return new PFont(fontName, fontSize) + } + } + return cache[idx] + }; + PFont.getFallback = function(fontName, fontSize) { + return new PFont(fontName, fontSize) + }; + PFont.list = function() { + return ["sans-serif", "serif", "monospace", "fantasy", "cursive"] + }; + PFont.preloading = { + template: {}, + initialized: false, + initialize: function() { + var generateTinyFont = function() { + var encoded = "#E3KAI2wAgT1MvMg7Eo3VmNtYX7ABi3CxnbHlm" + "7Abw3kaGVhZ7ACs3OGhoZWE7A53CRobXR47AY3" + "AGbG9jYQ7G03Bm1heH7ABC3CBuYW1l7Ae3AgcG" + "9zd7AI3AE#B3AQ2kgTY18PPPUACwAg3ALSRoo3" + "#yld0xg32QAB77#E777773B#E3C#I#Q77773E#" + "Q7777777772CMAIw7AB77732B#M#Q3wAB#g3B#" + "E#E2BB//82BB////w#B7#gAEg3E77x2B32B#E#" + "Q#MTcBAQ32gAe#M#QQJ#E32M#QQJ#I#g32Q77#"; + var expand = function(input) { + return "AAAAAAAA".substr(~~input ? 7 - input : 6) + }; + return encoded.replace(/[#237]/g, expand) + }; + var fontface = document.createElement("style"); + fontface.setAttribute("type", "text/css"); + fontface.innerHTML = "@font-face {\n" + ' font-family: "PjsEmptyFont";' + "\n" + " src: url('data:application/x-font-ttf;base64," + generateTinyFont() + "')\n" + " format('truetype');\n" + "}"; + document.head.appendChild(fontface); + var element = document.createElement("span"); + element.style.cssText = 'position: absolute; top: 0; left: 0; opacity: 0; font-family: "PjsEmptyFont", fantasy;'; + element.innerHTML = "AAAAAAAA"; + document.body.appendChild(element); + this.template = element; + this.initialized = true + }, + getElementWidth: function(element) { + return document.defaultView.getComputedStyle(element, "").getPropertyValue("width") + }, + timeAttempted: 0, + pending: function(intervallength) { + if (!this.initialized) this.initialize(); + var element, computedWidthFont, computedWidthRef = this.getElementWidth(this.template); + for (var i = 0; i < this.fontList.length; i++) { + element = this.fontList[i]; + computedWidthFont = this.getElementWidth(element); + if (this.timeAttempted < 4E3 && computedWidthFont === computedWidthRef) { + this.timeAttempted += intervallength; + return true + } else { + document.body.removeChild(element); + this.fontList.splice(i--, 1); + this.timeAttempted = 0 + } + } + if (this.fontList.length === 0) return false; + return true + }, + fontList: [], + addedList: {}, + add: function(fontSrc) { + if (!this.initialized) this.initialize(); + var fontName = typeof fontSrc === "object" ? fontSrc.fontFace : fontSrc, + fontUrl = typeof fontSrc === "object" ? fontSrc.url : fontSrc; + if (this.addedList[fontName]) return; + var style = document.createElement("style"); + style.setAttribute("type", "text/css"); + style.innerHTML = "@font-face{\n font-family: '" + fontName + "';\n src: url('" + fontUrl + "');\n}\n"; + document.head.appendChild(style); + this.addedList[fontName] = true; + var element = document.createElement("span"); + element.style.cssText = "position: absolute; top: 0; left: 0; opacity: 0;"; + element.style.fontFamily = '"' + fontName + '", "PjsEmptyFont", fantasy'; + element.innerHTML = "AAAAAAAA"; + document.body.appendChild(element); + this.fontList.push(element) + } + }; + defaultScope.PFont = PFont; + var Processing = this.Processing = function(aCanvas, aCode) { + if (! (this instanceof + Processing)) throw "called Processing constructor as if it were a function: missing 'new'."; + var curElement, pgraphicsMode = aCanvas === undef && aCode === undef; + if (pgraphicsMode) curElement = document.createElement("canvas"); + else curElement = typeof aCanvas === "string" ? document.getElementById(aCanvas) : aCanvas; + if (! (curElement instanceof HTMLCanvasElement)) throw "called Processing constructor without passing canvas element reference or id."; + + function unimplemented(s) { + Processing.debug("Unimplemented - " + s) + } + var p = this; + p.externals = { + canvas: curElement, + context: undef, + sketch: undef + }; + p.name = "Processing.js Instance"; + p.use3DContext = false; + p.focused = false; + p.breakShape = false; + p.glyphTable = {}; + p.pmouseX = 0; + p.pmouseY = 0; + p.mouseX = 0; + p.mouseY = 0; + p.mouseButton = 0; + p.mouseScroll = 0; + p.mouseClicked = undef; + p.mouseDragged = undef; + p.mouseMoved = undef; + p.mousePressed = undef; + p.mouseReleased = undef; + p.mouseScrolled = undef; + p.mouseOver = undef; + p.mouseOut = undef; + p.touchStart = undef; + p.touchEnd = undef; + p.touchMove = undef; + p.touchCancel = undef; + p.key = undef; + p.keyCode = undef; + p.keyPressed = nop; + p.keyReleased = nop; + p.keyTyped = nop; + p.draw = undef; + p.setup = undef; + p.__mousePressed = false; + p.__keyPressed = false; + p.__frameRate = 60; + p.frameCount = 0; + p.width = 100; + p.height = 100; + var curContext, curSketch, drawing, online = true, + doFill = true, + fillStyle = [1, 1, 1, 1], + currentFillColor = 4294967295, + isFillDirty = true, + doStroke = true, + strokeStyle = [0, 0, 0, 1], + currentStrokeColor = 4278190080, + isStrokeDirty = true, + lineWidth = 1, + loopStarted = false, + renderSmooth = false, + doLoop = true, + looping = 0, + curRectMode = 0, + curEllipseMode = 3, + normalX = 0, + normalY = 0, + normalZ = 0, + normalMode = 0, + curFrameRate = 60, + curMsPerFrame = 1E3 / curFrameRate, + curCursor = 'default', + oldCursor = curElement.style.cursor, + curShape = 20, + curShapeCount = 0, + curvePoints = [], + curTightness = 0, + curveDet = 20, + curveInited = false, + backgroundObj = -3355444, + bezDetail = 20, + colorModeA = 255, + colorModeX = 255, + colorModeY = 255, + colorModeZ = 255, + pathOpen = false, + mouseDragging = false, + pmouseXLastFrame = 0, + pmouseYLastFrame = 0, + curColorMode = 1, + curTint = null, + curTint3d = null, + getLoaded = false, + start = Date.now(), + timeSinceLastFPS = start, + framesSinceLastFPS = 0, + textcanvas, curveBasisMatrix, curveToBezierMatrix, curveDrawMatrix, bezierDrawMatrix, bezierBasisInverse, bezierBasisMatrix, curContextCache = { + attributes: {}, + locations: {} + }, + programObject3D, programObject2D, programObjectUnlitShape, boxBuffer, boxNormBuffer, boxOutlineBuffer, rectBuffer, rectNormBuffer, sphereBuffer, lineBuffer, fillBuffer, fillColorBuffer, strokeColorBuffer, pointBuffer, shapeTexVBO, canTex, textTex, curTexture = { + width: 0, + height: 0 + }, + curTextureMode = 2, + usingTexture = false, + textBuffer, textureBuffer, indexBuffer, horizontalTextAlignment = 37, + verticalTextAlignment = 0, + textMode = 4, + curFontName = "Arial", + curTextSize = 12, + curTextAscent = 9, + curTextDescent = 2, + curTextLeading = 14, + curTextFont = PFont.get(curFontName, curTextSize), + originalContext, proxyContext = null, + isContextReplaced = false, + setPixelsCached, maxPixelsCached = 1E3, + pressedKeysMap = [], + lastPressedKeyCode = null, + codedKeys = [16, + 17, 18, 20, 33, 34, 35, 36, 37, 38, 39, 40, 144, 155, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 157]; + var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop; + if (document.defaultView && document.defaultView.getComputedStyle) { + stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(curElement, null)["paddingLeft"], 10) || 0; + stylePaddingTop = parseInt(document.defaultView.getComputedStyle(curElement, null)["paddingTop"], 10) || 0; + styleBorderLeft = parseInt(document.defaultView.getComputedStyle(curElement, null)["borderLeftWidth"], 10) || 0; + styleBorderTop = parseInt(document.defaultView.getComputedStyle(curElement, null)["borderTopWidth"], 10) || 0 + } + var lightCount = 0; + var sphereDetailV = 0, + sphereDetailU = 0, + sphereX = [], + sphereY = [], + sphereZ = [], + sinLUT = new Float32Array(720), + cosLUT = new Float32Array(720), + sphereVerts, sphereNorms; + var cam, cameraInv, modelView, modelViewInv, userMatrixStack, userReverseMatrixStack, inverseCopy, projection, manipulatingCamera = false, + frustumMode = false, + cameraFOV = 60 * (Math.PI / 180), + cameraX = p.width / 2, + cameraY = p.height / 2, + cameraZ = cameraY / Math.tan(cameraFOV / 2), + cameraNear = cameraZ / 10, + cameraFar = cameraZ * 10, + cameraAspect = p.width / p.height; + var vertArray = [], + curveVertArray = [], + curveVertCount = 0, + isCurve = false, + isBezier = false, + firstVert = true; + var curShapeMode = 0; + var styleArray = []; + var boxVerts = new Float32Array([0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, + 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]); + var boxOutlineVerts = new Float32Array([0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5]); + var boxNorms = new Float32Array([0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]); + var rectVerts = new Float32Array([0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]); + var rectNorms = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); + var vertexShaderSrcUnlitShape = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec4 aColor;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform float uPointSize;" + "void main(void) {" + " vFrontColor = aColor;" + " gl_PointSize = uPointSize;" + " gl_Position = uProjection * uView * vec4(aVertex, 1.0);" + "}"; + var fragmentShaderSrcUnlitShape = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl_PointCoord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " gl_FragColor = vFrontColor;" + "}"; + var vertexShaderSrc2D = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec2 aTextureCoord;" + "uniform vec4 uColor;" + "uniform mat4 uModel;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform float uPointSize;" + "varying vec2 vTextureCoord;" + "void main(void) {" + " gl_PointSize = uPointSize;" + " vFrontColor = uColor;" + " gl_Position = uProjection * uView * uModel * vec4(aVertex, 1.0);" + " vTextureCoord = aTextureCoord;" + "}"; + var fragmentShaderSrc2D = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "varying vec2 vTextureCoord;" + "uniform sampler2D uSampler;" + "uniform int uIsDrawingText;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl_PointCoord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " if(uIsDrawingText == 1){" + " float alpha = texture2D(uSampler, vTextureCoord).a;" + " gl_FragColor = vec4(vFrontColor.rgb * alpha, alpha);" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; + var webglMaxTempsWorkaround = /Windows/.test(navigator.userAgent); + var vertexShaderSrc3D = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec3 aNormal;" + "attribute vec4 aColor;" + "attribute vec2 aTexture;" + "varying vec2 vTexture;" + "uniform vec4 uColor;" + "uniform bool uUsingMat;" + "uniform vec3 uSpecular;" + "uniform vec3 uMaterialEmissive;" + "uniform vec3 uMaterialAmbient;" + "uniform vec3 uMaterialSpecular;" + "uniform float uShininess;" + "uniform mat4 uModel;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform mat4 uNormalTransform;" + "uniform int uLightCount;" + "uniform vec3 uFalloff;" + "struct Light {" + " int type;" + " vec3 color;" + " vec3 position;" + " vec3 direction;" + " float angle;" + " vec3 halfVector;" + " float concentration;" + "};" + "uniform Light uLights0;" + "uniform Light uLights1;" + "uniform Light uLights2;" + "uniform Light uLights3;" + "uniform Light uLights4;" + "uniform Light uLights5;" + "uniform Light uLights6;" + "uniform Light uLights7;" + "Light getLight(int index){" + " if(index == 0) return uLights0;" + " if(index == 1) return uLights1;" + " if(index == 2) return uLights2;" + " if(index == 3) return uLights3;" + " if(index == 4) return uLights4;" + " if(index == 5) return uLights5;" + " if(index == 6) return uLights6;" + " return uLights7;" + "}" + "void AmbientLight( inout vec3 totalAmbient, in vec3 ecPos, in Light light ) {" + " float d = length( light.position - ecPos );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + " totalAmbient += light.color * attenuation;" + "}" + "void DirectionalLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float powerFactor = 0.0;" + " float nDotVP = max(0.0, dot( vertNormal, normalize(-light.position) ));" + " float nDotVH = max(0.0, dot( vertNormal, normalize(-light.position-normalize(ecPos) )));" + " if( nDotVP != 0.0 ){" + " powerFactor = pow( nDotVH, uShininess );" + " }" + " col += light.color * nDotVP;" + " spec += uSpecular * powerFactor;" + "}" + "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float powerFactor;" + " vec3 VP = light.position - ecPos;" + " float d = length( VP ); " + " VP = normalize( VP );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + " float nDotVP = max( 0.0, dot( vertNormal, VP ));" + " vec3 halfVector = normalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" + " if( nDotVP == 0.0 ) {" + " powerFactor = 0.0;" + " }" + " else {" + " powerFactor = pow( nDotHV, uShininess );" + " }" + " spec += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float spotAttenuation;" + " float powerFactor = 0.0;" + " vec3 VP = light.position - ecPos;" + " vec3 ldir = normalize( -light.direction );" + " float d = length( VP );" + " VP = normalize( VP );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ) );" + " float spotDot = dot( VP, ldir );" + (webglMaxTempsWorkaround ? " spotAttenuation = 1.0; " : " if( spotDot > cos( light.angle ) ) {" + " spotAttenuation = pow( spotDot, light.concentration );" + " }" + " else{" + " spotAttenuation = 0.0;" + " }" + " attenuation *= spotAttenuation;" + "") + " float nDotVP = max( 0.0, dot( vertNormal, VP ) );" + " vec3 halfVector = normalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0, dot( vertNormal, halfVector ) );" + " if( nDotVP != 0.0 ) {" + " powerFactor = pow( nDotHV, uShininess );" + " }" + " spec += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void main(void) {" + " vec3 finalAmbient = vec3( 0.0 );" + " vec3 finalDiffuse = vec3( 0.0 );" + " vec3 finalSpecular = vec3( 0.0 );" + " vec4 col = uColor;" + " if ( uColor[0] == -1.0 ){" + " col = aColor;" + " }" + " vec3 norm = normalize(vec3( uNormalTransform * vec4( aNormal, 0.0 ) ));" + " vec4 ecPos4 = uView * uModel * vec4(aVertex, 1.0);" + " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + " if( uLightCount == 0 ) {" + " vFrontColor = col + vec4(uMaterialSpecular, 1.0);" + " }" + " else {" + " for( int i = 0; i < 8; i++ ) {" + " Light l = getLight(i);" + " if( i >= uLightCount ){" + " break;" + " }" + " if( l.type == 0 ) {" + " AmbientLight( finalAmbient, ecPos, l );" + " }" + " else if( l.type == 1 ) {" + " DirectionalLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else if( l.type == 2 ) {" + " PointLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else {" + " SpotLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " }" + " if( uUsingMat == false ) {" + " vFrontColor = vec4(" + " vec3( col ) * finalAmbient +" + " vec3( col ) * finalDiffuse +" + " vec3( col ) * finalSpecular," + " col[3] );" + " }" + " else{" + " vFrontColor = vec4( " + " uMaterialEmissive + " + " (vec3(col) * uMaterialAmbient * finalAmbient ) + " + " (vec3(col) * finalDiffuse) + " + " (uMaterialSpecular * finalSpecular), " + " col[3] );" + " }" + " }" + " vTexture.xy = aTexture.xy;" + " gl_Position = uProjection * uView * uModel * vec4( aVertex, 1.0 );" + "}"; + var fragmentShaderSrc3D = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "uniform sampler2D uSampler;" + "uniform bool uUsingTexture;" + "varying vec2 vTexture;" + "void main(void){" + " if( uUsingTexture ){" + " gl_FragColor = vec4(texture2D(uSampler, vTexture.xy)) * vFrontColor;" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; + + function uniformf(cacheId, programObj, varName, varValue) { + var varLocation = curContextCache.locations[cacheId]; + if (varLocation === undef) { + varLocation = curContext.getUniformLocation(programObj, varName); + curContextCache.locations[cacheId] = varLocation + } + if (varLocation !== null) if (varValue.length === 4) curContext.uniform4fv(varLocation, varValue); + else if (varValue.length === 3) curContext.uniform3fv(varLocation, varValue); + else if (varValue.length === 2) curContext.uniform2fv(varLocation, varValue); + else curContext.uniform1f(varLocation, varValue) + } + function uniformi(cacheId, programObj, varName, varValue) { + var varLocation = curContextCache.locations[cacheId]; + if (varLocation === undef) { + varLocation = curContext.getUniformLocation(programObj, varName); + curContextCache.locations[cacheId] = varLocation + } + if (varLocation !== null) if (varValue.length === 4) curContext.uniform4iv(varLocation, varValue); + else if (varValue.length === 3) curContext.uniform3iv(varLocation, varValue); + else if (varValue.length === 2) curContext.uniform2iv(varLocation, varValue); + else curContext.uniform1i(varLocation, varValue) + } + function uniformMatrix(cacheId, programObj, varName, transpose, matrix) { + var varLocation = curContextCache.locations[cacheId]; + if (varLocation === undef) { + varLocation = curContext.getUniformLocation(programObj, varName); + curContextCache.locations[cacheId] = varLocation + } + if (varLocation !== -1) if (matrix.length === 16) curContext.uniformMatrix4fv(varLocation, transpose, matrix); + else if (matrix.length === 9) curContext.uniformMatrix3fv(varLocation, transpose, matrix); + else curContext.uniformMatrix2fv(varLocation, transpose, matrix) + } + function vertexAttribPointer(cacheId, programObj, varName, size, VBO) { + var varLocation = curContextCache.attributes[cacheId]; + if (varLocation === undef) { + varLocation = curContext.getAttribLocation(programObj, varName); + curContextCache.attributes[cacheId] = varLocation + } + if (varLocation !== -1) { + curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO); + curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, false, 0, 0); + curContext.enableVertexAttribArray(varLocation) + } + } + function disableVertexAttribPointer(cacheId, programObj, varName) { + var varLocation = curContextCache.attributes[cacheId]; + if (varLocation === undef) { + varLocation = curContext.getAttribLocation(programObj, varName); + curContextCache.attributes[cacheId] = varLocation + } + if (varLocation !== -1) curContext.disableVertexAttribArray(varLocation) + } + var createProgramObject = function(curContext, vetexShaderSource, fragmentShaderSource) { + var vertexShaderObject = curContext.createShader(curContext.VERTEX_SHADER); + curContext.shaderSource(vertexShaderObject, vetexShaderSource); + curContext.compileShader(vertexShaderObject); + if (!curContext.getShaderParameter(vertexShaderObject, curContext.COMPILE_STATUS)) throw curContext.getShaderInfoLog(vertexShaderObject); + var fragmentShaderObject = curContext.createShader(curContext.FRAGMENT_SHADER); + curContext.shaderSource(fragmentShaderObject, fragmentShaderSource); + curContext.compileShader(fragmentShaderObject); + if (!curContext.getShaderParameter(fragmentShaderObject, curContext.COMPILE_STATUS)) throw curContext.getShaderInfoLog(fragmentShaderObject); + var programObject = curContext.createProgram(); + curContext.attachShader(programObject, vertexShaderObject); + curContext.attachShader(programObject, fragmentShaderObject); + curContext.linkProgram(programObject); + if (!curContext.getProgramParameter(programObject, curContext.LINK_STATUS)) throw "Error linking shaders."; + return programObject + }; + var imageModeCorner = function(x, y, w, h, whAreSizes) { + return { + x: x, + y: y, + w: w, + h: h + } + }; + var imageModeConvert = imageModeCorner; + var imageModeCorners = function(x, y, w, h, whAreSizes) { + return { + x: x, + y: y, + w: whAreSizes ? w : w - x, + h: whAreSizes ? h : h - y + } + }; + var imageModeCenter = function(x, y, w, h, whAreSizes) { + return { + x: x - w / 2, + y: y - h / 2, + w: w, + h: h + } + }; + var DrawingShared = function() {}; + var Drawing2D = function() {}; + var Drawing3D = function() {}; + var DrawingPre = function() {}; + Drawing2D.prototype = new DrawingShared; + Drawing2D.prototype.constructor = Drawing2D; + Drawing3D.prototype = new DrawingShared; + Drawing3D.prototype.constructor = Drawing3D; + DrawingPre.prototype = new DrawingShared; + DrawingPre.prototype.constructor = DrawingPre; + DrawingShared.prototype.a3DOnlyFunction = nop; + var charMap = {}; + var Char = p.Character = function(chr) { + if (typeof chr === "string" && chr.length === 1) this.code = chr.charCodeAt(0); + else if (typeof chr === "number") this.code = chr; + else if (chr instanceof Char) this.code = chr; + else this.code = NaN; + return charMap[this.code] === undef ? charMap[this.code] = this : charMap[this.code] + }; + Char.prototype.toString = function() { + return String.fromCharCode(this.code) + }; + Char.prototype.valueOf = function() { + return this.code + }; + var PShape = p.PShape = function(family) { + this.family = family || 0; + this.visible = true; + this.style = true; + this.children = []; + this.nameTable = []; + this.params = []; + this.name = ""; + this.image = null; + this.matrix = null; + this.kind = null; + this.close = null; + this.width = null; + this.height = null; + this.parent = null + }; + PShape.prototype = { + isVisible: function() { + return this.visible + }, + setVisible: function(visible) { + this.visible = visible + }, + disableStyle: function() { + this.style = false; + for (var i = 0, j = this.children.length; i < j; i++) this.children[i].disableStyle() + }, + enableStyle: function() { + this.style = true; + for (var i = 0, j = this.children.length; i < j; i++) this.children[i].enableStyle() + }, + getFamily: function() { + return this.family + }, + getWidth: function() { + return this.width + }, + getHeight: function() { + return this.height + }, + setName: function(name) { + this.name = name + }, + getName: function() { + return this.name + }, + draw: function(renderContext) { + renderContext = renderContext || p; + if (this.visible) { + this.pre(renderContext); + this.drawImpl(renderContext); + this.post(renderContext) + } + }, + drawImpl: function(renderContext) { + if (this.family === 0) this.drawGroup(renderContext); + else if (this.family === 1) this.drawPrimitive(renderContext); + else if (this.family === 3) this.drawGeometry(renderContext); + else if (this.family === 21) this.drawPath(renderContext) + }, + drawPath: function(renderContext) { + var i, j; + if (this.vertices.length === 0) return; + renderContext.beginShape(); + if (this.vertexCodes.length === 0) if (this.vertices[0].length === 2) for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i][0], this.vertices[i][1]); + else for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i][0], this.vertices[i][1], this.vertices[i][2]); + else { + var index = 0; + if (this.vertices[0].length === 2) for (i = 0, j = this.vertexCodes.length; i < j; i++) if (this.vertexCodes[i] === 0) { + renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index]["moveTo"]); + renderContext.breakShape = false; + index++ + } else if (this.vertexCodes[i] === 1) { + renderContext.bezierVertex(this.vertices[index + 0][0], this.vertices[index + 0][1], this.vertices[index + 1][0], this.vertices[index + 1][1], this.vertices[index + 2][0], this.vertices[index + 2][1]); + index += 3 + } else if (this.vertexCodes[i] === 2) { + renderContext.curveVertex(this.vertices[index][0], this.vertices[index][1]); + index++ + } else { + if (this.vertexCodes[i] === 3) renderContext.breakShape = true + } else for (i = 0, j = this.vertexCodes.length; i < j; i++) if (this.vertexCodes[i] === 0) { + renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index][2]); + if (this.vertices[index]["moveTo"] === true) vertArray[vertArray.length - 1]["moveTo"] = true; + else if (this.vertices[index]["moveTo"] === false) vertArray[vertArray.length - 1]["moveTo"] = false; + renderContext.breakShape = false + } else if (this.vertexCodes[i] === 1) { + renderContext.bezierVertex(this.vertices[index + 0][0], this.vertices[index + 0][1], this.vertices[index + 0][2], this.vertices[index + 1][0], this.vertices[index + 1][1], this.vertices[index + 1][2], this.vertices[index + 2][0], this.vertices[index + 2][1], this.vertices[index + 2][2]); + index += 3 + } else if (this.vertexCodes[i] === 2) { + renderContext.curveVertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index][2]); + index++ + } else if (this.vertexCodes[i] === 3) renderContext.breakShape = true + } + renderContext.endShape(this.close ? 2 : 1) + }, + drawGeometry: function(renderContext) { + var i, j; + renderContext.beginShape(this.kind); + if (this.style) for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i]); + else for (i = 0, j = this.vertices.length; i < j; i++) { + var vert = this.vertices[i]; + if (vert[2] === 0) renderContext.vertex(vert[0], vert[1]); + else renderContext.vertex(vert[0], vert[1], vert[2]) + } + renderContext.endShape() + }, + drawGroup: function(renderContext) { + for (var i = 0, j = this.children.length; i < j; i++) this.children[i].draw(renderContext) + }, + drawPrimitive: function(renderContext) { + if (this.kind === 2) renderContext.point(this.params[0], this.params[1]); + else if (this.kind === 4) if (this.params.length === 4) renderContext.line(this.params[0], this.params[1], this.params[2], this.params[3]); + else renderContext.line(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); + else if (this.kind === 8) renderContext.triangle(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); + else if (this.kind === 16) renderContext.quad(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5], this.params[6], this.params[7]); + else if (this.kind === 30) if (this.image !== null) { + var imMode = imageModeConvert; + renderContext.imageMode(0); + renderContext.image(this.image, this.params[0], this.params[1], this.params[2], this.params[3]); + imageModeConvert = imMode + } else { + var rcMode = curRectMode; + renderContext.rectMode(0); + renderContext.rect(this.params[0], this.params[1], this.params[2], this.params[3]); + curRectMode = rcMode + } else if (this.kind === 31) { + var elMode = curEllipseMode; + renderContext.ellipseMode(0); + renderContext.ellipse(this.params[0], this.params[1], this.params[2], this.params[3]); + curEllipseMode = elMode + } else if (this.kind === 32) { + var eMode = curEllipseMode; + renderContext.ellipseMode(0); + renderContext.arc(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); + curEllipseMode = eMode + } else if (this.kind === 41) if (this.params.length === 1) renderContext.box(this.params[0]); + else renderContext.box(this.params[0], this.params[1], this.params[2]); + else if (this.kind === 40) renderContext.sphere(this.params[0]) + }, + pre: function(renderContext) { + if (this.matrix) { + renderContext.pushMatrix(); + renderContext.transform(this.matrix) + } + if (this.style) { + renderContext.pushStyle(); + this.styles(renderContext) + } + }, + post: function(renderContext) { + if (this.matrix) renderContext.popMatrix(); + if (this.style) renderContext.popStyle() + }, + styles: function(renderContext) { + if (this.stroke) { + renderContext.stroke(this.strokeColor); + renderContext.strokeWeight(this.strokeWeight); + renderContext.strokeCap(this.strokeCap); + renderContext.strokeJoin(this.strokeJoin) + } else renderContext.noStroke(); + if (this.fill) renderContext.fill(this.fillColor); + else renderContext.noFill() + }, + getChild: function(child) { + var i, j; + if (typeof child === "number") return this.children[child]; + var found; + if (child === "" || this.name === child) return this; + if (this.nameTable.length > 0) { + for (i = 0, j = this.nameTable.length; i < j || found; i++) if (this.nameTable[i].getName === child) { + found = this.nameTable[i]; + break + } + if (found) return found + } + for (i = 0, j = this.children.length; i < j; i++) { + found = this.children[i].getChild(child); + if (found) return found + } + return null + }, + getChildCount: function() { + return this.children.length + }, + addChild: function(child) { + this.children.push(child); + child.parent = this; + if (child.getName() !== null) this.addName(child.getName(), child) + }, + addName: function(name, shape) { + if (this.parent !== null) this.parent.addName(name, shape); + else this.nameTable.push([name, shape]) + }, + translate: function() { + if (arguments.length === 2) { + this.checkMatrix(2); + this.matrix.translate(arguments[0], arguments[1]) + } else { + this.checkMatrix(3); + this.matrix.translate(arguments[0], arguments[1], 0) + } + }, + checkMatrix: function(dimensions) { + if (this.matrix === null) if (dimensions === 2) this.matrix = new p.PMatrix2D; + else this.matrix = new p.PMatrix3D; + else if (dimensions === 3 && this.matrix instanceof p.PMatrix2D) this.matrix = new p.PMatrix3D + }, + rotateX: function(angle) { + this.rotate(angle, 1, 0, 0) + }, + rotateY: function(angle) { + this.rotate(angle, 0, 1, 0) + }, + rotateZ: function(angle) { + this.rotate(angle, 0, 0, 1) + }, + rotate: function() { + if (arguments.length === 1) { + this.checkMatrix(2); + this.matrix.rotate(arguments[0]) + } else { + this.checkMatrix(3); + this.matrix.rotate(arguments[0], arguments[1], arguments[2], arguments[3]) + } + }, + scale: function() { + if (arguments.length === 2) { + this.checkMatrix(2); + this.matrix.scale(arguments[0], arguments[1]) + } else if (arguments.length === 3) { + this.checkMatrix(2); + this.matrix.scale(arguments[0], arguments[1], arguments[2]) + } else { + this.checkMatrix(2); + this.matrix.scale(arguments[0]) + } + }, + resetMatrix: function() { + this.checkMatrix(2); + this.matrix.reset() + }, + applyMatrix: function(matrix) { + if (arguments.length === 1) this.applyMatrix(matrix.elements[0], matrix.elements[1], 0, matrix.elements[2], matrix.elements[3], matrix.elements[4], 0, matrix.elements[5], 0, 0, 1, 0, 0, 0, 0, 1); + else if (arguments.length === 6) { + this.checkMatrix(2); + this.matrix.apply(arguments[0], arguments[1], arguments[2], 0, arguments[3], arguments[4], arguments[5], 0, 0, 0, 1, 0, 0, 0, 0, 1) + } else if (arguments.length === 16) { + this.checkMatrix(3); + this.matrix.apply(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14], arguments[15]) + } + } + }; + var PShapeSVG = p.PShapeSVG = function() { + p.PShape.call(this); + if (arguments.length === 1) { + this.element = arguments[0]; + this.vertexCodes = []; + this.vertices = []; + this.opacity = 1; + this.stroke = false; + this.strokeColor = 4278190080; + this.strokeWeight = 1; + this.strokeCap = 'butt'; + this.strokeJoin = 'miter'; + this.strokeGradient = null; + this.strokeGradientPaint = null; + this.strokeName = null; + this.strokeOpacity = 1; + this.fill = true; + this.fillColor = 4278190080; + this.fillGradient = null; + this.fillGradientPaint = null; + this.fillName = null; + this.fillOpacity = 1; + if (this.element.getName() !== "svg") throw "root is not , it's <" + this.element.getName() + ">"; + } else if (arguments.length === 2) if (typeof arguments[1] === "string") { + if (arguments[1].indexOf(".svg") > -1) { + this.element = new p.XMLElement(p, arguments[1]); + this.vertexCodes = []; + this.vertices = []; + this.opacity = 1; + this.stroke = false; + this.strokeColor = 4278190080; + this.strokeWeight = 1; + this.strokeCap = 'butt'; + this.strokeJoin = 'miter'; + this.strokeGradient = ""; + this.strokeGradientPaint = ""; + this.strokeName = ""; + this.strokeOpacity = 1; + this.fill = true; + this.fillColor = 4278190080; + this.fillGradient = null; + this.fillGradientPaint = null; + this.fillOpacity = 1 + } + } else if (arguments[0]) { + this.element = arguments[1]; + this.vertexCodes = arguments[0].vertexCodes.slice(); + this.vertices = arguments[0].vertices.slice(); + this.stroke = arguments[0].stroke; + this.strokeColor = arguments[0].strokeColor; + this.strokeWeight = arguments[0].strokeWeight; + this.strokeCap = arguments[0].strokeCap; + this.strokeJoin = arguments[0].strokeJoin; + this.strokeGradient = arguments[0].strokeGradient; + this.strokeGradientPaint = arguments[0].strokeGradientPaint; + this.strokeName = arguments[0].strokeName; + this.fill = arguments[0].fill; + this.fillColor = arguments[0].fillColor; + this.fillGradient = arguments[0].fillGradient; + this.fillGradientPaint = arguments[0].fillGradientPaint; + this.fillName = arguments[0].fillName; + this.strokeOpacity = arguments[0].strokeOpacity; + this.fillOpacity = arguments[0].fillOpacity; + this.opacity = arguments[0].opacity + } + this.name = this.element.getStringAttribute("id"); + var displayStr = this.element.getStringAttribute("display", "inline"); + this.visible = displayStr !== "none"; + var str = this.element.getAttribute("transform"); + if (str) this.matrix = this.parseMatrix(str); + var viewBoxStr = this.element.getStringAttribute("viewBox"); + if (viewBoxStr !== null) { + var viewBox = viewBoxStr.split(" "); + this.width = viewBox[2]; + this.height = viewBox[3] + } + var unitWidth = this.element.getStringAttribute("width"); + var unitHeight = this.element.getStringAttribute("height"); + if (unitWidth !== null) { + this.width = this.parseUnitSize(unitWidth); + this.height = this.parseUnitSize(unitHeight) + } else if (this.width === 0 || this.height === 0) { + this.width = 1; + this.height = 1; + throw "The width and/or height is not " + "readable in the tag of this file."; + } + this.parseColors(this.element); + this.parseChildren(this.element) + }; + PShapeSVG.prototype = new PShape; + PShapeSVG.prototype.parseMatrix = function() { + function getCoords(s) { + var m = []; + s.replace(/\((.*?)\)/, function() { + return function(all, params) { + m = params.replace(/,+/g, " ").split(/\s+/) + } + }()); + return m + } + return function(str) { + this.checkMatrix(2); + var pieces = []; + str.replace(/\s*(\w+)\((.*?)\)/g, function(all) { + pieces.push(p.trim(all)) + }); + if (pieces.length === 0) return null; + for (var i = 0, j = pieces.length; i < j; i++) { + var m = getCoords(pieces[i]); + if (pieces[i].indexOf("matrix") !== -1) this.matrix.set(m[0], m[2], m[4], m[1], m[3], m[5]); + else if (pieces[i].indexOf("translate") !== -1) { + var tx = m[0]; + var ty = m.length === 2 ? m[1] : 0; + this.matrix.translate(tx, ty) + } else if (pieces[i].indexOf("scale") !== -1) { + var sx = m[0]; + var sy = m.length === 2 ? m[1] : m[0]; + this.matrix.scale(sx, sy) + } else if (pieces[i].indexOf("rotate") !== -1) { + var angle = m[0]; + if (m.length === 1) this.matrix.rotate(p.radians(angle)); + else if (m.length === 3) { + this.matrix.translate(m[1], m[2]); + this.matrix.rotate(p.radians(m[0])); + this.matrix.translate(-m[1], -m[2]) + } + } else if (pieces[i].indexOf("skewX") !== -1) this.matrix.skewX(parseFloat(m[0])); + else if (pieces[i].indexOf("skewY") !== -1) this.matrix.skewY(m[0]); + else if (pieces[i].indexOf("shearX") !== -1) this.matrix.shearX(m[0]); + else if (pieces[i].indexOf("shearY") !== -1) this.matrix.shearY(m[0]) + } + return this.matrix + } + }(); + PShapeSVG.prototype.parseChildren = function(element) { + var newelement = element.getChildren(); + var children = new p.PShape; + for (var i = 0, j = newelement.length; i < j; i++) { + var kid = this.parseChild(newelement[i]); + if (kid) children.addChild(kid) + } + this.children.push(children) + }; + PShapeSVG.prototype.getName = function() { + return this.name + }; + PShapeSVG.prototype.parseChild = function(elem) { + var name = elem.getName(); + var shape; + if (name === "g") shape = new PShapeSVG(this, elem); + else if (name === "defs") shape = new PShapeSVG(this, elem); + else if (name === "line") { + shape = new PShapeSVG(this, elem); + shape.parseLine() + } else if (name === "circle") { + shape = new PShapeSVG(this, elem); + shape.parseEllipse(true) + } else if (name === "ellipse") { + shape = new PShapeSVG(this, elem); + shape.parseEllipse(false) + } else if (name === "rect") { + shape = new PShapeSVG(this, elem); + shape.parseRect() + } else if (name === "polygon") { + shape = new PShapeSVG(this, elem); + shape.parsePoly(true) + } else if (name === "polyline") { + shape = new PShapeSVG(this, elem); + shape.parsePoly(false) + } else if (name === "path") { + shape = new PShapeSVG(this, elem); + shape.parsePath() + } else if (name === "radialGradient") unimplemented("PShapeSVG.prototype.parseChild, name = radialGradient"); + else if (name === "linearGradient") unimplemented("PShapeSVG.prototype.parseChild, name = linearGradient"); + else if (name === "text") unimplemented("PShapeSVG.prototype.parseChild, name = text"); + else if (name === "filter") unimplemented("PShapeSVG.prototype.parseChild, name = filter"); + else if (name === "mask") unimplemented("PShapeSVG.prototype.parseChild, name = mask"); + else nop(); + return shape + }; + PShapeSVG.prototype.parsePath = function() { + this.family = 21; + this.kind = 0; + var pathDataChars = []; + var c; + var pathData = p.trim(this.element.getStringAttribute("d").replace(/[\s,]+/g, " ")); + if (pathData === null) return; + pathData = p.__toCharArray(pathData); + var cx = 0, + cy = 0, + ctrlX = 0, + ctrlY = 0, + ctrlX1 = 0, + ctrlX2 = 0, + ctrlY1 = 0, + ctrlY2 = 0, + endX = 0, + endY = 0, + ppx = 0, + ppy = 0, + px = 0, + py = 0, + i = 0, + valOf = 0; + var str = ""; + var tmpArray = []; + var flag = false; + var lastInstruction; + var command; + var j, k; + while (i < pathData.length) { + valOf = pathData[i].valueOf(); + if (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 122) { + j = i; + i++; + if (i < pathData.length) { + tmpArray = []; + valOf = pathData[i].valueOf(); + while (! (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 100 || valOf >= 102 && valOf <= 122) && flag === false) { + if (valOf === 32) { + if (str !== "") { + tmpArray.push(parseFloat(str)); + str = "" + } + i++ + } else if (valOf === 45) if (pathData[i - 1].valueOf() === 101) { + str += pathData[i].toString(); + i++ + } else { + if (str !== "") tmpArray.push(parseFloat(str)); + str = pathData[i].toString(); + i++ + } else { + str += pathData[i].toString(); + i++ + } + if (i === pathData.length) flag = true; + else valOf = pathData[i].valueOf() + } + } + if (str !== "") { + tmpArray.push(parseFloat(str)); + str = "" + } + command = pathData[j]; + valOf = command.valueOf(); + if (valOf === 77) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { + cx = tmpArray[0]; + cy = tmpArray[1]; + this.parsePathMoveto(cx, cy); + if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { + cx = tmpArray[j]; + cy = tmpArray[j + 1]; + this.parsePathLineto(cx, cy) + } + } + } else if (valOf === 109) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { + cx += tmpArray[0]; + cy += tmpArray[1]; + this.parsePathMoveto(cx, cy); + if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { + cx += tmpArray[j]; + cy += tmpArray[j + 1]; + this.parsePathLineto(cx, cy) + } + } + } else if (valOf === 76) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { + cx = tmpArray[j]; + cy = tmpArray[j + 1]; + this.parsePathLineto(cx, cy) + } + } else if (valOf === 108) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { + cx += tmpArray[j]; + cy += tmpArray[j + 1]; + this.parsePathLineto(cx, cy) + } + } else if (valOf === 72) for (j = 0, k = tmpArray.length; j < k; j++) { + cx = tmpArray[j]; + this.parsePathLineto(cx, cy) + } else if (valOf === 104) for (j = 0, k = tmpArray.length; j < k; j++) { + cx += tmpArray[j]; + this.parsePathLineto(cx, cy) + } else if (valOf === 86) for (j = 0, k = tmpArray.length; j < k; j++) { + cy = tmpArray[j]; + this.parsePathLineto(cx, cy) + } else if (valOf === 118) for (j = 0, k = tmpArray.length; j < k; j++) { + cy += tmpArray[j]; + this.parsePathLineto(cx, cy) + } else if (valOf === 67) { + if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { + ctrlX1 = tmpArray[j]; + ctrlY1 = tmpArray[j + 1]; + ctrlX2 = tmpArray[j + 2]; + ctrlY2 = tmpArray[j + 3]; + endX = tmpArray[j + 4]; + endY = tmpArray[j + 5]; + this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 99) { + if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { + ctrlX1 = cx + tmpArray[j]; + ctrlY1 = cy + tmpArray[j + 1]; + ctrlX2 = cx + tmpArray[j + 2]; + ctrlY2 = cy + tmpArray[j + 3]; + endX = cx + tmpArray[j + 4]; + endY = cy + tmpArray[j + 5]; + this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 83) { + if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { + if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLowerCase() === "s") { + ppx = this.vertices[this.vertices.length - 2][0]; + ppy = this.vertices[this.vertices.length - 2][1]; + px = this.vertices[this.vertices.length - 1][0]; + py = this.vertices[this.vertices.length - 1][1]; + ctrlX1 = px + (px - ppx); + ctrlY1 = py + (py - ppy) + } else { + ctrlX1 = this.vertices[this.vertices.length - 1][0]; + ctrlY1 = this.vertices[this.vertices.length - 1][1] + } + ctrlX2 = tmpArray[j]; + ctrlY2 = tmpArray[j + 1]; + endX = tmpArray[j + 2]; + endY = tmpArray[j + 3]; + this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 115) { + if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { + if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLowerCase() === "s") { + ppx = this.vertices[this.vertices.length - 2][0]; + ppy = this.vertices[this.vertices.length - 2][1]; + px = this.vertices[this.vertices.length - 1][0]; + py = this.vertices[this.vertices.length - 1][1]; + ctrlX1 = px + (px - ppx); + ctrlY1 = py + (py - ppy) + } else { + ctrlX1 = this.vertices[this.vertices.length - 1][0]; + ctrlY1 = this.vertices[this.vertices.length - 1][1] + } + ctrlX2 = cx + tmpArray[j]; + ctrlY2 = cy + tmpArray[j + 1]; + endX = cx + tmpArray[j + 2]; + endY = cy + tmpArray[j + 3]; + this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 81) { + if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { + ctrlX = tmpArray[j]; + ctrlY = tmpArray[j + 1]; + endX = tmpArray[j + 2]; + endY = tmpArray[j + 3]; + this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 113) { + if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { + ctrlX = cx + tmpArray[j]; + ctrlY = cy + tmpArray[j + 1]; + endX = cx + tmpArray[j + 2]; + endY = cy + tmpArray[j + 3]; + this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 84) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { + if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLowerCase() === "t") { + ppx = this.vertices[this.vertices.length - 2][0]; + ppy = this.vertices[this.vertices.length - 2][1]; + px = this.vertices[this.vertices.length - 1][0]; + py = this.vertices[this.vertices.length - 1][1]; + ctrlX = px + (px - ppx); + ctrlY = py + (py - ppy) + } else { + ctrlX = cx; + ctrlY = cy + } + endX = tmpArray[j]; + endY = tmpArray[j + 1]; + this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 116) { + if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { + if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLowerCase() === "t") { + ppx = this.vertices[this.vertices.length - 2][0]; + ppy = this.vertices[this.vertices.length - 2][1]; + px = this.vertices[this.vertices.length - 1][0]; + py = this.vertices[this.vertices.length - 1][1]; + ctrlX = px + (px - ppx); + ctrlY = py + (py - ppy) + } else { + ctrlX = cx; + ctrlY = cy + } + endX = cx + tmpArray[j]; + endY = cy + tmpArray[j + 1]; + this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); + cx = endX; + cy = endY + } + } else if (valOf === 90 || valOf === 122) this.close = true; + lastInstruction = command.toString() + } else i++ + } + }; + PShapeSVG.prototype.parsePathQuadto = function(x1, y1, cx, cy, x2, y2) { + if (this.vertices.length > 0) { + this.parsePathCode(1); + this.parsePathVertex(x1 + (cx - x1) * 2 / 3, y1 + (cy - y1) * 2 / 3); + this.parsePathVertex(x2 + (cx - x2) * 2 / 3, y2 + (cy - y2) * 2 / 3); + this.parsePathVertex(x2, y2) + } else throw "Path must start with M/m"; + }; + PShapeSVG.prototype.parsePathCurveto = function(x1, y1, x2, y2, x3, y3) { + if (this.vertices.length > 0) { + this.parsePathCode(1); + this.parsePathVertex(x1, y1); + this.parsePathVertex(x2, y2); + this.parsePathVertex(x3, y3) + } else throw "Path must start with M/m"; + }; + PShapeSVG.prototype.parsePathLineto = function(px, py) { + if (this.vertices.length > 0) { + this.parsePathCode(0); + this.parsePathVertex(px, py); + this.vertices[this.vertices.length - 1]["moveTo"] = false + } else throw "Path must start with M/m"; + }; + PShapeSVG.prototype.parsePathMoveto = function(px, py) { + if (this.vertices.length > 0) this.parsePathCode(3); + this.parsePathCode(0); + this.parsePathVertex(px, py); + this.vertices[this.vertices.length - 1]["moveTo"] = true + }; + PShapeSVG.prototype.parsePathVertex = function(x, y) { + var verts = []; + verts[0] = x; + verts[1] = y; + this.vertices.push(verts) + }; + PShapeSVG.prototype.parsePathCode = function(what) { + this.vertexCodes.push(what) + }; + PShapeSVG.prototype.parsePoly = function(val) { + this.family = 21; + this.close = val; + var pointsAttr = p.trim(this.element.getStringAttribute("points").replace(/[,\s]+/g, " ")); + if (pointsAttr !== null) { + var pointsBuffer = pointsAttr.split(" "); + if (pointsBuffer.length % 2 === 0) for (var i = 0, j = pointsBuffer.length; i < j; i++) { + var verts = []; + verts[0] = pointsBuffer[i]; + verts[1] = pointsBuffer[++i]; + this.vertices.push(verts) + } else throw "Error parsing polygon points: odd number of coordinates provided"; + } + }; + PShapeSVG.prototype.parseRect = function() { + this.kind = 30; + this.family = 1; + this.params = []; + this.params[0] = this.element.getFloatAttribute("x"); + this.params[1] = this.element.getFloatAttribute("y"); + this.params[2] = this.element.getFloatAttribute("width"); + this.params[3] = this.element.getFloatAttribute("height"); + if (this.params[2] < 0 || this.params[3] < 0) throw "svg error: negative width or height found while parsing "; + }; + PShapeSVG.prototype.parseEllipse = function(val) { + this.kind = 31; + this.family = 1; + this.params = []; + this.params[0] = this.element.getFloatAttribute("cx") | 0; + this.params[1] = this.element.getFloatAttribute("cy") | 0; + var rx, ry; + if (val) { + rx = ry = this.element.getFloatAttribute("r"); + if (rx < 0) throw "svg error: negative radius found while parsing "; + } else { + rx = this.element.getFloatAttribute("rx"); + ry = this.element.getFloatAttribute("ry"); + if (rx < 0 || ry < 0) throw "svg error: negative x-axis radius or y-axis radius found while parsing "; + } + this.params[0] -= rx; + this.params[1] -= ry; + this.params[2] = rx * 2; + this.params[3] = ry * 2 + }; + PShapeSVG.prototype.parseLine = function() { + this.kind = 4; + this.family = 1; + this.params = []; + this.params[0] = this.element.getFloatAttribute("x1"); + this.params[1] = this.element.getFloatAttribute("y1"); + this.params[2] = this.element.getFloatAttribute("x2"); + this.params[3] = this.element.getFloatAttribute("y2") + }; + PShapeSVG.prototype.parseColors = function(element) { + if (element.hasAttribute("opacity")) this.setOpacity(element.getAttribute("opacity")); + if (element.hasAttribute("stroke")) this.setStroke(element.getAttribute("stroke")); + if (element.hasAttribute("stroke-width")) this.setStrokeWeight(element.getAttribute("stroke-width")); + if (element.hasAttribute("stroke-linejoin")) this.setStrokeJoin(element.getAttribute("stroke-linejoin")); + if (element.hasAttribute("stroke-linecap")) this.setStrokeCap(element.getStringAttribute("stroke-linecap")); + if (element.hasAttribute("fill")) this.setFill(element.getStringAttribute("fill")); + if (element.hasAttribute("style")) { + var styleText = element.getStringAttribute("style"); + var styleTokens = styleText.toString().split(";"); + for (var i = 0, j = styleTokens.length; i < j; i++) { + var tokens = p.trim(styleTokens[i].split(":")); + if (tokens[0] === "fill") this.setFill(tokens[1]); + else if (tokens[0] === "fill-opacity") this.setFillOpacity(tokens[1]); + else if (tokens[0] === "stroke") this.setStroke(tokens[1]); + else if (tokens[0] === "stroke-width") this.setStrokeWeight(tokens[1]); + else if (tokens[0] === "stroke-linecap") this.setStrokeCap(tokens[1]); + else if (tokens[0] === "stroke-linejoin") this.setStrokeJoin(tokens[1]); + else if (tokens[0] === "stroke-opacity") this.setStrokeOpacity(tokens[1]); + else if (tokens[0] === "opacity") this.setOpacity(tokens[1]) + } + } + }; + PShapeSVG.prototype.setFillOpacity = function(opacityText) { + this.fillOpacity = parseFloat(opacityText); + this.fillColor = this.fillOpacity * 255 << 24 | this.fillColor & 16777215 + }; + PShapeSVG.prototype.setFill = function(fillText) { + var opacityMask = this.fillColor & 4278190080; + if (fillText === "none") this.fill = false; + else if (fillText.indexOf("#") === 0) { + this.fill = true; + if (fillText.length === 4) fillText = fillText.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); + this.fillColor = opacityMask | parseInt(fillText.substring(1), 16) & 16777215 + } else if (fillText.indexOf("rgb") === 0) { + this.fill = true; + this.fillColor = opacityMask | this.parseRGB(fillText) + } else if (fillText.indexOf("url(#") === 0) this.fillName = fillText.substring(5, fillText.length - 1); + else if (colors[fillText]) { + this.fill = true; + this.fillColor = opacityMask | parseInt(colors[fillText].substring(1), 16) & 16777215 + } + }; + PShapeSVG.prototype.setOpacity = function(opacity) { + this.strokeColor = parseFloat(opacity) * 255 << 24 | this.strokeColor & 16777215; + this.fillColor = parseFloat(opacity) * 255 << 24 | this.fillColor & 16777215 + }; + PShapeSVG.prototype.setStroke = function(strokeText) { + var opacityMask = this.strokeColor & 4278190080; + if (strokeText === "none") this.stroke = false; + else if (strokeText.charAt(0) === "#") { + this.stroke = true; + if (strokeText.length === 4) strokeText = strokeText.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); + this.strokeColor = opacityMask | parseInt(strokeText.substring(1), 16) & 16777215 + } else if (strokeText.indexOf("rgb") === 0) { + this.stroke = true; + this.strokeColor = opacityMask | this.parseRGB(strokeText) + } else if (strokeText.indexOf("url(#") === 0) this.strokeName = strokeText.substring(5, strokeText.length - 1); + else if (colors[strokeText]) { + this.stroke = true; + this.strokeColor = opacityMask | parseInt(colors[strokeText].substring(1), 16) & 16777215 + } + }; + PShapeSVG.prototype.setStrokeWeight = function(weight) { + this.strokeWeight = this.parseUnitSize(weight) + }; + PShapeSVG.prototype.setStrokeJoin = function(linejoin) { + if (linejoin === "miter") this.strokeJoin = 'miter'; + else if (linejoin === "round") this.strokeJoin = 'round'; + else if (linejoin === "bevel") this.strokeJoin = 'bevel' + }; + PShapeSVG.prototype.setStrokeCap = function(linecap) { + if (linecap === "butt") this.strokeCap = 'butt'; + else if (linecap === "round") this.strokeCap = 'round'; + else if (linecap === "square") this.strokeCap = 'square' + }; + PShapeSVG.prototype.setStrokeOpacity = function(opacityText) { + this.strokeOpacity = parseFloat(opacityText); + this.strokeColor = this.strokeOpacity * 255 << 24 | this.strokeColor & 16777215 + }; + PShapeSVG.prototype.parseRGB = function(color) { + var sub = color.substring(color.indexOf("(") + 1, color.indexOf(")")); + var values = sub.split(", "); + return values[0] << 16 | values[1] << 8 | values[2] + }; + PShapeSVG.prototype.parseUnitSize = function(text) { + var len = text.length - 2; + if (len < 0) return text; + if (text.indexOf("pt") === len) return parseFloat(text.substring(0, len)) * 1.25; + if (text.indexOf("pc") === len) return parseFloat(text.substring(0, len)) * 15; + if (text.indexOf("mm") === len) return parseFloat(text.substring(0, len)) * 3.543307; + if (text.indexOf("cm") === len) return parseFloat(text.substring(0, len)) * 35.43307; + if (text.indexOf("in") === len) return parseFloat(text.substring(0, len)) * 90; + if (text.indexOf("px") === len) return parseFloat(text.substring(0, len)); + return parseFloat(text) + }; + p.shape = function(shape, x, y, width, height) { + if (arguments.length >= 1 && arguments[0] !== null) if (shape.isVisible()) { + p.pushMatrix(); + if (curShapeMode === 3) if (arguments.length === 5) { + p.translate(x - width / 2, y - height / 2); + p.scale(width / shape.getWidth(), height / shape.getHeight()) + } else if (arguments.length === 3) p.translate(x - shape.getWidth() / 2, -shape.getHeight() / 2); + else p.translate(-shape.getWidth() / 2, -shape.getHeight() / 2); + else if (curShapeMode === 0) if (arguments.length === 5) { + p.translate(x, y); + p.scale(width / shape.getWidth(), height / shape.getHeight()) + } else { + if (arguments.length === 3) p.translate(x, y) + } else if (curShapeMode === 1) if (arguments.length === 5) { + width -= x; + height -= y; + p.translate(x, y); + p.scale(width / shape.getWidth(), height / shape.getHeight()) + } else if (arguments.length === 3) p.translate(x, y); + shape.draw(p); + if (arguments.length === 1 && curShapeMode === 3 || arguments.length > 1) p.popMatrix() + } + }; + p.shapeMode = function(mode) { + curShapeMode = mode + }; + p.loadShape = function(filename) { + if (arguments.length === 1) if (filename.indexOf(".svg") > -1) return new PShapeSVG(null, filename); + return null + }; + var XMLAttribute = function(fname, n, nameSpace, v, t) { + this.fullName = fname || ""; + this.name = n || ""; + this.namespace = nameSpace || ""; + this.value = v; + this.type = t + }; + XMLAttribute.prototype = { + getName: function() { + return this.name + }, + getFullName: function() { + return this.fullName + }, + getNamespace: function() { + return this.namespace + }, + getValue: function() { + return this.value + }, + getType: function() { + return this.type + }, + setValue: function(newval) { + this.value = newval + } + }; + var XMLElement = p.XMLElement = function(selector, uri, sysid, line) { + this.attributes = []; + this.children = []; + this.fullName = null; + this.name = null; + this.namespace = ""; + this.content = null; + this.parent = null; + this.lineNr = ""; + this.systemID = ""; + this.type = "ELEMENT"; + if (selector) if (typeof selector === "string") if (uri === undef && selector.indexOf("<") > -1) this.parse(selector); + else { + this.fullName = selector; + this.namespace = uri; + this.systemId = sysid; + this.lineNr = line + } else this.parse(uri) + }; + XMLElement.prototype = { + parse: function(textstring) { + var xmlDoc; + try { + var extension = textstring.substring(textstring.length - 4); + if (extension === ".xml" || extension === ".svg") textstring = ajax(textstring); + xmlDoc = (new DOMParser).parseFromString(textstring, "text/xml"); + var elements = xmlDoc.documentElement; + if (elements) this.parseChildrenRecursive(null, elements); + else throw "Error loading document"; + return this + } catch(e) { + throw e; + } + }, + parseChildrenRecursive: function(parent, elementpath) { + var xmlelement, xmlattribute, tmpattrib, l, m, child; + if (!parent) { + this.fullName = elementpath.localName; + this.name = elementpath.nodeName; + xmlelement = this + } else { + xmlelement = new XMLElement(elementpath.nodeName); + xmlelement.parent = parent + } + if (elementpath.nodeType === 3 && elementpath.textContent !== "") return this.createPCDataElement(elementpath.textContent); + if (elementpath.nodeType === 4) return this.createCDataElement(elementpath.textContent); + if (elementpath.attributes) for (l = 0, m = elementpath.attributes.length; l < m; l++) { + tmpattrib = elementpath.attributes[l]; + xmlattribute = new XMLAttribute(tmpattrib.getname, tmpattrib.nodeName, tmpattrib.namespaceURI, tmpattrib.nodeValue, tmpattrib.nodeType); + xmlelement.attributes.push(xmlattribute) + } + if (elementpath.childNodes) for (l = 0, m = elementpath.childNodes.length; l < m; l++) { + var node = elementpath.childNodes[l]; + child = xmlelement.parseChildrenRecursive(xmlelement, node); + if (child !== null) xmlelement.children.push(child) + } + return xmlelement + }, + createElement: function(fullname, namespaceuri, sysid, line) { + if (sysid === undef) return new XMLElement(fullname, namespaceuri); + return new XMLElement(fullname, namespaceuri, sysid, line) + }, + createPCDataElement: function(content, isCDATA) { + if (content.replace(/^\s+$/g, "") === "") return null; + var pcdata = new XMLElement; + pcdata.type = "TEXT"; + pcdata.content = content; + return pcdata + }, + createCDataElement: function(content) { + var cdata = this.createPCDataElement(content); + if (cdata === null) return null; + cdata.type = "CDATA"; + var htmlentities = { + "<": "<", + ">": ">", + "'": "'", + '"': """ + }, + entity; + for (entity in htmlentities) if (!Object.hasOwnProperty(htmlentities, entity)) content = content.replace(new RegExp(entity, "g"), htmlentities[entity]); + cdata.cdata = content; + return cdata + }, + hasAttribute: function() { + if (arguments.length === 1) return this.getAttribute(arguments[0]) !== null; + if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]) !== null + }, + equals: function(other) { + if (! (other instanceof XMLElement)) return false; + var i, j; + if (this.fullName !== other.fullName) return false; + if (this.attributes.length !== other.getAttributeCount()) return false; + if (this.attributes.length !== other.attributes.length) return false; + var attr_name, attr_ns, attr_value, attr_type, attr_other; + for (i = 0, j = this.attributes.length; i < j; i++) { + attr_name = this.attributes[i].getName(); + attr_ns = this.attributes[i].getNamespace(); + attr_other = other.findAttribute(attr_name, attr_ns); + if (attr_other === null) return false; + if (this.attributes[i].getValue() !== attr_other.getValue()) return false; + if (this.attributes[i].getType() !== attr_other.getType()) return false + } + if (this.children.length !== other.getChildCount()) return false; + if (this.children.length > 0) { + var child1, child2; + for (i = 0, j = this.children.length; i < j; i++) { + child1 = this.getChild(i); + child2 = other.getChild(i); + if (!child1.equals(child2)) return false + } + return true + } + return this.content === other.content + }, + getContent: function() { + if (this.type === "TEXT" || this.type === "CDATA") return this.content; + var children = this.children; + if (children.length === 1 && (children[0].type === "TEXT" || children[0].type === "CDATA")) return children[0].content; + return null + }, + getAttribute: function() { + var attribute; + if (arguments.length === 2) { + attribute = this.findAttribute(arguments[0]); + if (attribute) return attribute.getValue(); + return arguments[1] + } else if (arguments.length === 1) { + attribute = this.findAttribute(arguments[0]); + if (attribute) return attribute.getValue(); + return null + } else if (arguments.length === 3) { + attribute = this.findAttribute(arguments[0], arguments[1]); + if (attribute) return attribute.getValue(); + return arguments[2] + } + }, + getStringAttribute: function() { + if (arguments.length === 1) return this.getAttribute(arguments[0]); + if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); + return this.getAttribute(arguments[0], arguments[1], arguments[2]) + }, + getString: function(attributeName) { + return this.getStringAttribute(attributeName) + }, + getFloatAttribute: function() { + if (arguments.length === 1) return parseFloat(this.getAttribute(arguments[0], 0)); + if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); + return this.getAttribute(arguments[0], arguments[1], arguments[2]) + }, + getFloat: function(attributeName) { + return this.getFloatAttribute(attributeName) + }, + getIntAttribute: function() { + if (arguments.length === 1) return this.getAttribute(arguments[0], 0); + if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); + return this.getAttribute(arguments[0], arguments[1], arguments[2]) + }, + getInt: function(attributeName) { + return this.getIntAttribute(attributeName) + }, + hasChildren: function() { + return this.children.length > 0 + }, + addChild: function(child) { + if (child !== null) { + child.parent = this; + this.children.push(child) + } + }, + insertChild: function(child, index) { + if (child) { + if (child.getLocalName() === null && !this.hasChildren()) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild.getLocalName() === null) { + lastChild.setContent(lastChild.getContent() + child.getContent()); + return + } + } + child.parent = this; + this.children.splice(index, 0, child) + } + }, + getChild: function(selector) { + if (typeof selector === "number") return this.children[selector]; + if (selector.indexOf("/") !== -1) return this.getChildRecursive(selector.split("/"), 0); + var kid, kidName; + for (var i = 0, j = this.getChildCount(); i < j; i++) { + kid = this.getChild(i); + kidName = kid.getName(); + if (kidName !== null && kidName === selector) return kid + } + return null + }, + getChildren: function() { + if (arguments.length === 1) { + if (typeof arguments[0] === "number") return this.getChild(arguments[0]); + if (arguments[0].indexOf("/") !== -1) return this.getChildrenRecursive(arguments[0].split("/"), 0); + var matches = []; + var kid, kidName; + for (var i = 0, j = this.getChildCount(); i < j; i++) { + kid = this.getChild(i); + kidName = kid.getName(); + if (kidName !== null && kidName === arguments[0]) matches.push(kid) + } + return matches + } + return this.children + }, + getChildCount: function() { + return this.children.length + }, + getChildRecursive: function(items, offset) { + if (offset === items.length) return this; + var kid, kidName, matchName = items[offset]; + for (var i = 0, j = this.getChildCount(); i < j; i++) { + kid = this.getChild(i); + kidName = kid.getName(); + if (kidName !== null && kidName === matchName) return kid.getChildRecursive(items, offset + 1) + } + return null + }, + getChildrenRecursive: function(items, offset) { + if (offset === items.length - 1) return this.getChildren(items[offset]); + var matches = this.getChildren(items[offset]); + var kidMatches = []; + for (var i = 0; i < matches.length; i++) kidMatches = kidMatches.concat(matches[i].getChildrenRecursive(items, offset + 1)); + return kidMatches + }, + isLeaf: function() { + return !this.hasChildren() + }, + listChildren: function() { + var arr = []; + for (var i = 0, j = this.children.length; i < j; i++) arr.push(this.getChild(i).getName()); + return arr + }, + removeAttribute: function(name, namespace) { + this.namespace = namespace || ""; + for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) { + this.attributes.splice(i, 1); + break + } + }, + removeChild: function(child) { + if (child) for (var i = 0, j = this.children.length; i < j; i++) if (this.children[i].equals(child)) { + this.children.splice(i, 1); + break + } + }, + removeChildAtIndex: function(index) { + if (this.children.length > index) this.children.splice(index, 1) + }, + findAttribute: function(name, namespace) { + this.namespace = namespace || ""; + for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) return this.attributes[i]; + return null + }, + setAttribute: function() { + var attr; + if (arguments.length === 3) { + var index = arguments[0].indexOf(":"); + var name = arguments[0].substring(index + 1); + attr = this.findAttribute(name, arguments[1]); + if (attr) attr.setValue(arguments[2]); + else { + attr = new XMLAttribute(arguments[0], name, arguments[1], arguments[2], "CDATA"); + this.attributes.push(attr) + } + } else { + attr = this.findAttribute(arguments[0]); + if (attr) attr.setValue(arguments[1]); + else { + attr = new XMLAttribute(arguments[0], arguments[0], null, arguments[1], "CDATA"); + this.attributes.push(attr) + } + } + }, + setString: function(attribute, value) { + this.setAttribute(attribute, value) + }, + setInt: function(attribute, value) { + this.setAttribute(attribute, value) + }, + setFloat: function(attribute, value) { + this.setAttribute(attribute, value) + }, + setContent: function(content) { + if (this.children.length > 0) Processing.debug("Tried to set content for XMLElement with children"); + this.content = content + }, + setName: function() { + if (arguments.length === 1) { + this.name = arguments[0]; + this.fullName = arguments[0]; + this.namespace = null + } else { + var index = arguments[0].indexOf(":"); + if (arguments[1] === null || index < 0) this.name = arguments[0]; + else this.name = arguments[0].substring(index + 1); + this.fullName = arguments[0]; + this.namespace = arguments[1] + } + }, + getName: function() { + return this.fullName + }, + getLocalName: function() { + return this.name + }, + getAttributeCount: function() { + return this.attributes.length + }, + toString: function() { + if (this.type === "TEXT") return this.content; + if (this.type === "CDATA") return this.cdata; + var tagstring = this.fullName; + var xmlstring = "<" + tagstring; + var a, c; + for (a = 0; a < this.attributes.length; a++) { + var attr = this.attributes[a]; + xmlstring += " " + attr.getName() + "=" + '"' + attr.getValue() + '"' + } + if (this.children.length === 0) if (this.content === "") xmlstring += "/>"; + else xmlstring += ">" + this.content + ""; + else { + xmlstring += ">"; + for (c = 0; c < this.children.length; c++) xmlstring += this.children[c].toString(); + xmlstring += "" + } + return xmlstring + } + }; + XMLElement.parse = function(xmlstring) { + var element = new XMLElement; + element.parse(xmlstring); + return element + }; + var XML = p.XML = p.XMLElement; + p.loadXML = function(uri) { + return new XML(p, uri) + }; + var printMatrixHelper = function(elements) { + var big = 0; + for (var i = 0; i < elements.length; i++) if (i !== 0) big = Math.max(big, Math.abs(elements[i])); + else big = Math.abs(elements[i]); + var digits = (big + "").indexOf("."); + if (digits === 0) digits = 1; + else if (digits === -1) digits = (big + "").length; + return digits + }; + var PMatrix2D = p.PMatrix2D = function() { + if (arguments.length === 0) this.reset(); + else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this.set(arguments[0].array()); + else if (arguments.length === 6) this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]) + }; + PMatrix2D.prototype = { + set: function() { + if (arguments.length === 6) { + var a = arguments; + this.set([a[0], a[1], a[2], a[3], a[4], a[5]]) + } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this.elements = arguments[0].array(); + else if (arguments.length === 1 && arguments[0] instanceof Array) this.elements = arguments[0].slice() + }, + get: function() { + var outgoing = new PMatrix2D; + outgoing.set(this.elements); + return outgoing + }, + reset: function() { + this.set([1, 0, 0, 0, 1, 0]) + }, + array: function array() { + return this.elements.slice() + }, + translate: function(tx, ty) { + this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2]; + this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5] + }, + invTranslate: function(tx, ty) { + this.translate(-tx, -ty) + }, + transpose: function() {}, + mult: function(source, target) { + var x, y; + if (source instanceof + PVector) { + x = source.x; + y = source.y; + if (!target) target = new PVector + } else if (source instanceof Array) { + x = source[0]; + y = source[1]; + if (!target) target = [] + } + if (target instanceof Array) { + target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2]; + target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5] + } else if (target instanceof PVector) { + target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2]; + target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5]; + target.z = 0 + } + return target + }, + multX: function(x, y) { + return x * this.elements[0] + y * this.elements[1] + this.elements[2] + }, + multY: function(x, y) { + return x * this.elements[3] + y * this.elements[4] + this.elements[5] + }, + skewX: function(angle) { + this.apply(1, 0, 1, angle, 0, 0) + }, + skewY: function(angle) { + this.apply(1, 0, 1, 0, angle, 0) + }, + shearX: function(angle) { + this.apply(1, 0, 1, Math.tan(angle), 0, 0) + }, + shearY: function(angle) { + this.apply(1, 0, 1, 0, Math.tan(angle), 0) + }, + determinant: function() { + return this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3] + }, + invert: function() { + var d = this.determinant(); + if (Math.abs(d) > -2147483648) { + var old00 = this.elements[0]; + var old01 = this.elements[1]; + var old02 = this.elements[2]; + var old10 = this.elements[3]; + var old11 = this.elements[4]; + var old12 = this.elements[5]; + this.elements[0] = old11 / d; + this.elements[3] = -old10 / d; + this.elements[1] = -old01 / d; + this.elements[4] = old00 / d; + this.elements[2] = (old01 * old12 - old11 * old02) / d; + this.elements[5] = (old10 * old02 - old00 * old12) / d; + return true + } + return false + }, + scale: function(sx, sy) { + if (sx && !sy) sy = sx; + if (sx && sy) { + this.elements[0] *= sx; + this.elements[1] *= sy; + this.elements[3] *= sx; + this.elements[4] *= sy + } + }, + invScale: function(sx, sy) { + if (sx && !sy) sy = sx; + this.scale(1 / sx, 1 / sy) + }, + apply: function() { + var source; + if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array(); + else if (arguments.length === 6) source = Array.prototype.slice.call(arguments); + else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; + var result = [0, 0, this.elements[2], 0, 0, this.elements[5]]; + var e = 0; + for (var row = 0; row < 2; row++) for (var col = 0; col < 3; col++, e++) result[e] += this.elements[row * 3 + 0] * source[col + 0] + this.elements[row * 3 + 1] * source[col + 3]; + this.elements = result.slice() + }, + preApply: function() { + var source; + if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array(); + else if (arguments.length === 6) source = Array.prototype.slice.call(arguments); + else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; + var result = [0, 0, source[2], 0, 0, source[5]]; + result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1]; + result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4]; + result[0] = this.elements[0] * source[0] + this.elements[3] * source[1]; + result[3] = this.elements[0] * source[3] + this.elements[3] * source[4]; + result[1] = this.elements[1] * source[0] + this.elements[4] * source[1]; + result[4] = this.elements[1] * source[3] + this.elements[4] * source[4]; + this.elements = result.slice() + }, + rotate: function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + var temp1 = this.elements[0]; + var temp2 = this.elements[1]; + this.elements[0] = c * temp1 + s * temp2; + this.elements[1] = -s * temp1 + c * temp2; + temp1 = this.elements[3]; + temp2 = this.elements[4]; + this.elements[3] = c * temp1 + s * temp2; + this.elements[4] = -s * temp1 + c * temp2 + }, + rotateZ: function(angle) { + this.rotate(angle) + }, + invRotateZ: function(angle) { + this.rotateZ(angle - Math.PI) + }, + print: function() { + var digits = printMatrixHelper(this.elements); + var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + "\n" + p.nfs(this.elements[3], digits, 4) + " " + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + "\n\n"; + p.println(output) + } + }; + var PMatrix3D = p.PMatrix3D = function() { + this.reset() + }; + PMatrix3D.prototype = { + set: function() { + if (arguments.length === 16) this.elements = Array.prototype.slice.call(arguments); + else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) this.elements = arguments[0].array(); + else if (arguments.length === 1 && arguments[0] instanceof Array) this.elements = arguments[0].slice() + }, + get: function() { + var outgoing = new PMatrix3D; + outgoing.set(this.elements); + return outgoing + }, + reset: function() { + this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] + }, + array: function array() { + return this.elements.slice() + }, + translate: function(tx, ty, tz) { + if (tz === undef) tz = 0; + this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2]; + this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6]; + this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10]; + this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14] + }, + transpose: function() { + var temp = this.elements[4]; + this.elements[4] = this.elements[1]; + this.elements[1] = temp; + temp = this.elements[8]; + this.elements[8] = this.elements[2]; + this.elements[2] = temp; + temp = this.elements[6]; + this.elements[6] = this.elements[9]; + this.elements[9] = temp; + temp = this.elements[3]; + this.elements[3] = this.elements[12]; + this.elements[12] = temp; + temp = this.elements[7]; + this.elements[7] = this.elements[13]; + this.elements[13] = temp; + temp = this.elements[11]; + this.elements[11] = this.elements[14]; + this.elements[14] = temp + }, + mult: function(source, target) { + var x, y, z, w; + if (source instanceof + PVector) { + x = source.x; + y = source.y; + z = source.z; + w = 1; + if (!target) target = new PVector + } else if (source instanceof Array) { + x = source[0]; + y = source[1]; + z = source[2]; + w = source[3] || 1; + if (!target || target.length !== 3 && target.length !== 4) target = [0, 0, 0] + } + if (target instanceof Array) if (target.length === 3) { + target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; + target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; + target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] + } else if (target.length === 4) { + target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; + target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; + target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; + target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w + } + if (target instanceof PVector) { + target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; + target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; + target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] + } + return target + }, + preApply: function() { + var source; + if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); + else if (arguments.length === 16) source = Array.prototype.slice.call(arguments); + else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; + var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var e = 0; + for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] * source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] + this.elements[col + 12] * source[row * 4 + 3]; + this.elements = result.slice() + }, + apply: function() { + var source; + if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); + else if (arguments.length === 16) source = Array.prototype.slice.call(arguments); + else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; + var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var e = 0; + for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] * source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] + this.elements[row * 4 + 3] * source[col + 12]; + this.elements = result.slice() + }, + rotate: function(angle, v0, v1, v2) { + if (!v1) this.rotateZ(angle); + else { + var c = p.cos(angle); + var s = p.sin(angle); + var t = 1 - c; + this.apply(t * v0 * v0 + c, t * v0 * v1 - s * v2, t * v0 * v2 + s * v1, 0, t * v0 * v1 + s * v2, t * v1 * v1 + c, t * v1 * v2 - s * v0, 0, t * v0 * v2 - s * v1, t * v1 * v2 + s * v0, t * v2 * v2 + c, 0, 0, 0, 0, 1) + } + }, + invApply: function() { + if (inverseCopy === undef) inverseCopy = new PMatrix3D; + var a = arguments; + inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); + if (!inverseCopy.invert()) return false; + this.preApply(inverseCopy); + return true + }, + rotateX: function(angle) { + var c = p.cos(angle); + var s = p.sin(angle); + this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) + }, + rotateY: function(angle) { + var c = p.cos(angle); + var s = p.sin(angle); + this.apply([c, + 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) + }, + rotateZ: function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) + }, + scale: function(sx, sy, sz) { + if (sx && !sy && !sz) sy = sz = sx; + else if (sx && sy && !sz) sz = 1; + if (sx && sy && sz) { + this.elements[0] *= sx; + this.elements[1] *= sy; + this.elements[2] *= sz; + this.elements[4] *= sx; + this.elements[5] *= sy; + this.elements[6] *= sz; + this.elements[8] *= sx; + this.elements[9] *= sy; + this.elements[10] *= sz; + this.elements[12] *= sx; + this.elements[13] *= sy; + this.elements[14] *= sz + } + }, + skewX: function(angle) { + var t = Math.tan(angle); + this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + }, + skewY: function(angle) { + var t = Math.tan(angle); + this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + }, + shearX: function(angle) { + var t = Math.tan(angle); + this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + }, + shearY: function(angle) { + var t = Math.tan(angle); + this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + }, + multX: function(x, y, z, w) { + if (!z) return this.elements[0] * x + this.elements[1] * y + this.elements[3]; + if (!w) return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; + return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w + }, + multY: function(x, y, z, w) { + if (!z) return this.elements[4] * x + this.elements[5] * y + this.elements[7]; + if (!w) return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; + return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w + }, + multZ: function(x, y, z, w) { + if (!w) return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; + return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w + }, + multW: function(x, y, z, w) { + if (!w) return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15]; + return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w + }, + invert: function() { + var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4]; + var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4]; + var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4]; + var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5]; + var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5]; + var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6]; + var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12]; + var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12]; + var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12]; + var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13]; + var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13]; + var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14]; + var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; + if (Math.abs(fDet) <= 1.0E-9) return false; + var kInv = []; + kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3; + kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1; + kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0; + kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0; + kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3; + kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1; + kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0; + kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0; + kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3; + kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1; + kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0; + kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0; + kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3; + kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1; + kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0; + kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0; + var fInvDet = 1 / fDet; + kInv[0] *= fInvDet; + kInv[1] *= fInvDet; + kInv[2] *= fInvDet; + kInv[3] *= fInvDet; + kInv[4] *= fInvDet; + kInv[5] *= fInvDet; + kInv[6] *= fInvDet; + kInv[7] *= fInvDet; + kInv[8] *= fInvDet; + kInv[9] *= fInvDet; + kInv[10] *= fInvDet; + kInv[11] *= fInvDet; + kInv[12] *= fInvDet; + kInv[13] *= fInvDet; + kInv[14] *= fInvDet; + kInv[15] *= fInvDet; + this.elements = kInv.slice(); + return true + }, + toString: function() { + var str = ""; + for (var i = 0; i < 15; i++) str += this.elements[i] + ", "; + str += this.elements[15]; + return str + }, + print: function() { + var digits = printMatrixHelper(this.elements); + var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) + "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) + "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) + " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) + "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) + " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n"; + p.println(output) + }, + invTranslate: function(tx, ty, tz) { + this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1) + }, + invRotateX: function(angle) { + var c = Math.cos(-angle); + var s = Math.sin(-angle); + this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) + }, + invRotateY: function(angle) { + var c = Math.cos(-angle); + var s = Math.sin(-angle); + this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) + }, + invRotateZ: function(angle) { + var c = Math.cos(-angle); + var s = Math.sin(-angle); + this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) + }, + invScale: function(x, y, z) { + this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]) + } + }; + var PMatrixStack = p.PMatrixStack = function() { + this.matrixStack = [] + }; + PMatrixStack.prototype.load = function() { + var tmpMatrix = drawing.$newPMatrix(); + if (arguments.length === 1) tmpMatrix.set(arguments[0]); + else tmpMatrix.set(arguments); + this.matrixStack.push(tmpMatrix) + }; + Drawing2D.prototype.$newPMatrix = function() { + return new PMatrix2D + }; + Drawing3D.prototype.$newPMatrix = function() { + return new PMatrix3D + }; + PMatrixStack.prototype.push = function() { + this.matrixStack.push(this.peek()) + }; + PMatrixStack.prototype.pop = function() { + return this.matrixStack.pop() + }; + PMatrixStack.prototype.peek = function() { + var tmpMatrix = drawing.$newPMatrix(); + tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]); + return tmpMatrix + }; + PMatrixStack.prototype.mult = function(matrix) { + this.matrixStack[this.matrixStack.length - 1].apply(matrix) + }; + p.split = function(str, delim) { + return str.split(delim) + }; + p.splitTokens = function(str, tokens) { + if (tokens === undef) return str.split(/\s+/g); + var chars = tokens.split(/()/g), + buffer = "", + len = str.length, + i, c, tokenized = []; + for (i = 0; i < len; i++) { + c = str[i]; + if (chars.indexOf(c) > -1) { + if (buffer !== "") tokenized.push(buffer); + buffer = "" + } else buffer += c + } + if (buffer !== "") tokenized.push(buffer); + return tokenized + }; + p.append = function(array, element) { + array[array.length] = element; + return array + }; + p.concat = function(array1, array2) { + return array1.concat(array2) + }; + p.sort = function(array, numElem) { + var ret = []; + if (array.length > 0) { + var elemsToCopy = numElem > 0 ? numElem : array.length; + for (var i = 0; i < elemsToCopy; i++) ret.push(array[i]); + if (typeof array[0] === "string") ret.sort(); + else ret.sort(function(a, b) { + return a - b + }); + if (numElem > 0) for (var j = ret.length; j < array.length; j++) ret.push(array[j]) + } + return ret + }; + p.splice = function(array, value, index) { + if (value.length === 0) return array; + if (value instanceof Array) for (var i = 0, j = index; i < value.length; j++, i++) array.splice(j, 0, value[i]); + else array.splice(index, 0, value); + return array + }; + p.subset = function(array, offset, length) { + var end = length !== undef ? offset + length : array.length; + return array.slice(offset, end) + }; + p.join = function(array, seperator) { + return array.join(seperator) + }; + p.shorten = function(ary) { + var newary = []; + var len = ary.length; + for (var i = 0; i < len; i++) newary[i] = ary[i]; + newary.pop(); + return newary + }; + p.expand = function(ary, targetSize) { + var temp = ary.slice(0), + newSize = targetSize || ary.length * 2; + temp.length = newSize; + return temp + }; + p.arrayCopy = function() { + var src, srcPos = 0, + dest, destPos = 0, + length; + if (arguments.length === 2) { + src = arguments[0]; + dest = arguments[1]; + length = src.length + } else if (arguments.length === 3) { + src = arguments[0]; + dest = arguments[1]; + length = arguments[2] + } else if (arguments.length === 5) { + src = arguments[0]; + srcPos = arguments[1]; + dest = arguments[2]; + destPos = arguments[3]; + length = arguments[4] + } + for (var i = srcPos, j = destPos; i < length + srcPos; i++, j++) if (dest[j] !== undef) dest[j] = src[i]; + else throw "array index out of bounds exception"; + }; + p.reverse = function(array) { + return array.reverse() + }; + p.mix = function(a, b, f) { + return a + ((b - a) * f >> 8) + }; + p.peg = function(n) { + return n < 0 ? 0 : n > 255 ? 255 : n + }; + p.modes = function() { + var ALPHA_MASK = 4278190080, + RED_MASK = 16711680, + GREEN_MASK = 65280, + BLUE_MASK = 255, + min = Math.min, + max = Math.max; + + function applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) { + var a = min(((c1 & 4278190080) >>> 24) + f, 255) << 24; + var r = ar + ((cr - ar) * f >> 8); + r = (r < 0 ? 0 : r > 255 ? 255 : r) << 16; + var g = ag + ((cg - ag) * f >> 8); + g = (g < 0 ? 0 : g > 255 ? 255 : g) << 8; + var b = ab + ((cb - ab) * f >> 8); + b = b < 0 ? 0 : b > 255 ? 255 : b; + return a | r | g | b + } + return { + replace: function(c1, c2) { + return c2 + }, + blend: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = c1 & RED_MASK, + ag = c1 & GREEN_MASK, + ab = c1 & BLUE_MASK, + br = c2 & RED_MASK, + bg = c2 & GREEN_MASK, + bb = c2 & BLUE_MASK; + return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab) * f >> 8) & BLUE_MASK + }, + add: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24; + return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | min((c1 & RED_MASK) + ((c2 & RED_MASK) >> 8) * f, RED_MASK) & RED_MASK | min((c1 & GREEN_MASK) + ((c2 & GREEN_MASK) >> 8) * f, GREEN_MASK) & GREEN_MASK | min((c1 & BLUE_MASK) + ((c2 & BLUE_MASK) * f >> 8), BLUE_MASK) + }, + subtract: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24; + return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max((c1 & RED_MASK) - ((c2 & RED_MASK) >> 8) * f, GREEN_MASK) & RED_MASK | max((c1 & GREEN_MASK) - ((c2 & GREEN_MASK) >> 8) * f, BLUE_MASK) & GREEN_MASK | max((c1 & BLUE_MASK) - ((c2 & BLUE_MASK) * f >> 8), 0) + }, + lightest: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24; + return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f) & RED_MASK | max(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f) & GREEN_MASK | max(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8) + }, + darkest: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = c1 & RED_MASK, + ag = c1 & GREEN_MASK, + ab = c1 & BLUE_MASK, + br = min(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f), + bg = min(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f), + bb = min(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8); + return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab) * f >> 8) & BLUE_MASK + }, + difference: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = ar > br ? ar - br : br - ar, + cg = ag > bg ? ag - bg : bg - ag, + cb = ab > bb ? ab - bb : bb - ab; + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + exclusion: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = ar + br - (ar * br >> 7), + cg = ag + bg - (ag * bg >> 7), + cb = ab + bb - (ab * bb >> 7); + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + multiply: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = ar * br >> 8, + cg = ag * bg >> 8, + cb = ab * bb >> 8; + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + screen: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = 255 - ((255 - ar) * (255 - br) >> 8), + cg = 255 - ((255 - ag) * (255 - bg) >> 8), + cb = 255 - ((255 - ab) * (255 - bb) >> 8); + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + hard_light: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = br < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), + cg = bg < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), + cb = bb < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + soft_light: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = (ar * br >> 7) + (ar * ar >> 8) - (ar * ar * br >> 15), + cg = (ag * bg >> 7) + (ag * ag >> 8) - (ag * ag * bg >> 15), + cb = (ab * bb >> 7) + (ab * ab >> 8) - (ab * ab * bb >> 15); + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + overlay: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK, + cr = ar < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), + cg = ag < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), + cb = ab < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + dodge: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK; + var cr = 255; + if (br !== 255) { + cr = (ar << 8) / (255 - br); + cr = cr < 0 ? 0 : cr > 255 ? 255 : cr + } + var cg = 255; + if (bg !== 255) { + cg = (ag << 8) / (255 - bg); + cg = cg < 0 ? 0 : cg > 255 ? 255 : cg + } + var cb = 255; + if (bb !== 255) { + cb = (ab << 8) / (255 - bb); + cb = cb < 0 ? 0 : cb > 255 ? 255 : cb + } + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + }, + burn: function(c1, c2) { + var f = (c2 & ALPHA_MASK) >>> 24, + ar = (c1 & RED_MASK) >> 16, + ag = (c1 & GREEN_MASK) >> 8, + ab = c1 & BLUE_MASK, + br = (c2 & RED_MASK) >> 16, + bg = (c2 & GREEN_MASK) >> 8, + bb = c2 & BLUE_MASK; + var cr = 0; + if (br !== 0) { + cr = (255 - ar << 8) / br; + cr = 255 - (cr < 0 ? 0 : cr > 255 ? 255 : cr) + } + var cg = 0; + if (bg !== 0) { + cg = (255 - ag << 8) / bg; + cg = 255 - (cg < 0 ? 0 : cg > 255 ? 255 : cg) + } + var cb = 0; + if (bb !== 0) { + cb = (255 - ab << 8) / bb; + cb = 255 - (cb < 0 ? 0 : cb > 255 ? 255 : cb) + } + return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) + } + } + }(); + + function color$4(aValue1, aValue2, aValue3, aValue4) { + var r, g, b, a; + if (curColorMode === 3) { + var rgb = p.color.toRGB(aValue1, aValue2, aValue3); + r = rgb[0]; + g = rgb[1]; + b = rgb[2] + } else { + r = Math.round(255 * (aValue1 / colorModeX)); + g = Math.round(255 * (aValue2 / colorModeY)); + b = Math.round(255 * (aValue3 / colorModeZ)) + } + a = Math.round(255 * (aValue4 / colorModeA)); + r = r < 0 ? 0 : r; + g = g < 0 ? 0 : g; + b = b < 0 ? 0 : b; + a = a < 0 ? 0 : a; + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + a = a > 255 ? 255 : a; + return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 + } + function color$2(aValue1, aValue2) { + var a; + if (aValue1 & 4278190080) { + a = Math.round(255 * (aValue2 / colorModeA)); + a = a > 255 ? 255 : a; + a = a < 0 ? 0 : a; + return aValue1 - (aValue1 & 4278190080) + (a << 24 & 4278190080) + } + if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, aValue2); + if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colorModeZ, aValue2) + } + function color$1(aValue1) { + if (aValue1 <= colorModeX && aValue1 >= 0) { + if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, colorModeA); + if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colorModeZ, colorModeA) + } + if (aValue1) { + if (aValue1 > 2147483647) aValue1 -= 4294967296; + return aValue1 + } + } + p.color = function(aValue1, aValue2, aValue3, aValue4) { + if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef && aValue4 !== undef) return color$4(aValue1, aValue2, aValue3, aValue4); + if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) return color$4(aValue1, aValue2, aValue3, colorModeA); + if (aValue1 !== undef && aValue2 !== undef) return color$2(aValue1, aValue2); + if (typeof aValue1 === "number") return color$1(aValue1); + return color$4(colorModeX, colorModeY, colorModeZ, colorModeA) + }; + p.color.toString = function(colorInt) { + return "rgba(" + ((colorInt >> 16) & 255) + "," + ((colorInt >> 8) & 255) + "," + (colorInt & 255) + "," + ((colorInt >> 24) & 255) / 255 + ")" + }; + p.color.toInt = function(r, g, b, a) { + return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 + }; + p.color.toArray = function(colorInt) { + return [(colorInt >> 16) & 255, (colorInt >> 8) & 255, colorInt & 255, (colorInt >> 24) & 255] + }; + p.color.toGLArray = function(colorInt) { + return [((colorInt & 16711680) >>> 16) / 255, ((colorInt >> 8) & 255) / 255, (colorInt & 255) / 255, ((colorInt >> 24) & 255) / 255] + }; + p.color.toRGB = function(h, s, b) { + h = h > colorModeX ? colorModeX : h; + s = s > colorModeY ? colorModeY : s; + b = b > colorModeZ ? colorModeZ : b; + h = h / colorModeX * 360; + s = s / colorModeY * 100; + b = b / colorModeZ * 100; + var br = Math.round(b / 100 * 255); + if (s === 0) return [br, br, br]; + var hue = h % 360; + var f = hue % 60; + var p = Math.round(b * (100 - s) / 1E4 * 255); + var q = Math.round(b * (6E3 - s * f) / 6E5 * 255); + var t = Math.round(b * (6E3 - s * (60 - f)) / 6E5 * 255); + switch (Math.floor(hue / 60)) { + case 0: + return [br, t, p]; + case 1: + return [q, br, p]; + case 2: + return [p, br, t]; + case 3: + return [p, q, br]; + case 4: + return [t, p, br]; + case 5: + return [br, p, q] + } + }; + + function colorToHSB(colorInt) { + var red, green, blue; + red = ((colorInt >> 16) & 255) / 255; + green = ((colorInt >> 8) & 255) / 255; + blue = (colorInt & 255) / 255; + var max = p.max(p.max(red, green), blue), + min = p.min(p.min(red, green), blue), + hue, saturation; + if (min === max) return [0, 0, max * colorModeZ]; + saturation = (max - min) / max; + if (red === max) hue = (green - blue) / (max - min); + else if (green === max) hue = 2 + (blue - red) / (max - min); + else hue = 4 + (red - green) / (max - min); + hue /= 6; + if (hue < 0) hue += 1; + else if (hue > 1) hue -= 1; + return [hue * colorModeX, saturation * colorModeY, max * colorModeZ] + } + p.brightness = function(colInt) { + return colorToHSB(colInt)[2] + }; + p.saturation = function(colInt) { + return colorToHSB(colInt)[1] + }; + p.hue = function(colInt) { + return colorToHSB(colInt)[0] + }; + p.red = function(aColor) { + return ((aColor >> 16) & 255) / 255 * colorModeX + }; + p.green = function(aColor) { + return ((aColor & 65280) >>> 8) / 255 * colorModeY + }; + p.blue = function(aColor) { + return (aColor & 255) / 255 * colorModeZ + }; + p.alpha = function(aColor) { + return ((aColor >> 24) & 255) / 255 * colorModeA + }; + p.lerpColor = function(c1, c2, amt) { + var r, g, b, a, r1, g1, b1, a1, r2, g2, b2, a2; + var hsb1, hsb2, rgb, h, s; + var colorBits1 = p.color(c1); + var colorBits2 = p.color(c2); + if (curColorMode === 3) { + hsb1 = colorToHSB(colorBits1); + a1 = ((colorBits1 >> 24) & 255) / colorModeA; + hsb2 = colorToHSB(colorBits2); + a2 = ((colorBits2 & 4278190080) >>> 24) / colorModeA; + h = p.lerp(hsb1[0], hsb2[0], amt); + s = p.lerp(hsb1[1], hsb2[1], amt); + b = p.lerp(hsb1[2], hsb2[2], amt); + rgb = p.color.toRGB(h, s, b); + a = p.lerp(a1, a2, amt) * colorModeA; + return a << 24 & 4278190080 | (rgb[0] & 255) << 16 | (rgb[1] & 255) << 8 | rgb[2] & 255 + } + r1 = (colorBits1 >> 16) & 255; + g1 = (colorBits1 >> 8) & 255; + b1 = colorBits1 & 255; + a1 = ((colorBits1 >> 24) & 255) / colorModeA; + r2 = (colorBits2 & 16711680) >>> 16; + g2 = (colorBits2 >> 8) & 255; + b2 = colorBits2 & 255; + a2 = ((colorBits2 >> 24) & 255) / colorModeA; + r = p.lerp(r1, r2, amt) | 0; + g = p.lerp(g1, g2, amt) | 0; + b = p.lerp(b1, b2, amt) | 0; + a = p.lerp(a1, a2, amt) * colorModeA; + return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 + }; + p.colorMode = function() { + curColorMode = arguments[0]; + if (arguments.length > 1) { + colorModeX = arguments[1]; + colorModeY = arguments[2] || arguments[1]; + colorModeZ = arguments[3] || arguments[1]; + colorModeA = arguments[4] || arguments[1] + } + }; + p.blendColor = function(c1, c2, mode) { + if (mode === 0) return p.modes.replace(c1, c2); + else if (mode === 1) return p.modes.blend(c1, c2); + else if (mode === 2) return p.modes.add(c1, c2); + else if (mode === 4) return p.modes.subtract(c1, c2); + else if (mode === 8) return p.modes.lightest(c1, c2); + else if (mode === 16) return p.modes.darkest(c1, c2); + else if (mode === 32) return p.modes.difference(c1, c2); + else if (mode === 64) return p.modes.exclusion(c1, c2); + else if (mode === 128) return p.modes.multiply(c1, c2); + else if (mode === 256) return p.modes.screen(c1, c2); + else if (mode === 1024) return p.modes.hard_light(c1, c2); + else if (mode === 2048) return p.modes.soft_light(c1, c2); + else if (mode === 512) return p.modes.overlay(c1, c2); + else if (mode === 4096) return p.modes.dodge(c1, c2); + else if (mode === 8192) return p.modes.burn(c1, c2) + }; + + function saveContext() { + curContext.save() + } + function restoreContext() { + curContext.restore(); + isStrokeDirty = true; + isFillDirty = true + } + p.printMatrix = function() { + modelView.print() + }; + Drawing2D.prototype.translate = function(x, y) { + modelView.translate(x, y); + modelViewInv.invTranslate(x, y); + curContext.translate(x, y) + }; + Drawing3D.prototype.translate = function(x, y, z) { + modelView.translate(x, y, z); + modelViewInv.invTranslate(x, y, z) + }; + Drawing2D.prototype.scale = function(x, y) { + modelView.scale(x, y); + modelViewInv.invScale(x, y); + curContext.scale(x, y || x) + }; + Drawing3D.prototype.scale = function(x, y, z) { + modelView.scale(x, y, z); + modelViewInv.invScale(x, y, z) + }; + Drawing2D.prototype.transform = function(pmatrix) { + var e = pmatrix.array(); + curContext.transform(e[0], e[3], e[1], e[4], e[2], e[5]) + }; + Drawing3D.prototype.transformm = function(pmatrix3d) { + throw "p.transform is currently not supported in 3D mode"; + }; + Drawing2D.prototype.pushMatrix = function() { + userMatrixStack.load(modelView); + userReverseMatrixStack.load(modelViewInv); + saveContext() + }; + Drawing3D.prototype.pushMatrix = function() { + userMatrixStack.load(modelView); + userReverseMatrixStack.load(modelViewInv) + }; + Drawing2D.prototype.popMatrix = function() { + modelView.set(userMatrixStack.pop()); + modelViewInv.set(userReverseMatrixStack.pop()); + restoreContext() + }; + Drawing3D.prototype.popMatrix = function() { + modelView.set(userMatrixStack.pop()); + modelViewInv.set(userReverseMatrixStack.pop()) + }; + Drawing2D.prototype.resetMatrix = function() { + modelView.reset(); + modelViewInv.reset(); + curContext.setTransform(1, 0, 0, 1, 0, 0) + }; + Drawing3D.prototype.resetMatrix = function() { + modelView.reset(); + modelViewInv.reset() + }; + DrawingShared.prototype.applyMatrix = function() { + var a = arguments; + modelView.apply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); + modelViewInv.invApply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]) + }; + Drawing2D.prototype.applyMatrix = function() { + var a = arguments; + for (var cnt = a.length; cnt < 16; cnt++) a[cnt] = 0; + a[10] = a[15] = 1; + DrawingShared.prototype.applyMatrix.apply(this, a) + }; + p.rotateX = function(angleInRadians) { + modelView.rotateX(angleInRadians); + modelViewInv.invRotateX(angleInRadians) + }; + Drawing2D.prototype.rotateZ = function() { + throw "rotateZ() is not supported in 2D mode. Use rotate(float) instead."; + }; + Drawing3D.prototype.rotateZ = function(angleInRadians) { + modelView.rotateZ(angleInRadians); + modelViewInv.invRotateZ(angleInRadians) + }; + p.rotateY = function(angleInRadians) { + modelView.rotateY(angleInRadians); + modelViewInv.invRotateY(angleInRadians) + }; + Drawing2D.prototype.rotate = function(angleInRadians) { + modelView.rotateZ(angleInRadians); + modelViewInv.invRotateZ(angleInRadians); + curContext.rotate(angleInRadians) + }; + Drawing3D.prototype.rotate = function(angleInRadians) { + p.rotateZ(angleInRadians) + }; + Drawing2D.prototype.shearX = function(angleInRadians) { + modelView.shearX(angleInRadians); + curContext.transform(1, 0, angleInRadians, 1, 0, 0) + }; + Drawing3D.prototype.shearX = function(angleInRadians) { + modelView.shearX(angleInRadians) + }; + Drawing2D.prototype.shearY = function(angleInRadians) { + modelView.shearY(angleInRadians); + curContext.transform(1, angleInRadians, 0, 1, 0, 0) + }; + Drawing3D.prototype.shearY = function(angleInRadians) { + modelView.shearY(angleInRadians) + }; + p.pushStyle = function() { + saveContext(); + p.pushMatrix(); + var newState = { + "doFill": doFill, + "currentFillColor": currentFillColor, + "doStroke": doStroke, + "currentStrokeColor": currentStrokeColor, + "curTint": curTint, + "curRectMode": curRectMode, + "curColorMode": curColorMode, + "colorModeX": colorModeX, + "colorModeZ": colorModeZ, + "colorModeY": colorModeY, + "colorModeA": colorModeA, + "curTextFont": curTextFont, + "horizontalTextAlignment": horizontalTextAlignment, + "verticalTextAlignment": verticalTextAlignment, + "textMode": textMode, + "curFontName": curFontName, + "curTextSize": curTextSize, + "curTextAscent": curTextAscent, + "curTextDescent": curTextDescent, + "curTextLeading": curTextLeading + }; + styleArray.push(newState) + }; + p.popStyle = function() { + var oldState = styleArray.pop(); + if (oldState) { + restoreContext(); + p.popMatrix(); + doFill = oldState.doFill; + currentFillColor = oldState.currentFillColor; + doStroke = oldState.doStroke; + currentStrokeColor = oldState.currentStrokeColor; + curTint = oldState.curTint; + curRectMode = oldState.curRectMode; + curColorMode = oldState.curColorMode; + colorModeX = oldState.colorModeX; + colorModeZ = oldState.colorModeZ; + colorModeY = oldState.colorModeY; + colorModeA = oldState.colorModeA; + curTextFont = oldState.curTextFont; + curFontName = oldState.curFontName; + curTextSize = oldState.curTextSize; + horizontalTextAlignment = oldState.horizontalTextAlignment; + verticalTextAlignment = oldState.verticalTextAlignment; + textMode = oldState.textMode; + curTextAscent = oldState.curTextAscent; + curTextDescent = oldState.curTextDescent; + curTextLeading = oldState.curTextLeading + } else throw "Too many popStyle() without enough pushStyle()"; + }; + p.year = function() { + return (new Date).getFullYear() + }; + p.month = function() { + return (new Date).getMonth() + 1 + }; + p.day = function() { + return (new Date).getDate() + }; + p.hour = function() { + return (new Date).getHours() + }; + p.minute = function() { + return (new Date).getMinutes() + }; + p.second = function() { + return (new Date).getSeconds() + }; + p.millis = function() { + return Date.now() - start + }; + + function redrawHelper() { + var sec = (Date.now() - timeSinceLastFPS) / 1E3; + framesSinceLastFPS++; + var fps = framesSinceLastFPS / sec; + if (sec > 0.5) { + timeSinceLastFPS = Date.now(); + framesSinceLastFPS = 0; + p.__frameRate = fps + } + p.frameCount++ + } + Drawing2D.prototype.redraw = function() { + redrawHelper(); + curContext.lineWidth = lineWidth; + var pmouseXLastEvent = p.pmouseX, + pmouseYLastEvent = p.pmouseY; + p.pmouseX = pmouseXLastFrame; + p.pmouseY = pmouseYLastFrame; + saveContext(); + p.draw(); + restoreContext(); + pmouseXLastFrame = p.mouseX; + pmouseYLastFrame = p.mouseY; + p.pmouseX = pmouseXLastEvent; + p.pmouseY = pmouseYLastEvent + }; + Drawing3D.prototype.redraw = function() { + redrawHelper(); + var pmouseXLastEvent = p.pmouseX, + pmouseYLastEvent = p.pmouseY; + p.pmouseX = pmouseXLastFrame; + p.pmouseY = pmouseYLastFrame; + curContext.clear(curContext.DEPTH_BUFFER_BIT); + curContextCache = { + attributes: {}, + locations: {} + }; + p.noLights(); + p.lightFalloff(1, 0, 0); + p.shininess(1); + p.ambient(255, 255, 255); + p.specular(0, 0, 0); + p.emissive(0, 0, 0); + p.camera(); + p.draw(); + pmouseXLastFrame = p.mouseX; + pmouseYLastFrame = p.mouseY; + p.pmouseX = pmouseXLastEvent; + p.pmouseY = pmouseYLastEvent + }; + p.noLoop = function() { + doLoop = false; + loopStarted = false; + clearInterval(looping); + curSketch.onPause() + }; + p.loop = function() { + if (loopStarted) return; + timeSinceLastFPS = Date.now(); + framesSinceLastFPS = 0; + looping = window.setInterval(function() { + try { + curSketch.onFrameStart(); + p.redraw(); + curSketch.onFrameEnd() + } catch(e_loop) { + window.clearInterval(looping); + throw e_loop; + } + }, + curMsPerFrame); + doLoop = true; + loopStarted = true; + curSketch.onLoop() + }; + p.frameRate = function(aRate) { + curFrameRate = aRate; + curMsPerFrame = 1E3 / curFrameRate; + if (doLoop) { + p.noLoop(); + p.loop() + } + }; + var eventHandlers = []; + + function attachEventHandler(elem, type, fn) { + if (elem.addEventListener) elem.addEventListener(type, fn, false); + else elem.attachEvent("on" + type, fn); + eventHandlers.push({ + elem: elem, + type: type, + fn: fn + }) + } + function detachEventHandler(eventHandler) { + var elem = eventHandler.elem, + type = eventHandler.type, + fn = eventHandler.fn; + if (elem.removeEventListener) elem.removeEventListener(type, fn, false); + else if (elem.detachEvent) elem.detachEvent("on" + type, fn) + } + p.exit = function() { + window.clearInterval(looping); + removeInstance(p.externals.canvas.id); + delete curElement.onmousedown; + for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if (Processing.lib[lib].hasOwnProperty("detach")) Processing.lib[lib].detach(p); + var i = eventHandlers.length; + while (i--) detachEventHandler(eventHandlers[i]); + curSketch.onExit() + }; + p.cursor = function() { + if (arguments.length > 1 || arguments.length === 1 && arguments[0] instanceof p.PImage) { + var image = arguments[0], + x, y; + if (arguments.length >= 3) { + x = arguments[1]; + y = arguments[2]; + if (x < 0 || y < 0 || y >= image.height || x >= image.width) throw "x and y must be non-negative and less than the dimensions of the image"; + } else { + x = image.width >>> 1; + y = image.height >>> 1 + } + var imageDataURL = image.toDataURL(); + var style = 'url("' + imageDataURL + '") ' + x + " " + y + ", default"; + curCursor = curElement.style.cursor = style + } else if (arguments.length === 1) { + var mode = arguments[0]; + curCursor = curElement.style.cursor = mode + } else curCursor = curElement.style.cursor = oldCursor + }; + p.noCursor = function() { + curCursor = curElement.style.cursor = PConstants.NOCURSOR + }; + p.link = function(href, target) { + if (target !== undef) window.open(href, target); + else window.location = href + }; + p.beginDraw = nop; + p.endDraw = nop; + Drawing2D.prototype.toImageData = function(x, y, w, h) { + x = x !== undef ? x : 0; + y = y !== undef ? y : 0; + w = w !== undef ? w : p.width; + h = h !== undef ? h : p.height; + return curContext.getImageData(x, y, w, h) + }; + Drawing3D.prototype.toImageData = function(x, y, w, h) { + x = x !== undef ? x : 0; + y = y !== undef ? y : 0; + w = w !== undef ? w : p.width; + h = h !== undef ? h : p.height; + var c = document.createElement("canvas"), + ctx = c.getContext("2d"), + obj = ctx.createImageData(w, h), + uBuff = new Uint8Array(w * h * 4); + curContext.readPixels(x, y, w, h, curContext.RGBA, curContext.UNSIGNED_BYTE, uBuff); + for (var i = 0, ul = uBuff.length, obj_data = obj.data; i < ul; i++) obj_data[i] = uBuff[(h - 1 - Math.floor(i / 4 / w)) * w * 4 + i % (w * 4)]; + return obj + }; + p.status = function(text) { + window.status = text + }; + p.binary = function(num, numBits) { + var bit; + if (numBits > 0) bit = numBits; + else if (num instanceof Char) { + bit = 16; + num |= 0 + } else { + bit = 32; + while (bit > 1 && !(num >>> bit - 1 & 1)) bit-- + } + var result = ""; + while (bit > 0) result += num >>> --bit & 1 ? "1" : "0"; + return result + }; + p.unbinary = function(binaryString) { + var i = binaryString.length - 1, + mask = 1, + result = 0; + while (i >= 0) { + var ch = binaryString[i--]; + if (ch !== "0" && ch !== "1") throw "the value passed into unbinary was not an 8 bit binary number"; + if (ch === "1") result += mask; + mask <<= 1 + } + return result + }; + + function nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) { + var sign = value < 0 ? minus : plus; + var autoDetectDecimals = rightDigits === 0; + var rightDigitsOfDefault = rightDigits === undef || rightDigits < 0 ? 0 : rightDigits; + var absValue = Math.abs(value); + if (autoDetectDecimals) { + rightDigitsOfDefault = 1; + absValue *= 10; + while (Math.abs(Math.round(absValue) - absValue) > 1.0E-6 && rightDigitsOfDefault < 7) { + ++rightDigitsOfDefault; + absValue *= 10 + } + } else if (rightDigitsOfDefault !== 0) absValue *= Math.pow(10, rightDigitsOfDefault); + var number, doubled = absValue * 2; + if (Math.floor(absValue) === absValue) number = absValue; + else if (Math.floor(doubled) === doubled) { + var floored = Math.floor(absValue); + number = floored + floored % 2 + } else number = Math.round(absValue); + var buffer = ""; + var totalDigits = leftDigits + rightDigitsOfDefault; + while (totalDigits > 0 || number > 0) { + totalDigits--; + buffer = "" + number % 10 + buffer; + number = Math.floor(number / 10) + } + if (group !== undef) { + var i = buffer.length - 3 - rightDigitsOfDefault; + while (i > 0) { + buffer = buffer.substring(0, i) + group + buffer.substring(i); + i -= 3 + } + } + if (rightDigitsOfDefault > 0) return sign + buffer.substring(0, buffer.length - rightDigitsOfDefault) + "." + buffer.substring(buffer.length - rightDigitsOfDefault, buffer.length); + return sign + buffer + } + function nfCore(value, plus, minus, leftDigits, rightDigits, group) { + if (value instanceof Array) { + var arr = []; + for (var i = 0, len = value.length; i < len; i++) arr.push(nfCoreScalar(value[i], plus, minus, leftDigits, rightDigits, group)); + return arr + } + return nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) + } + p.nf = function(value, leftDigits, rightDigits) { + return nfCore(value, "", "-", leftDigits, rightDigits) + }; + p.nfs = function(value, leftDigits, rightDigits) { + return nfCore(value, " ", "-", leftDigits, rightDigits) + }; + p.nfp = function(value, leftDigits, rightDigits) { + return nfCore(value, "+", "-", leftDigits, rightDigits) + }; + p.nfc = function(value, leftDigits, rightDigits) { + return nfCore(value, "", "-", leftDigits, rightDigits, ",") + }; + var decimalToHex = function(d, padding) { + padding = padding === undef || padding === null ? padding = 8 : padding; + if (d < 0) d = 4294967295 + d + 1; + var hex = Number(d).toString(16).toUpperCase(); + while (hex.length < padding) hex = "0" + hex; + if (hex.length >= padding) hex = hex.substring(hex.length - padding, hex.length); + return hex + }; + p.hex = function(value, len) { + if (arguments.length === 1) if (value instanceof Char) len = 4; + else len = 8; + return decimalToHex(value, len) + }; + + function unhexScalar(hex) { + var value = parseInt("0x" + hex, 16); + if (value > 2147483647) value -= 4294967296; + return value + } + p.unhex = function(hex) { + if (hex instanceof Array) { + var arr = []; + for (var i = 0; i < hex.length; i++) arr.push(unhexScalar(hex[i])); + return arr + } + return unhexScalar(hex) + }; + p.loadStrings = function(filename) { + if (localStorage[filename]) return localStorage[filename].split("\n"); + var filecontent = ajax(filename); + if (typeof filecontent !== "string" || filecontent === "") return []; + filecontent = filecontent.replace(/(\r\n?)/g, "\n").replace(/\n$/, ""); + return filecontent.split("\n") + }; + p.saveStrings = function(filename, strings) { + localStorage[filename] = strings.join("\n") + }; + p.loadBytes = function(url) { + var string = ajax(url); + var ret = []; + for (var i = 0; i < string.length; i++) ret.push(string.charCodeAt(i)); + return ret + }; + + function removeFirstArgument(args) { + return Array.prototype.slice.call(args, 1) + } + p.matchAll = function(aString, aRegExp) { + var results = [], + latest; + var regexp = new RegExp(aRegExp, "g"); + while ((latest = regexp.exec(aString)) !== null) { + results.push(latest); + if (latest[0].length === 0)++regexp.lastIndex + } + return results.length > 0 ? results : null + }; + p.__contains = function(subject, subStr) { + if (typeof subject !== "string") return subject.contains.apply(subject, removeFirstArgument(arguments)); + return subject !== null && subStr !== null && typeof subStr === "string" && subject.indexOf(subStr) > -1 + }; + p.__replaceAll = function(subject, regex, replacement) { + if (typeof subject !== "string") return subject.replaceAll.apply(subject, removeFirstArgument(arguments)); + return subject.replace(new RegExp(regex, "g"), replacement) + }; + p.__replaceFirst = function(subject, regex, replacement) { + if (typeof subject !== "string") return subject.replaceFirst.apply(subject, removeFirstArgument(arguments)); + return subject.replace(new RegExp(regex, ""), replacement) + }; + p.__replace = function(subject, what, replacement) { + if (typeof subject !== "string") return subject.replace.apply(subject, removeFirstArgument(arguments)); + if (what instanceof RegExp) return subject.replace(what, replacement); + if (typeof what !== "string") what = what.toString(); + if (what === "") return subject; + var i = subject.indexOf(what); + if (i < 0) return subject; + var j = 0, + result = ""; + do { + result += subject.substring(j, i) + replacement; + j = i + what.length + } while ((i = subject.indexOf(what, j)) >= 0); + return result + subject.substring(j) + }; + p.__equals = function(subject, other) { + if (subject.equals instanceof + Function) return subject.equals.apply(subject, removeFirstArgument(arguments)); + return subject.valueOf() === other.valueOf() + }; + p.__equalsIgnoreCase = function(subject, other) { + if (typeof subject !== "string") return subject.equalsIgnoreCase.apply(subject, removeFirstArgument(arguments)); + return subject.toLowerCase() === other.toLowerCase() + }; + p.__toCharArray = function(subject) { + if (typeof subject !== "string") return subject.toCharArray.apply(subject, removeFirstArgument(arguments)); + var chars = []; + for (var i = 0, len = subject.length; i < len; ++i) chars[i] = new Char(subject.charAt(i)); + return chars + }; + p.__split = function(subject, regex, limit) { + if (typeof subject !== "string") return subject.split.apply(subject, removeFirstArgument(arguments)); + var pattern = new RegExp(regex); + if (limit === undef || limit < 1) return subject.split(pattern); + var result = [], + currSubject = subject, + pos; + while ((pos = currSubject.search(pattern)) !== -1 && result.length < limit - 1) { + var match = pattern.exec(currSubject).toString(); + result.push(currSubject.substring(0, pos)); + currSubject = currSubject.substring(pos + match.length) + } + if (pos !== -1 || currSubject !== "") result.push(currSubject); + return result + }; + p.__codePointAt = function(subject, idx) { + var code = subject.charCodeAt(idx), + hi, low; + if (55296 <= code && code <= 56319) { + hi = code; + low = subject.charCodeAt(idx + 1); + return (hi - 55296) * 1024 + (low - 56320) + 65536 + } + return code + }; + p.match = function(str, regexp) { + return str.match(regexp) + }; + p.__matches = function(str, regexp) { + return (new RegExp(regexp)).test(str) + }; + p.__startsWith = function(subject, prefix, toffset) { + if (typeof subject !== "string") return subject.startsWith.apply(subject, removeFirstArgument(arguments)); + toffset = toffset || 0; + if (toffset < 0 || toffset > subject.length) return false; + return prefix === "" || prefix === subject ? true : subject.indexOf(prefix) === toffset + }; + p.__endsWith = function(subject, suffix) { + if (typeof subject !== "string") return subject.endsWith.apply(subject, removeFirstArgument(arguments)); + var suffixLen = suffix ? suffix.length : 0; + return suffix === "" || suffix === subject ? true : subject.indexOf(suffix) === subject.length - suffixLen + }; + p.__hashCode = function(subject) { + if (subject.hashCode instanceof + Function) return subject.hashCode.apply(subject, removeFirstArgument(arguments)); + return virtHashCode(subject) + }; + p.__printStackTrace = function(subject) { + p.println("Exception: " + subject.toString()) + }; + var logBuffer = []; + p.println = function(message) { + var bufferLen = logBuffer.length; + if (bufferLen) { + Processing.logger.log(logBuffer.join("")); + logBuffer.length = 0 + } + if (arguments.length === 0 && bufferLen === 0) Processing.logger.log(""); + else if (arguments.length !== 0) Processing.logger.log(message) + }; + p.print = function(message) { + logBuffer.push(message) + }; + p.str = function(val) { + if (val instanceof Array) { + var arr = []; + for (var i = 0; i < val.length; i++) arr.push(val[i].toString() + ""); + return arr + } + return val.toString() + "" + }; + p.trim = function(str) { + if (str instanceof Array) { + var arr = []; + for (var i = 0; i < str.length; i++) arr.push(str[i].replace(/^\s*/, "").replace(/\s*$/, "").replace(/\r*$/, "")); + return arr + } + return str.replace(/^\s*/, "").replace(/\s*$/, "").replace(/\r*$/, "") + }; + + function booleanScalar(val) { + if (typeof val === "number") return val !== 0; + if (typeof val === "boolean") return val; + if (typeof val === "string") return val.toLowerCase() === "true"; + if (val instanceof Char) return val.code === 49 || val.code === 84 || val.code === 116 + } + p.parseBoolean = function(val) { + if (val instanceof Array) { + var ret = []; + for (var i = 0; i < val.length; i++) ret.push(booleanScalar(val[i])); + return ret + } + return booleanScalar(val) + }; + p.parseByte = function(what) { + if (what instanceof Array) { + var bytes = []; + for (var i = 0; i < what.length; i++) bytes.push(0 - (what[i] & 128) | what[i] & 127); + return bytes + } + return 0 - (what & 128) | what & 127 + }; + p.parseChar = function(key) { + if (typeof key === "number") return new Char(String.fromCharCode(key & 65535)); + if (key instanceof Array) { + var ret = []; + for (var i = 0; i < key.length; i++) ret.push(new Char(String.fromCharCode(key[i] & 65535))); + return ret + } + throw "char() may receive only one argument of type int, byte, int[], or byte[]."; + }; + + function floatScalar(val) { + if (typeof val === "number") return val; + if (typeof val === "boolean") return val ? 1 : 0; + if (typeof val === "string") return parseFloat(val); + if (val instanceof Char) return val.code + } + p.parseFloat = function(val) { + if (val instanceof + Array) { + var ret = []; + for (var i = 0; i < val.length; i++) ret.push(floatScalar(val[i])); + return ret + } + return floatScalar(val) + }; + + function intScalar(val, radix) { + if (typeof val === "number") return val & 4294967295; + if (typeof val === "boolean") return val ? 1 : 0; + if (typeof val === "string") { + var number = parseInt(val, radix || 10); + return number & 4294967295 + } + if (val instanceof Char) return val.code + } + p.parseInt = function(val, radix) { + if (val instanceof Array) { + var ret = []; + for (var i = 0; i < val.length; i++) if (typeof val[i] === "string" && !/^\s*[+\-]?\d+\s*$/.test(val[i])) ret.push(0); + else ret.push(intScalar(val[i], radix)); + return ret + } + return intScalar(val, radix) + }; + p.__int_cast = function(val) { + return 0 | val + }; + p.__instanceof = function(obj, type) { + if (typeof type !== "function") throw "Function is expected as type argument for instanceof operator"; + if (typeof obj === "string") return type === Object || type === String; + if (obj instanceof type) return true; + if (typeof obj !== "object" || obj === null) return false; + var objType = obj.constructor; + if (type.$isInterface) { + var interfaces = []; + while (objType) { + if (objType.$interfaces) interfaces = interfaces.concat(objType.$interfaces); + objType = objType.$base + } + while (interfaces.length > 0) { + var i = interfaces.shift(); + if (i === type) return true; + if (i.$interfaces) interfaces = interfaces.concat(i.$interfaces) + } + return false + } + while (objType.hasOwnProperty("$base")) { + objType = objType.$base; + if (objType === type) return true + } + return false + }; + p.abs = Math.abs; + p.ceil = Math.ceil; + p.constrain = function(aNumber, aMin, aMax) { + return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber + }; + p.dist = function() { + var dx, dy, dz; + if (arguments.length === 4) { + dx = arguments[0] - arguments[2]; + dy = arguments[1] - arguments[3]; + return Math.sqrt(dx * dx + dy * dy) + } + if (arguments.length === 6) { + dx = arguments[0] - arguments[3]; + dy = arguments[1] - arguments[4]; + dz = arguments[2] - arguments[5]; + return Math.sqrt(dx * dx + dy * dy + dz * dz) + } + }; + p.exp = Math.exp; + p.floor = Math.floor; + p.lerp = function(value1, value2, amt) { + return (value2 - value1) * amt + value1 + }; + p.log = Math.log; + p.mag = function(a, b, c) { + if (c) return Math.sqrt(a * a + b * b + c * c); + return Math.sqrt(a * a + b * b) + }; + p.map = function(value, istart, istop, ostart, ostop) { + return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) + }; + p.max = function() { + if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments[1] : arguments[0]; + var numbers = arguments.length === 1 ? arguments[0] : arguments; + if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; + var max = numbers[0], + count = numbers.length; + for (var i = 1; i < count; ++i) if (max < numbers[i]) max = numbers[i]; + return max + }; + p.min = function() { + if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments[0] : arguments[1]; + var numbers = arguments.length === 1 ? arguments[0] : arguments; + if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; + var min = numbers[0], + count = numbers.length; + for (var i = 1; i < count; ++i) if (min > numbers[i]) min = numbers[i]; + return min + }; + p.norm = function(aNumber, low, high) { + return (aNumber - low) / (high - low) + }; + p.pow = Math.pow; + p.round = Math.round; + p.sq = function(aNumber) { + return aNumber * aNumber + }; + p.sqrt = Math.sqrt; + p.acos = Math.acos; + p.asin = Math.asin; + p.atan = Math.atan; + p.atan2 = Math.atan2; + p.cos = Math.cos; + p.degrees = function(aAngle) { + return aAngle * 180 / Math.PI + }; + p.radians = function(aAngle) { + return aAngle / 180 * Math.PI + }; + p.sin = Math.sin; + p.tan = Math.tan; + var currentRandom = Math.random; + p.random = function() { + if (arguments.length === 0) return currentRandom(); + if (arguments.length === 1) return currentRandom() * arguments[0]; + var aMin = arguments[0], + aMax = arguments[1]; + return currentRandom() * (aMax - aMin) + aMin + }; + + function Marsaglia(i1, i2) { + var z = i1 || 362436069, + w = i2 || 521288629; + var nextInt = function() { + z = 36969 * (z & 65535) + (z >>> 16) & 4294967295; + w = 18E3 * (w & 65535) + (w >>> 16) & 4294967295; + return ((z & 65535) << 16 | w & 65535) & 4294967295 + }; + this.nextDouble = function() { + var i = nextInt() / 4294967296; + return i < 0 ? 1 + i : i + }; + this.nextInt = nextInt + } + Marsaglia.createRandomized = function() { + var now = new Date; + return new Marsaglia(now / 6E4 & 4294967295, now & 4294967295) + }; + p.randomSeed = function(seed) { + currentRandom = (new Marsaglia(seed)).nextDouble + }; + p.Random = function(seed) { + var haveNextNextGaussian = false, + nextNextGaussian, random; + this.nextGaussian = function() { + if (haveNextNextGaussian) { + haveNextNextGaussian = false; + return nextNextGaussian + } + var v1, v2, s; + do { + v1 = 2 * random() - 1; + v2 = 2 * random() - 1; + s = v1 * v1 + v2 * v2 + } while (s >= 1 || s === 0); + var multiplier = Math.sqrt(-2 * Math.log(s) / s); + nextNextGaussian = v2 * multiplier; + haveNextNextGaussian = true; + return v1 * multiplier + }; + random = seed === undef ? Math.random : (new Marsaglia(seed)).nextDouble + }; + + function PerlinNoise(seed) { + var rnd = seed !== undef ? new Marsaglia(seed) : Marsaglia.createRandomized(); + var i, j; + var perm = new Uint8Array(512); + for (i = 0; i < 256; ++i) perm[i] = i; + for (i = 0; i < 256; ++i) { + var t = perm[j = rnd.nextInt() & 255]; + perm[j] = perm[i]; + perm[i] = t + } + for (i = 0; i < 256; ++i) perm[i + 256] = perm[i]; + + function grad3d(i, x, y, z) { + var h = i & 15; + var u = h < 8 ? x : y, + v = h < 4 ? y : h === 12 || h === 14 ? x : z; + return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v) + } + function grad2d(i, x, y) { + var v = (i & 1) === 0 ? x : y; + return (i & 2) === 0 ? -v : v + } + function grad1d(i, x) { + return (i & 1) === 0 ? -x : x + } + function lerp(t, a, b) { + return a + t * (b - a) + } + this.noise3d = function(x, y, z) { + var X = Math.floor(x) & 255, + Y = Math.floor(y) & 255, + Z = Math.floor(z) & 255; + x -= Math.floor(x); + y -= Math.floor(y); + z -= Math.floor(z); + var fx = (3 - 2 * x) * x * x, + fy = (3 - 2 * y) * y * y, + fz = (3 - 2 * z) * z * z; + var p0 = perm[X] + Y, + p00 = perm[p0] + Z, + p01 = perm[p0 + 1] + Z, + p1 = perm[X + 1] + Y, + p10 = perm[p1] + Z, + p11 = perm[p1 + 1] + Z; + return lerp(fz, lerp(fy, lerp(fx, grad3d(perm[p00], x, y, z), grad3d(perm[p10], x - 1, y, z)), lerp(fx, grad3d(perm[p01], x, y - 1, z), grad3d(perm[p11], x - 1, y - 1, z))), lerp(fy, lerp(fx, grad3d(perm[p00 + 1], x, y, z - 1), grad3d(perm[p10 + 1], x - 1, y, z - 1)), lerp(fx, grad3d(perm[p01 + 1], x, y - 1, z - 1), grad3d(perm[p11 + 1], x - 1, y - 1, z - 1)))) + }; + this.noise2d = function(x, y) { + var X = Math.floor(x) & 255, + Y = Math.floor(y) & 255; + x -= Math.floor(x); + y -= Math.floor(y); + var fx = (3 - 2 * x) * x * x, + fy = (3 - 2 * y) * y * y; + var p0 = perm[X] + Y, + p1 = perm[X + 1] + Y; + return lerp(fy, lerp(fx, grad2d(perm[p0], x, y), grad2d(perm[p1], x - 1, y)), lerp(fx, grad2d(perm[p0 + 1], x, y - 1), grad2d(perm[p1 + 1], x - 1, y - 1))) + }; + this.noise1d = function(x) { + var X = Math.floor(x) & 255; + x -= Math.floor(x); + var fx = (3 - 2 * x) * x * x; + return lerp(fx, grad1d(perm[X], x), grad1d(perm[X + 1], x - 1)) + } + } + var noiseProfile = { + generator: undef, + octaves: 4, + fallout: 0.5, + seed: undef + }; + p.noise = function(x, y, z) { + if (noiseProfile.generator === undef) noiseProfile.generator = new PerlinNoise(noiseProfile.seed); + var generator = noiseProfile.generator; + var effect = 1, + k = 1, + sum = 0; + for (var i = 0; i < noiseProfile.octaves; ++i) { + effect *= noiseProfile.fallout; + switch (arguments.length) { + case 1: + sum += effect * (1 + generator.noise1d(k * x)) / 2; + break; + case 2: + sum += effect * (1 + generator.noise2d(k * x, k * y)) / 2; + break; + case 3: + sum += effect * (1 + generator.noise3d(k * x, k * y, k * z)) / 2; + break + } + k *= 2 + } + return sum + }; + p.noiseDetail = function(octaves, fallout) { + noiseProfile.octaves = octaves; + if (fallout !== undef) noiseProfile.fallout = fallout + }; + p.noiseSeed = function(seed) { + noiseProfile.seed = seed; + noiseProfile.generator = undef + }; + DrawingShared.prototype.size = function(aWidth, aHeight, aMode) { + if (doStroke) p.stroke(0); + if (doFill) p.fill(255); + var savedProperties = { + fillStyle: curContext.fillStyle, + strokeStyle: curContext.strokeStyle, + lineCap: curContext.lineCap, + lineJoin: curContext.lineJoin + }; + if (curElement.style.length > 0) { + curElement.style.removeProperty("width"); + curElement.style.removeProperty("height") + } + curElement.width = p.width = aWidth || 100; + curElement.height = p.height = aHeight || 100; + for (var prop in savedProperties) if (savedProperties.hasOwnProperty(prop)) curContext[prop] = savedProperties[prop]; + p.textFont(curTextFont); + p.background(); + maxPixelsCached = Math.max(1E3, aWidth * aHeight * 0.05); + p.externals.context = curContext; + for (var i = 0; i < 720; i++) { + sinLUT[i] = p.sin(i * (Math.PI / 180) * 0.5); + cosLUT[i] = p.cos(i * (Math.PI / 180) * 0.5) + } + }; + Drawing2D.prototype.size = function(aWidth, aHeight, aMode) { + if (curContext === undef) { + curContext = curElement.getContext("2d"); + userMatrixStack = new PMatrixStack; + userReverseMatrixStack = new PMatrixStack; + modelView = new PMatrix2D; + modelViewInv = new PMatrix2D + } + DrawingShared.prototype.size.apply(this, arguments) + }; + Drawing3D.prototype.size = function() { + var size3DCalled = false; + return function size(aWidth, aHeight, aMode) { + if (size3DCalled) throw "Multiple calls to size() for 3D renders are not allowed."; + size3DCalled = true; + + function getGLContext(canvas) { + var ctxNames = ["experimental-webgl", "webgl", "webkit-3d"], + gl; + for (var i = 0, l = ctxNames.length; i < l; i++) { + gl = canvas.getContext(ctxNames[i], { + antialias: false, + preserveDrawingBuffer: true + }); + if (gl) break + } + return gl + } + try { + curElement.width = p.width = aWidth || 100; + curElement.height = p.height = aHeight || 100; + curContext = getGLContext(curElement); + canTex = curContext.createTexture(); + textTex = curContext.createTexture() + } catch(e_size) { + Processing.debug(e_size) + } + if (!curContext) throw "WebGL context is not supported on this browser."; + curContext.viewport(0, 0, curElement.width, curElement.height); + curContext.enable(curContext.DEPTH_TEST); + curContext.enable(curContext.BLEND); + curContext.blendFunc(curContext.SRC_ALPHA, curContext.ONE_MINUS_SRC_ALPHA); + programObject2D = createProgramObject(curContext, vertexShaderSrc2D, fragmentShaderSrc2D); + programObjectUnlitShape = createProgramObject(curContext, vertexShaderSrcUnlitShape, fragmentShaderSrcUnlitShape); + p.strokeWeight(1); + programObject3D = createProgramObject(curContext, vertexShaderSrc3D, fragmentShaderSrc3D); + curContext.useProgram(programObject3D); + uniformi("usingTexture3d", programObject3D, "usingTexture", usingTexture); + p.lightFalloff(1, 0, 0); + p.shininess(1); + p.ambient(255, 255, 255); + p.specular(0, 0, 0); + p.emissive(0, 0, 0); + boxBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, boxVerts, curContext.STATIC_DRAW); + boxNormBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, boxNorms, curContext.STATIC_DRAW); + boxOutlineBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, boxOutlineVerts, curContext.STATIC_DRAW); + rectBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, rectBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, rectVerts, curContext.STATIC_DRAW); + rectNormBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, rectNorms, curContext.STATIC_DRAW); + sphereBuffer = curContext.createBuffer(); + lineBuffer = curContext.createBuffer(); + fillBuffer = curContext.createBuffer(); + fillColorBuffer = curContext.createBuffer(); + strokeColorBuffer = curContext.createBuffer(); + shapeTexVBO = curContext.createBuffer(); + pointBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, pointBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 0]), curContext.STATIC_DRAW); + textBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0]), curContext.STATIC_DRAW); + textureBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ARRAY_BUFFER, textureBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), curContext.STATIC_DRAW); + indexBuffer = curContext.createBuffer(); + curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); + curContext.bufferData(curContext.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 2, 3, 0]), curContext.STATIC_DRAW); + cam = new PMatrix3D; + cameraInv = new PMatrix3D; + modelView = new PMatrix3D; + modelViewInv = new PMatrix3D; + projection = new PMatrix3D; + p.camera(); + p.perspective(); + userMatrixStack = new PMatrixStack; + userReverseMatrixStack = new PMatrixStack; + curveBasisMatrix = new PMatrix3D; + curveToBezierMatrix = new PMatrix3D; + curveDrawMatrix = new PMatrix3D; + bezierDrawMatrix = new PMatrix3D; + bezierBasisInverse = new PMatrix3D; + bezierBasisMatrix = new PMatrix3D; + bezierBasisMatrix.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0); + DrawingShared.prototype.size.apply(this, arguments) + } + }(); + Drawing2D.prototype.ambientLight = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.ambientLight = function(r, g, b, x, y, z) { + if (lightCount === 8) throw "can only create " + 8 + " lights"; + var pos = new PVector(x, y, z); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.mult(pos, pos); + var col = color$4(r, g, b, 0); + var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; + curContext.useProgram(programObject3D); + uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); + uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); + uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 0); + uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) + }; + Drawing2D.prototype.directionalLight = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.directionalLight = function(r, g, b, nx, ny, nz) { + if (lightCount === 8) throw "can only create " + 8 + " lights"; + curContext.useProgram(programObject3D); + var mvm = new PMatrix3D; + mvm.scale(1, -1, 1); + mvm.apply(modelView.array()); + mvm = mvm.array(); + var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz]; + var col = color$4(r, g, b, 0); + var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; + uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); + uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", dir); + uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 1); + uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) + }; + Drawing2D.prototype.lightFalloff = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.lightFalloff = function(constant, linear, quadratic) { + curContext.useProgram(programObject3D); + uniformf("uFalloff3d", programObject3D, "uFalloff", [constant, linear, quadratic]) + }; + Drawing2D.prototype.lightSpecular = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.lightSpecular = function(r, g, b) { + var col = color$4(r, g, b, 0); + var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; + curContext.useProgram(programObject3D); + uniformf("uSpecular3d", programObject3D, "uSpecular", normalizedCol) + }; + p.lights = function() { + p.ambientLight(128, 128, 128); + p.directionalLight(128, 128, 128, 0, 0, -1); + p.lightFalloff(1, 0, 0); + p.lightSpecular(0, 0, 0) + }; + Drawing2D.prototype.pointLight = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.pointLight = function(r, g, b, x, y, z) { + if (lightCount === 8) throw "can only create " + 8 + " lights"; + var pos = new PVector(x, y, z); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.mult(pos, pos); + var col = color$4(r, g, b, 0); + var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; + curContext.useProgram(programObject3D); + uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); + uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); + uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 2); + uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) + }; + Drawing2D.prototype.noLights = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.noLights = function() { + lightCount = 0; + curContext.useProgram(programObject3D); + uniformi("uLightCount3d", programObject3D, "uLightCount", lightCount) + }; + Drawing2D.prototype.spotLight = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.spotLight = function(r, g, b, x, y, z, nx, ny, nz, angle, concentration) { + if (lightCount === 8) throw "can only create " + 8 + " lights"; + curContext.useProgram(programObject3D); + var pos = new PVector(x, y, z); + var mvm = new PMatrix3D; + mvm.scale(1, -1, 1); + mvm.apply(modelView.array()); + mvm.mult(pos, pos); + mvm = mvm.array(); + var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * + nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz]; + var col = color$4(r, g, b, 0); + var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; + uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); + uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); + uniformf("uLights.direction.3d." + lightCount, programObject3D, "uLights" + lightCount + ".direction", dir); + uniformf("uLights.concentration.3d." + lightCount, programObject3D, "uLights" + lightCount + ".concentration", concentration); + uniformf("uLights.angle.3d." + lightCount, programObject3D, "uLights" + lightCount + ".angle", angle); + uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 3); + uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) + }; + Drawing2D.prototype.beginCamera = function() { + throw "beginCamera() is not available in 2D mode"; + }; + Drawing3D.prototype.beginCamera = function() { + if (manipulatingCamera) throw "You cannot call beginCamera() again before calling endCamera()"; + manipulatingCamera = true; + modelView = cameraInv; + modelViewInv = cam + }; + Drawing2D.prototype.endCamera = function() { + throw "endCamera() is not available in 2D mode"; + }; + Drawing3D.prototype.endCamera = function() { + if (!manipulatingCamera) throw "You cannot call endCamera() before calling beginCamera()"; + modelView.set(cam); + modelViewInv.set(cameraInv); + manipulatingCamera = false + }; + p.camera = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { + if (eyeX === undef) { + cameraX = p.width / 2; + cameraY = p.height / 2; + cameraZ = cameraY / Math.tan(cameraFOV / 2); + eyeX = cameraX; + eyeY = cameraY; + eyeZ = cameraZ; + centerX = cameraX; + centerY = cameraY; + centerZ = 0; + upX = 0; + upY = 1; + upZ = 0 + } + var z = new PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ); + var y = new PVector(upX, upY, upZ); + z.normalize(); + var x = PVector.cross(y, z); + y = PVector.cross(z, x); + x.normalize(); + y.normalize(); + var xX = x.x, + xY = x.y, + xZ = x.z; + var yX = y.x, + yY = y.y, + yZ = y.z; + var zX = z.x, + zY = z.y, + zZ = z.z; + cam.set(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); + cam.translate(-eyeX, -eyeY, -eyeZ); + cameraInv.reset(); + cameraInv.invApply(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); + cameraInv.translate(eyeX, eyeY, eyeZ); + modelView.set(cam); + modelViewInv.set(cameraInv) + }; + p.perspective = function(fov, aspect, near, far) { + if (arguments.length === 0) { + cameraY = curElement.height / 2; + cameraZ = cameraY / Math.tan(cameraFOV / 2); + cameraNear = cameraZ / 10; + cameraFar = cameraZ * 10; + cameraAspect = p.width / p.height; + fov = cameraFOV; + aspect = cameraAspect; + near = cameraNear; + far = cameraFar + } + var yMax, yMin, xMax, xMin; + yMax = near * Math.tan(fov / 2); + yMin = -yMax; + xMax = yMax * aspect; + xMin = yMin * aspect; + p.frustum(xMin, xMax, yMin, yMax, near, far) + }; + Drawing2D.prototype.frustum = function() { + throw "Processing.js: frustum() is not supported in 2D mode"; + }; + Drawing3D.prototype.frustum = function(left, right, bottom, top, near, far) { + frustumMode = true; + projection = new PMatrix3D; + projection.set(2 * near / (right - left), 0, (right + left) / (right - left), 0, 0, 2 * near / (top - bottom), (top + bottom) / (top - bottom), 0, 0, 0, -(far + near) / (far - near), -(2 * far * near) / (far - near), 0, 0, -1, 0); + var proj = new PMatrix3D; + proj.set(projection); + proj.transpose(); + curContext.useProgram(programObject2D); + uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); + curContext.useProgram(programObject3D); + uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); + curContext.useProgram(programObjectUnlitShape); + uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()) + }; + p.ortho = function(left, right, bottom, top, near, far) { + if (arguments.length === 0) { + left = 0; + right = p.width; + bottom = 0; + top = p.height; + near = -10; + far = 10 + } + var x = 2 / (right - left); + var y = 2 / (top - bottom); + var z = -2 / (far - near); + var tx = -(right + left) / (right - left); + var ty = -(top + bottom) / (top - bottom); + var tz = -(far + near) / (far - near); + projection = new PMatrix3D; + projection.set(x, 0, 0, tx, 0, y, 0, ty, 0, 0, z, tz, 0, 0, 0, 1); + var proj = new PMatrix3D; + proj.set(projection); + proj.transpose(); + curContext.useProgram(programObject2D); + uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); + curContext.useProgram(programObject3D); + uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); + curContext.useProgram(programObjectUnlitShape); + uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()); + frustumMode = false + }; + p.printProjection = function() { + projection.print() + }; + p.printCamera = function() { + cam.print() + }; + Drawing2D.prototype.box = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.box = function(w, h, d) { + if (!h || !d) h = d = w; + var model = new PMatrix3D; + model.scale(w, h, d); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + if (doFill) { + curContext.useProgram(programObject3D); + uniformMatrix("model3d", programObject3D, "uModel", false, model.array()); + uniformMatrix("view3d", programObject3D, "uView", false, view.array()); + curContext.enable(curContext.POLYGON_OFFSET_FILL); + curContext.polygonOffset(1, 1); + uniformf("color3d", programObject3D, "uColor", fillStyle); + if (lightCount > 0) { + var v = new PMatrix3D; + v.set(view); + var m = new PMatrix3D; + m.set(model); + v.mult(m); + var normalMatrix = new PMatrix3D; + normalMatrix.set(v); + normalMatrix.invert(); + normalMatrix.transpose(); + uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); + vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, boxNormBuffer) + } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); + vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, boxBuffer); + disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); + disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); + curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3); + curContext.disable(curContext.POLYGON_OFFSET_FILL) + } + if (lineWidth > 0 && doStroke) { + curContext.useProgram(programObject2D); + uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + uniformf("uColor2d", programObject2D, "uColor", strokeStyle); + uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); + vertexAttribPointer("vertex2d", programObject2D, "aVertex", 3, boxOutlineBuffer); + disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); + curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3) + } + }; + var initSphere = function() { + var i; + sphereVerts = []; + for (i = 0; i < sphereDetailU; i++) { + sphereVerts.push(0); + sphereVerts.push(-1); + sphereVerts.push(0); + sphereVerts.push(sphereX[i]); + sphereVerts.push(sphereY[i]); + sphereVerts.push(sphereZ[i]) + } + sphereVerts.push(0); + sphereVerts.push(-1); + sphereVerts.push(0); + sphereVerts.push(sphereX[0]); + sphereVerts.push(sphereY[0]); + sphereVerts.push(sphereZ[0]); + var v1, v11, v2; + var voff = 0; + for (i = 2; i < sphereDetailV; i++) { + v1 = v11 = voff; + voff += sphereDetailU; + v2 = voff; + for (var j = 0; j < sphereDetailU; j++) { + sphereVerts.push(sphereX[v1]); + sphereVerts.push(sphereY[v1]); + sphereVerts.push(sphereZ[v1++]); + sphereVerts.push(sphereX[v2]); + sphereVerts.push(sphereY[v2]); + sphereVerts.push(sphereZ[v2++]) + } + v1 = v11; + v2 = voff; + sphereVerts.push(sphereX[v1]); + sphereVerts.push(sphereY[v1]); + sphereVerts.push(sphereZ[v1]); + sphereVerts.push(sphereX[v2]); + sphereVerts.push(sphereY[v2]); + sphereVerts.push(sphereZ[v2]) + } + for (i = 0; i < sphereDetailU; i++) { + v2 = voff + i; + sphereVerts.push(sphereX[v2]); + sphereVerts.push(sphereY[v2]); + sphereVerts.push(sphereZ[v2]); + sphereVerts.push(0); + sphereVerts.push(1); + sphereVerts.push(0) + } + sphereVerts.push(sphereX[voff]); + sphereVerts.push(sphereY[voff]); + sphereVerts.push(sphereZ[voff]); + sphereVerts.push(0); + sphereVerts.push(1); + sphereVerts.push(0); + curContext.bindBuffer(curContext.ARRAY_BUFFER, sphereBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(sphereVerts), curContext.STATIC_DRAW) + }; + p.sphereDetail = function(ures, vres) { + var i; + if (arguments.length === 1) ures = vres = arguments[0]; + if (ures < 3) ures = 3; + if (vres < 2) vres = 2; + if (ures === sphereDetailU && vres === sphereDetailV) return; + var delta = 720 / ures; + var cx = new Float32Array(ures); + var cz = new Float32Array(ures); + for (i = 0; i < ures; i++) { + cx[i] = cosLUT[i * delta % 720 | 0]; + cz[i] = sinLUT[i * delta % 720 | 0] + } + var vertCount = ures * (vres - 1) + 2; + var currVert = 0; + sphereX = new Float32Array(vertCount); + sphereY = new Float32Array(vertCount); + sphereZ = new Float32Array(vertCount); + var angle_step = 720 * 0.5 / vres; + var angle = angle_step; + for (i = 1; i < vres; i++) { + var curradius = sinLUT[angle % 720 | 0]; + var currY = -cosLUT[angle % 720 | 0]; + for (var j = 0; j < ures; j++) { + sphereX[currVert] = cx[j] * curradius; + sphereY[currVert] = currY; + sphereZ[currVert++] = cz[j] * curradius + } + angle += angle_step + } + sphereDetailU = ures; + sphereDetailV = vres; + initSphere() + }; + Drawing2D.prototype.sphere = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.sphere = function() { + var sRad = arguments[0]; + if (sphereDetailU < 3 || sphereDetailV < 2) p.sphereDetail(30); + var model = new PMatrix3D; + model.scale(sRad, sRad, sRad); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + if (doFill) { + if (lightCount > 0) { + var v = new PMatrix3D; + v.set(view); + var m = new PMatrix3D; + m.set(model); + v.mult(m); + var normalMatrix = new PMatrix3D; + normalMatrix.set(v); + normalMatrix.invert(); + normalMatrix.transpose(); + uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); + vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, sphereBuffer) + } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); + curContext.useProgram(programObject3D); + disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); + uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); + uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); + vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, sphereBuffer); + disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); + curContext.enable(curContext.POLYGON_OFFSET_FILL); + curContext.polygonOffset(1, 1); + uniformf("uColor3d", programObject3D, "uColor", fillStyle); + curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3); + curContext.disable(curContext.POLYGON_OFFSET_FILL) + } + if (lineWidth > 0 && doStroke) { + curContext.useProgram(programObject2D); + uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, sphereBuffer); + disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); + uniformf("uColor2d", programObject2D, "uColor", strokeStyle); + uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); + curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3) + } + }; + p.modelX = function(x, y, z) { + var mv = modelView.array(); + var ci = cameraInv.array(); + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw; + var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; + return ow !== 0 ? ox / ow : ox + }; + p.modelY = function(x, y, z) { + var mv = modelView.array(); + var ci = cameraInv.array(); + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw; + var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; + return ow !== 0 ? oy / ow : oy + }; + p.modelZ = function(x, y, z) { + var mv = modelView.array(); + var ci = cameraInv.array(); + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var oz = ci[8] * ax + ci[9] * ay + ci[10] * az + ci[11] * aw; + var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; + return ow !== 0 ? oz / ow : oz + }; + Drawing2D.prototype.ambient = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.ambient = function(v1, v2, v3) { + curContext.useProgram(programObject3D); + uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); + var col = p.color(v1, v2, v3); + uniformf("uMaterialAmbient3d", programObject3D, "uMaterialAmbient", p.color.toGLArray(col).slice(0, 3)) + }; + Drawing2D.prototype.emissive = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.emissive = function(v1, v2, v3) { + curContext.useProgram(programObject3D); + uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); + var col = p.color(v1, v2, v3); + uniformf("uMaterialEmissive3d", programObject3D, "uMaterialEmissive", p.color.toGLArray(col).slice(0, 3)) + }; + Drawing2D.prototype.shininess = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.shininess = function(shine) { + curContext.useProgram(programObject3D); + uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); + uniformf("uShininess3d", programObject3D, "uShininess", shine) + }; + Drawing2D.prototype.specular = DrawingShared.prototype.a3DOnlyFunction; + Drawing3D.prototype.specular = function(v1, v2, v3) { + curContext.useProgram(programObject3D); + uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); + var col = p.color(v1, v2, v3); + uniformf("uMaterialSpecular3d", programObject3D, "uMaterialSpecular", p.color.toGLArray(col).slice(0, 3)) + }; + p.screenX = function(x, y, z) { + var mv = modelView.array(); + if (mv.length === 16) { + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var pj = projection.array(); + var ox = pj[0] * ax + pj[1] * ay + pj[2] * az + pj[3] * aw; + var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; + if (ow !== 0) ox /= ow; + return p.width * (1 + ox) / 2 + } + return modelView.multX(x, y) + }; + p.screenY = function screenY(x, y, z) { + var mv = modelView.array(); + if (mv.length === 16) { + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var pj = projection.array(); + var oy = pj[4] * ax + pj[5] * ay + pj[6] * az + pj[7] * aw; + var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; + if (ow !== 0) oy /= ow; + return p.height * (1 + oy) / 2 + } + return modelView.multY(x, y) + }; + p.screenZ = function screenZ(x, y, z) { + var mv = modelView.array(); + if (mv.length !== 16) return 0; + var pj = projection.array(); + var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; + var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; + var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; + var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; + var oz = pj[8] * ax + pj[9] * ay + pj[10] * az + pj[11] * aw; + var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; + if (ow !== 0) oz /= ow; + return (oz + 1) / 2 + }; + DrawingShared.prototype.fill = function() { + var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]); + if (color === currentFillColor && doFill) return; + doFill = true; + currentFillColor = color + }; + Drawing2D.prototype.fill = function() { + DrawingShared.prototype.fill.apply(this, arguments); + isFillDirty = true + }; + Drawing3D.prototype.fill = function() { + DrawingShared.prototype.fill.apply(this, arguments); + fillStyle = p.color.toGLArray(currentFillColor) + }; + + function executeContextFill() { + if (doFill) { + if (isFillDirty) { + curContext.fillStyle = p.color.toString(currentFillColor); + isFillDirty = false + } + curContext.fill() + } + } + p.noFill = function() { + doFill = false + }; + DrawingShared.prototype.stroke = function() { + var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]); + if (color === currentStrokeColor && doStroke) return; + doStroke = true; + currentStrokeColor = color + }; + Drawing2D.prototype.stroke = function() { + DrawingShared.prototype.stroke.apply(this, arguments); + isStrokeDirty = true + }; + Drawing3D.prototype.stroke = function() { + DrawingShared.prototype.stroke.apply(this, arguments); + strokeStyle = p.color.toGLArray(currentStrokeColor) + }; + + function executeContextStroke() { + if (doStroke) { + if (isStrokeDirty) { + curContext.strokeStyle = p.color.toString(currentStrokeColor); + isStrokeDirty = false + } + curContext.stroke() + } + } + p.noStroke = function() { + doStroke = false + }; + DrawingShared.prototype.strokeWeight = function(w) { + lineWidth = w + }; + Drawing2D.prototype.strokeWeight = function(w) { + DrawingShared.prototype.strokeWeight.apply(this, arguments); + curContext.lineWidth = w + }; + Drawing3D.prototype.strokeWeight = function(w) { + DrawingShared.prototype.strokeWeight.apply(this, arguments); + curContext.useProgram(programObject2D); + uniformf("pointSize2d", programObject2D, "uPointSize", w); + curContext.useProgram(programObjectUnlitShape); + uniformf("pointSizeUnlitShape", programObjectUnlitShape, "uPointSize", w); + curContext.lineWidth(w) + }; + p.strokeCap = function(value) { + drawing.$ensureContext().lineCap = value + }; + p.strokeJoin = function(value) { + drawing.$ensureContext().lineJoin = value + }; + Drawing2D.prototype.smooth = function() { + renderSmooth = true; + var style = curElement.style; + style.setProperty("image-rendering", "optimizeQuality", "important"); + style.setProperty("-ms-interpolation-mode", "bicubic", "important"); + if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozImageSmoothingEnabled = true + }; + Drawing3D.prototype.smooth = function() { + renderSmooth = true + }; + Drawing2D.prototype.noSmooth = function() { + renderSmooth = false; + var style = curElement.style; + style.setProperty("image-rendering", "optimizeSpeed", "important"); + style.setProperty("image-rendering", "-moz-crisp-edges", "important"); + style.setProperty("image-rendering", "-webkit-optimize-contrast", "important"); + style.setProperty("image-rendering", "optimize-contrast", "important"); + style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important"); + if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozImageSmoothingEnabled = false + }; + Drawing3D.prototype.noSmooth = function() { + renderSmooth = false + }; + Drawing2D.prototype.point = function(x, y) { + if (!doStroke) return; + x = Math.round(x); + y = Math.round(y); + curContext.fillStyle = p.color.toString(currentStrokeColor); + isFillDirty = true; + if (lineWidth > 1) { + curContext.beginPath(); + curContext.arc(x, y, lineWidth / 2, 0, 6.283185307179586, false); + curContext.fill() + } else curContext.fillRect(x, y, 1, 1) + }; + Drawing3D.prototype.point = function(x, y, z) { + var model = new PMatrix3D; + model.translate(x, y, z || 0); + model.transpose(); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + curContext.useProgram(programObject2D); + uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + if (lineWidth > 0 && doStroke) { + uniformf("uColor2d", programObject2D, "uColor", strokeStyle); + uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); + uniformi("uSmooth2d", programObject2D, "uSmooth", renderSmooth); + vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, pointBuffer); + disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); + curContext.drawArrays(curContext.POINTS, 0, 1) + } + }; + p.beginShape = function(type) { + curShape = type; + curvePoints = []; + vertArray = [] + }; + Drawing2D.prototype.vertex = function(x, y, moveTo) { + var vert = []; + if (firstVert) firstVert = false; + vert["isVert"] = true; + vert[0] = x; + vert[1] = y; + vert[2] = 0; + vert[3] = 0; + vert[4] = 0; + vert[5] = currentFillColor; + vert[6] = currentStrokeColor; + vertArray.push(vert); + if (moveTo) vertArray[vertArray.length - 1]["moveTo"] = moveTo + }; + Drawing3D.prototype.vertex = function(x, y, z, u, v) { + var vert = []; + if (firstVert) firstVert = false; + vert["isVert"] = true; + if (v === undef && usingTexture) { + v = u; + u = z; + z = 0 + } + if (u !== undef && v !== undef) { + if (curTextureMode === 2) { + u /= curTexture.width; + v /= curTexture.height + } + u = u > 1 ? 1 : u; + u = u < 0 ? 0 : u; + v = v > 1 ? 1 : v; + v = v < 0 ? 0 : v + } + vert[0] = x; + vert[1] = y; + vert[2] = z || 0; + vert[3] = u || 0; + vert[4] = v || 0; + vert[5] = fillStyle[0]; + vert[6] = fillStyle[1]; + vert[7] = fillStyle[2]; + vert[8] = fillStyle[3]; + vert[9] = strokeStyle[0]; + vert[10] = strokeStyle[1]; + vert[11] = strokeStyle[2]; + vert[12] = strokeStyle[3]; + vert[13] = normalX; + vert[14] = normalY; + vert[15] = normalZ; + vertArray.push(vert) + }; + var point3D = function(vArray, cArray) { + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + curContext.useProgram(programObjectUnlitShape); + uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); + uniformi("uSmoothUS", programObjectUnlitShape, "uSmooth", renderSmooth); + vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, pointBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); + vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, fillColorBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); + curContext.drawArrays(curContext.POINTS, 0, vArray.length / 3) + }; + var line3D = function(vArray, mode, cArray) { + var ctxMode; + if (mode === "LINES") ctxMode = curContext.LINES; + else if (mode === "LINE_LOOP") ctxMode = curContext.LINE_LOOP; + else ctxMode = curContext.LINE_STRIP; + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + curContext.useProgram(programObjectUnlitShape); + uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); + vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, lineBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); + vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, strokeColorBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); + curContext.drawArrays(ctxMode, 0, vArray.length / 3) + }; + var fill3D = function(vArray, mode, cArray, tArray) { + var ctxMode; + if (mode === "TRIANGLES") ctxMode = curContext.TRIANGLES; + else if (mode === "TRIANGLE_FAN") ctxMode = curContext.TRIANGLE_FAN; + else ctxMode = curContext.TRIANGLE_STRIP; + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + curContext.useProgram(programObject3D); + uniformMatrix("model3d", programObject3D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); + uniformMatrix("view3d", programObject3D, "uView", false, view.array()); + curContext.enable(curContext.POLYGON_OFFSET_FILL); + curContext.polygonOffset(1, 1); + uniformf("color3d", programObject3D, "uColor", [-1, 0, 0, 0]); + vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, fillBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); + if (usingTexture && curTint !== null) curTint3d(cArray); + vertexAttribPointer("aColor3d", programObject3D, "aColor", 4, fillColorBuffer); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); + disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); + if (usingTexture) { + uniformi("uUsingTexture3d", programObject3D, "uUsingTexture", usingTexture); + vertexAttribPointer("aTexture3d", programObject3D, "aTexture", 2, shapeTexVBO); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(tArray), curContext.STREAM_DRAW) + } + curContext.drawArrays(ctxMode, 0, vArray.length / 3); + curContext.disable(curContext.POLYGON_OFFSET_FILL) + }; + + function fillStrokeClose() { + executeContextFill(); + executeContextStroke(); + curContext.closePath() + } + Drawing2D.prototype.endShape = function(mode) { + if (vertArray.length === 0) return; + var closeShape = mode === 2; + if (closeShape) vertArray.push(vertArray[0]); + var lineVertArray = []; + var fillVertArray = []; + var colorVertArray = []; + var strokeVertArray = []; + var texVertArray = []; + var cachedVertArray; + firstVert = true; + var i, j, k; + var vertArrayLength = vertArray.length; + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + texVertArray.push(cachedVertArray[3]); + texVertArray.push(cachedVertArray[4]) + } + if (isCurve && (curShape === 20 || curShape === undef)) { + if (vertArrayLength > 3) { + var b = [], + s = 1 - curTightness; + curContext.beginPath(); + curContext.moveTo(vertArray[1][0], vertArray[1][1]); + for (i = 1; i + 2 < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + b[0] = [cachedVertArray[0], cachedVertArray[1]]; + b[1] = [cachedVertArray[0] + (s * vertArray[i + 1][0] - s * vertArray[i - 1][0]) / 6, cachedVertArray[1] + (s * vertArray[i + 1][1] - s * vertArray[i - 1][1]) / 6]; + b[2] = [vertArray[i + 1][0] + (s * vertArray[i][0] - s * vertArray[i + 2][0]) / 6, vertArray[i + 1][1] + (s * vertArray[i][1] - s * vertArray[i + 2][1]) / 6]; + b[3] = [vertArray[i + 1][0], vertArray[i + 1][1]]; + curContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]) + } + fillStrokeClose() + } + } else if (isBezier && (curShape === 20 || curShape === undef)) { + curContext.beginPath(); + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + if (vertArray[i]["isVert"]) if (vertArray[i]["moveTo"]) curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); + else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + else curContext.bezierCurveTo(vertArray[i][0], vertArray[i][1], vertArray[i][2], vertArray[i][3], vertArray[i][4], vertArray[i][5]) + } + fillStrokeClose() + } else if (curShape === 2) for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + if (doStroke) p.stroke(cachedVertArray[6]); + p.point(cachedVertArray[0], cachedVertArray[1]) + } else if (curShape === 4) for (i = 0; i + 1 < vertArrayLength; i += 2) { + cachedVertArray = vertArray[i]; + if (doStroke) p.stroke(vertArray[i + 1][6]); + p.line(cachedVertArray[0], cachedVertArray[1], vertArray[i + 1][0], vertArray[i + 1][1]) + } else if (curShape === 9) for (i = 0; i + 2 < vertArrayLength; i += 3) { + cachedVertArray = vertArray[i]; + curContext.beginPath(); + curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); + curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); + curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); + curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + if (doFill) { + p.fill(vertArray[i + 2][5]); + executeContextFill() + } + if (doStroke) { + p.stroke(vertArray[i + 2][6]); + executeContextStroke() + } + curContext.closePath() + } else if (curShape === 10) for (i = 0; i + 1 < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + curContext.beginPath(); + curContext.moveTo(vertArray[i + 1][0], vertArray[i + 1][1]); + curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + if (doStroke) p.stroke(vertArray[i + 1][6]); + if (doFill) p.fill(vertArray[i + 1][5]); + if (i + 2 < vertArrayLength) { + curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); + if (doStroke) p.stroke(vertArray[i + 2][6]); + if (doFill) p.fill(vertArray[i + 2][5]) + } + fillStrokeClose() + } else if (curShape === 11) { + if (vertArrayLength > 2) { + curContext.beginPath(); + curContext.moveTo(vertArray[0][0], vertArray[0][1]); + curContext.lineTo(vertArray[1][0], vertArray[1][1]); + curContext.lineTo(vertArray[2][0], vertArray[2][1]); + if (doFill) { + p.fill(vertArray[2][5]); + executeContextFill() + } + if (doStroke) { + p.stroke(vertArray[2][6]); + executeContextStroke() + } + curContext.closePath(); + for (i = 3; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + curContext.beginPath(); + curContext.moveTo(vertArray[0][0], vertArray[0][1]); + curContext.lineTo(vertArray[i - 1][0], vertArray[i - 1][1]); + curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + if (doFill) { + p.fill(cachedVertArray[5]); + executeContextFill() + } + if (doStroke) { + p.stroke(cachedVertArray[6]); + executeContextStroke() + } + curContext.closePath() + } + } + } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { + cachedVertArray = vertArray[i]; + curContext.beginPath(); + curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); + for (j = 1; j < 4; j++) curContext.lineTo(vertArray[i + j][0], vertArray[i + j][1]); + curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + if (doFill) { + p.fill(vertArray[i + 3][5]); + executeContextFill() + } + if (doStroke) { + p.stroke(vertArray[i + 3][6]); + executeContextStroke() + } + curContext.closePath() + } else if (curShape === 17) { + if (vertArrayLength > 3) for (i = 0; i + 1 < vertArrayLength; i += 2) { + cachedVertArray = vertArray[i]; + curContext.beginPath(); + if (i + 3 < vertArrayLength) { + curContext.moveTo(vertArray[i + 2][0], vertArray[i + 2][1]); + curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); + curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); + curContext.lineTo(vertArray[i + 3][0], vertArray[i + 3][1]); + if (doFill) p.fill(vertArray[i + 3][5]); + if (doStroke) p.stroke(vertArray[i + 3][6]) + } else { + curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); + curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]) + } + fillStrokeClose() + } + } else { + curContext.beginPath(); + curContext.moveTo(vertArray[0][0], vertArray[0][1]); + for (i = 1; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + if (cachedVertArray["isVert"]) if (cachedVertArray["moveTo"]) curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); + else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]) + } + fillStrokeClose() + } + isCurve = false; + isBezier = false; + curveVertArray = []; + curveVertCount = 0; + if (closeShape) vertArray.pop() + }; + Drawing3D.prototype.endShape = function(mode) { + if (vertArray.length === 0) return; + var closeShape = mode === 2; + var lineVertArray = []; + var fillVertArray = []; + var colorVertArray = []; + var strokeVertArray = []; + var texVertArray = []; + var cachedVertArray; + firstVert = true; + var i, j, k; + var vertArrayLength = vertArray.length; + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + texVertArray.push(cachedVertArray[3]); + texVertArray.push(cachedVertArray[4]) + } + if (closeShape) { + fillVertArray.push(vertArray[0][0]); + fillVertArray.push(vertArray[0][1]); + fillVertArray.push(vertArray[0][2]); + for (i = 5; i < 9; i++) colorVertArray.push(vertArray[0][i]); + for (i = 9; i < 13; i++) strokeVertArray.push(vertArray[0][i]); + texVertArray.push(vertArray[0][3]); + texVertArray.push(vertArray[0][4]) + } + if (isCurve && (curShape === 20 || curShape === undef)) { + lineVertArray = fillVertArray; + if (doStroke) line3D(lineVertArray, null, strokeVertArray); + if (doFill) fill3D(fillVertArray, null, colorVertArray) + } else if (isBezier && (curShape === 20 || curShape === undef)) { + lineVertArray = fillVertArray; + lineVertArray.splice(lineVertArray.length - 3); + strokeVertArray.splice(strokeVertArray.length - 4); + if (doStroke) line3D(lineVertArray, null, strokeVertArray); + if (doFill) fill3D(fillVertArray, "TRIANGLES", colorVertArray) + } else { + if (curShape === 2) { + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) + } + point3D(lineVertArray, strokeVertArray) + } else if (curShape === 4) { + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) + } + line3D(lineVertArray, "LINES", strokeVertArray) + } else if (curShape === 9) { + if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i += 3) { + fillVertArray = []; + texVertArray = []; + lineVertArray = []; + colorVertArray = []; + strokeVertArray = []; + for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { + lineVertArray.push(vertArray[i + j][k]); + fillVertArray.push(vertArray[i + j][k]) + } + for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(vertArray[i + j][k]); + for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { + colorVertArray.push(vertArray[i + j][k]); + strokeVertArray.push(vertArray[i + j][k + 4]) + } + if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); + if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLES", colorVertArray, texVertArray) + } + } else if (curShape === 10) { + if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i++) { + lineVertArray = []; + fillVertArray = []; + strokeVertArray = []; + colorVertArray = []; + texVertArray = []; + for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { + lineVertArray.push(vertArray[i + j][k]); + fillVertArray.push(vertArray[i + j][k]) + } + for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(vertArray[i + j][k]); + for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { + strokeVertArray.push(vertArray[i + j][k + 4]); + colorVertArray.push(vertArray[i + j][k]) + } + if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray); + if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray) + } + } else if (curShape === 11) { + if (vertArrayLength > 2) { + for (i = 0; i < 3; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < 3; i++) { + cachedVertArray = vertArray[i]; + for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) + } + if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); + for (i = 2; i + 1 < vertArrayLength; i++) { + lineVertArray = []; + strokeVertArray = []; + lineVertArray.push(vertArray[0][0]); + lineVertArray.push(vertArray[0][1]); + lineVertArray.push(vertArray[0][2]); + strokeVertArray.push(vertArray[0][9]); + strokeVertArray.push(vertArray[0][10]); + strokeVertArray.push(vertArray[0][11]); + strokeVertArray.push(vertArray[0][12]); + for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) lineVertArray.push(vertArray[i + j][k]); + for (j = 0; j < 2; j++) for (k = 9; k < 13; k++) strokeVertArray.push(vertArray[i + j][k]); + if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) + } + if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray) + } + } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { + lineVertArray = []; + for (j = 0; j < 4; j++) { + cachedVertArray = vertArray[i + j]; + for (k = 0; k < 3; k++) lineVertArray.push(cachedVertArray[k]) + } + if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); + if (doFill) { + fillVertArray = []; + colorVertArray = []; + texVertArray = []; + for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); + for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]); + for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 1][j]); + for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 1][j]); + for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 3][j]); + for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 3][j]); + for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 2][j]); + for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 2][j]); + if (usingTexture) { + texVertArray.push(vertArray[i + 0][3]); + texVertArray.push(vertArray[i + 0][4]); + texVertArray.push(vertArray[i + 1][3]); + texVertArray.push(vertArray[i + 1][4]); + texVertArray.push(vertArray[i + 3][3]); + texVertArray.push(vertArray[i + 3][4]); + texVertArray.push(vertArray[i + 2][3]); + texVertArray.push(vertArray[i + 2][4]) + } + fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray) + } + } else if (curShape === 17) { + var tempArray = []; + if (vertArrayLength > 3) { + for (i = 0; i < 2; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) + } + for (i = 0; i < 2; i++) { + cachedVertArray = vertArray[i]; + for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) + } + line3D(lineVertArray, "LINE_STRIP", strokeVertArray); + if (vertArrayLength > 4 && vertArrayLength % 2 > 0) { + tempArray = fillVertArray.splice(fillVertArray.length - 3); + vertArray.pop() + } + for (i = 0; i + 3 < vertArrayLength; i += 2) { + lineVertArray = []; + strokeVertArray = []; + for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 1][j]); + for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 3][j]); + for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 2][j]); + for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 0][j]); + for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 1][j]); + for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 3][j]); + for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 2][j]); + for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 0][j]); + if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) + } + if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_LIST", colorVertArray, texVertArray) + } + } else if (vertArrayLength === 1) { + for (j = 0; j < 3; j++) lineVertArray.push(vertArray[0][j]); + for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[0][j]); + point3D(lineVertArray, strokeVertArray) + } else { + for (i = 0; i < vertArrayLength; i++) { + cachedVertArray = vertArray[i]; + for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]); + for (j = 5; j < 9; j++) strokeVertArray.push(cachedVertArray[j]) + } + if (doStroke && closeShape) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); + else if (doStroke && !closeShape) line3D(lineVertArray, "LINE_STRIP", strokeVertArray); + if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray) + } + usingTexture = false; + curContext.useProgram(programObject3D); + uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture) + } + isCurve = false; + isBezier = false; + curveVertArray = []; + curveVertCount = 0 + }; + var splineForward = function(segments, matrix) { + var f = 1 / segments; + var ff = f * f; + var fff = ff * f; + matrix.set(0, 0, 0, 1, fff, ff, f, 0, 6 * fff, 2 * ff, 0, 0, 6 * fff, 0, 0, 0) + }; + var curveInit = function() { + if (!curveDrawMatrix) { + curveBasisMatrix = new PMatrix3D; + curveDrawMatrix = new PMatrix3D; + curveInited = true + } + var s = curTightness; + curveBasisMatrix.set((s - 1) / 2, (s + 3) / 2, (-3 - s) / 2, (1 - s) / 2, 1 - s, (-5 - s) / 2, s + 2, (s - 1) / 2, (s - 1) / 2, 0, (1 - s) / 2, 0, 0, 1, 0, 0); + splineForward(curveDet, curveDrawMatrix); + if (!bezierBasisInverse) curveToBezierMatrix = new PMatrix3D; + curveToBezierMatrix.set(curveBasisMatrix); + curveToBezierMatrix.preApply(bezierBasisInverse); + curveDrawMatrix.apply(curveBasisMatrix) + }; + Drawing2D.prototype.bezierVertex = function() { + isBezier = true; + var vert = []; + if (firstVert) throw "vertex() must be used at least once before calling bezierVertex()"; + for (var i = 0; i < arguments.length; i++) vert[i] = arguments[i]; + vertArray.push(vert); + vertArray[vertArray.length - 1]["isVert"] = false + }; + Drawing3D.prototype.bezierVertex = function() { + isBezier = true; + var vert = []; + if (firstVert) throw "vertex() must be used at least once before calling bezierVertex()"; + if (arguments.length === 9) { + if (bezierDrawMatrix === undef) bezierDrawMatrix = new PMatrix3D; + var lastPoint = vertArray.length - 1; + splineForward(bezDetail, bezierDrawMatrix); + bezierDrawMatrix.apply(bezierBasisMatrix); + var draw = bezierDrawMatrix.array(); + var x1 = vertArray[lastPoint][0], + y1 = vertArray[lastPoint][1], + z1 = vertArray[lastPoint][2]; + var xplot1 = draw[4] * x1 + draw[5] * arguments[0] + draw[6] * arguments[3] + draw[7] * arguments[6]; + var xplot2 = draw[8] * x1 + draw[9] * arguments[0] + draw[10] * arguments[3] + draw[11] * arguments[6]; + var xplot3 = draw[12] * x1 + draw[13] * arguments[0] + draw[14] * arguments[3] + draw[15] * arguments[6]; + var yplot1 = draw[4] * y1 + draw[5] * arguments[1] + draw[6] * arguments[4] + draw[7] * arguments[7]; + var yplot2 = draw[8] * y1 + draw[9] * arguments[1] + draw[10] * arguments[4] + draw[11] * arguments[7]; + var yplot3 = draw[12] * y1 + draw[13] * arguments[1] + draw[14] * arguments[4] + draw[15] * arguments[7]; + var zplot1 = draw[4] * z1 + draw[5] * arguments[2] + draw[6] * arguments[5] + draw[7] * arguments[8]; + var zplot2 = draw[8] * z1 + draw[9] * arguments[2] + draw[10] * arguments[5] + draw[11] * arguments[8]; + var zplot3 = draw[12] * z1 + draw[13] * arguments[2] + draw[14] * arguments[5] + draw[15] * arguments[8]; + for (var j = 0; j < bezDetail; j++) { + x1 += xplot1; + xplot1 += xplot2; + xplot2 += xplot3; + y1 += yplot1; + yplot1 += yplot2; + yplot2 += yplot3; + z1 += zplot1; + zplot1 += zplot2; + zplot2 += zplot3; + p.vertex(x1, y1, z1) + } + p.vertex(arguments[6], arguments[7], arguments[8]) + } + }; + p.texture = function(pimage) { + var curContext = drawing.$ensureContext(); + if (pimage.__texture) curContext.bindTexture(curContext.TEXTURE_2D, pimage.__texture); + else if (pimage.localName === "canvas") { + curContext.bindTexture(curContext.TEXTURE_2D, canTex); + curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, pimage); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); + curContext.generateMipmap(curContext.TEXTURE_2D); + curTexture.width = pimage.width; + curTexture.height = pimage.height + } else { + var texture = curContext.createTexture(), + cvs = document.createElement("canvas"), + cvsTextureCtx = cvs.getContext("2d"), + pot; + if (pimage.width & pimage.width - 1 === 0) cvs.width = pimage.width; + else { + pot = 1; + while (pot < pimage.width) pot *= 2; + cvs.width = pot + } + if (pimage.height & pimage.height - 1 === 0) cvs.height = pimage.height; + else { + pot = 1; + while (pot < pimage.height) pot *= 2; + cvs.height = pot + } + cvsTextureCtx.drawImage(pimage.sourceImg, 0, 0, pimage.width, pimage.height, 0, 0, cvs.width, cvs.height); + curContext.bindTexture(curContext.TEXTURE_2D, texture); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR_MIPMAP_LINEAR); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); + curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, cvs); + curContext.generateMipmap(curContext.TEXTURE_2D); + pimage.__texture = texture; + curTexture.width = pimage.width; + curTexture.height = pimage.height + } + usingTexture = true; + curContext.useProgram(programObject3D); + uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture) + }; + p.textureMode = function(mode) { + curTextureMode = mode + }; + var curveVertexSegment = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { + var x0 = x2; + var y0 = y2; + var z0 = z2; + var draw = curveDrawMatrix.array(); + var xplot1 = draw[4] * x1 + draw[5] * x2 + draw[6] * x3 + draw[7] * x4; + var xplot2 = draw[8] * x1 + draw[9] * x2 + draw[10] * x3 + draw[11] * x4; + var xplot3 = draw[12] * x1 + draw[13] * x2 + draw[14] * x3 + draw[15] * x4; + var yplot1 = draw[4] * y1 + draw[5] * y2 + draw[6] * y3 + draw[7] * y4; + var yplot2 = draw[8] * y1 + draw[9] * y2 + draw[10] * y3 + draw[11] * y4; + var yplot3 = draw[12] * y1 + draw[13] * y2 + draw[14] * y3 + draw[15] * y4; + var zplot1 = draw[4] * z1 + draw[5] * z2 + draw[6] * z3 + draw[7] * z4; + var zplot2 = draw[8] * z1 + draw[9] * z2 + draw[10] * z3 + draw[11] * z4; + var zplot3 = draw[12] * z1 + draw[13] * z2 + draw[14] * z3 + draw[15] * z4; + p.vertex(x0, y0, z0); + for (var j = 0; j < curveDet; j++) { + x0 += xplot1; + xplot1 += xplot2; + xplot2 += xplot3; + y0 += yplot1; + yplot1 += yplot2; + yplot2 += yplot3; + z0 += zplot1; + zplot1 += zplot2; + zplot2 += zplot3; + p.vertex(x0, y0, z0) + } + }; + Drawing2D.prototype.curveVertex = function(x, y) { + isCurve = true; + p.vertex(x, y) + }; + Drawing3D.prototype.curveVertex = function(x, y, z) { + isCurve = true; + if (!curveInited) curveInit(); + var vert = []; + vert[0] = x; + vert[1] = y; + vert[2] = z; + curveVertArray.push(vert); + curveVertCount++; + if (curveVertCount > 3) curveVertexSegment(curveVertArray[curveVertCount - 4][0], curveVertArray[curveVertCount - 4][1], curveVertArray[curveVertCount - 4][2], curveVertArray[curveVertCount - 3][0], curveVertArray[curveVertCount - 3][1], curveVertArray[curveVertCount - 3][2], curveVertArray[curveVertCount - 2][0], curveVertArray[curveVertCount - 2][1], curveVertArray[curveVertCount - 2][2], curveVertArray[curveVertCount - 1][0], curveVertArray[curveVertCount - 1][1], curveVertArray[curveVertCount - 1][2]) + }; + Drawing2D.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) { + p.beginShape(); + p.curveVertex(x1, y1); + p.curveVertex(x2, y2); + p.curveVertex(x3, y3); + p.curveVertex(x4, y4); + p.endShape() + }; + Drawing3D.prototype.curve = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { + if (z4 !== undef) { + p.beginShape(); + p.curveVertex(x1, y1, z1); + p.curveVertex(x2, y2, z2); + p.curveVertex(x3, y3, z3); + p.curveVertex(x4, y4, z4); + p.endShape(); + return + } + p.beginShape(); + p.curveVertex(x1, y1); + p.curveVertex(z1, x2); + p.curveVertex(y2, z2); + p.curveVertex(x3, y3); + p.endShape() + }; + p.curveTightness = function(tightness) { + curTightness = tightness + }; + p.curveDetail = function(detail) { + curveDet = detail; + curveInit() + }; + p.rectMode = function(aRectMode) { + curRectMode = aRectMode + }; + p.imageMode = function(mode) { + switch (mode) { + case 0: + imageModeConvert = imageModeCorner; + break; + case 1: + imageModeConvert = imageModeCorners; + break; + case 3: + imageModeConvert = imageModeCenter; + break; + default: + throw "Invalid imageMode"; + } + }; + p.ellipseMode = function(aEllipseMode) { + curEllipseMode = aEllipseMode + }; + p.arc = function(x, y, width, height, start, stop) { + if (width <= 0 || stop < start) return; + if (curEllipseMode === 1) { + width = width - x; + height = height - y + } else if (curEllipseMode === 2) { + x = x - width; + y = y - height; + width = width * 2; + height = height * 2 + } else if (curEllipseMode === 3) { + x = x - width / 2; + y = y - height / 2 + } + while (start < 0) { + start += 6.283185307179586; + stop += 6.283185307179586 + } + if (stop - start > 6.283185307179586) { + start = 0; + stop = 6.283185307179586 + } + var hr = width / 2, + vr = height / 2, + centerX = x + hr, + centerY = y + vr, + startLUT = 0 | 0.5 + start * p.RAD_TO_DEG * 2, + stopLUT = 0 | 0.5 + stop * p.RAD_TO_DEG * 2, + i, j; + if (doFill) { + var savedStroke = doStroke; + doStroke = false; + p.beginShape(); + p.vertex(centerX, centerY); + for (i = startLUT; i <= stopLUT; i++) { + j = i % 720; + p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr) + } + p.endShape(2); + doStroke = savedStroke + } + if (doStroke) { + var savedFill = doFill; + doFill = false; + p.beginShape(); + for (i = startLUT; i <= stopLUT; i++) { + j = i % 720; + p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr) + } + p.endShape(); + doFill = savedFill + } + }; + Drawing2D.prototype.line = function(x1, y1, x2, y2) { + if (!doStroke) return; + x1 = Math.round(x1); + x2 = Math.round(x2); + y1 = Math.round(y1); + y2 = Math.round(y2); + if (x1 === x2 && y1 === y2) { + p.point(x1, y1); + return + } + var swap = undef, + lineCap = undef, + drawCrisp = true, + currentModelView = modelView.array(), + identityMatrix = [1, 0, 0, 0, 1, 0]; + for (var i = 0; i < 6 && drawCrisp; i++) drawCrisp = currentModelView[i] === identityMatrix[i]; + if (drawCrisp) { + if (x1 === x2) { + if (y1 > y2) { + swap = y1; + y1 = y2; + y2 = swap + } + y2++; + if (lineWidth % 2 === 1) curContext.translate(0.5, 0) + } else if (y1 === y2) { + if (x1 > x2) { + swap = x1; + x1 = x2; + x2 = swap + } + x2++; + if (lineWidth % 2 === 1) curContext.translate(0, 0.5) + } + if (lineWidth === 1) { + lineCap = curContext.lineCap; + curContext.lineCap = "butt" + } + } + curContext.beginPath(); + curContext.moveTo(x1 || 0, y1 || 0); + curContext.lineTo(x2 || 0, y2 || 0); + executeContextStroke(); + if (drawCrisp) { + if (x1 === x2 && lineWidth % 2 === 1) curContext.translate(-0.5, 0); + else if (y1 === y2 && lineWidth % 2 === 1) curContext.translate(0, -0.5); + if (lineWidth === 1) curContext.lineCap = lineCap + } + }; + Drawing3D.prototype.line = function(x1, y1, z1, x2, y2, z2) { + if (y2 === undef || z2 === undef) { + z2 = 0; + y2 = x2; + x2 = z1; + z1 = 0 + } + if (x1 === x2 && y1 === y2 && z1 === z2) { + p.point(x1, y1, z1); + return + } + var lineVerts = [x1, y1, z1, x2, y2, z2]; + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + if (lineWidth > 0 && doStroke) { + curContext.useProgram(programObject2D); + uniformMatrix("uModel2d", programObject2D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + uniformf("uColor2d", programObject2D, "uColor", strokeStyle); + uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); + vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, lineBuffer); + disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); + curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(lineVerts), curContext.STREAM_DRAW); + curContext.drawArrays(curContext.LINES, 0, 2) + } + }; + Drawing2D.prototype.bezier = function() { + if (arguments.length !== 8) throw "You must use 8 parameters for bezier() in 2D mode"; + p.beginShape(); + p.vertex(arguments[0], arguments[1]); + p.bezierVertex(arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); + p.endShape() + }; + Drawing3D.prototype.bezier = function() { + if (arguments.length !== 12) throw "You must use 12 parameters for bezier() in 3D mode"; + p.beginShape(); + p.vertex(arguments[0], arguments[1], arguments[2]); + p.bezierVertex(arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11]); + p.endShape() + }; + p.bezierDetail = function(detail) { + bezDetail = detail + }; + p.bezierPoint = function(a, b, c, d, t) { + return (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b + 3 * (1 - t) * t * t * c + t * t * t * d + }; + p.bezierTangent = function(a, b, c, d, t) { + return 3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b) + }; + p.curvePoint = function(a, b, c, d, t) { + return 0.5 * (2 * b + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t * t + (-a + 3 * b - 3 * c + d) * t * t * t) + }; + p.curveTangent = function(a, b, c, d, t) { + return 0.5 * (-a + c + 2 * (2 * a - 5 * b + 4 * c - d) * t + 3 * (-a + 3 * b - 3 * c + d) * t * t) + }; + p.triangle = function(x1, y1, x2, y2, x3, y3) { + p.beginShape(9); + p.vertex(x1, y1, 0); + p.vertex(x2, y2, 0); + p.vertex(x3, y3, 0); + p.endShape() + }; + p.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { + p.beginShape(16); + p.vertex(x1, y1, 0); + p.vertex(x2, y2, 0); + p.vertex(x3, y3, 0); + p.vertex(x4, y4, 0); + p.endShape() + }; + var roundedRect$2d = function(x, y, width, height, tl, tr, br, bl) { + if (bl === undef) { + tr = tl; + br = tl; + bl = tl + } + var halfWidth = width / 2, + halfHeight = height / 2; + if (tl > halfWidth || tl > halfHeight) tl = Math.min(halfWidth, halfHeight); + if (tr > halfWidth || tr > halfHeight) tr = Math.min(halfWidth, halfHeight); + if (br > halfWidth || br > halfHeight) br = Math.min(halfWidth, halfHeight); + if (bl > halfWidth || bl > halfHeight) bl = Math.min(halfWidth, halfHeight); + if (!doFill || doStroke) curContext.translate(0.5, 0.5); + curContext.beginPath(); + curContext.moveTo(x + tl, y); + curContext.lineTo(x + width - tr, y); + curContext.quadraticCurveTo(x + width, y, x + width, y + tr); + curContext.lineTo(x + width, y + height - br); + curContext.quadraticCurveTo(x + width, y + height, x + width - br, y + height); + curContext.lineTo(x + bl, y + height); + curContext.quadraticCurveTo(x, y + height, x, y + height - bl); + curContext.lineTo(x, y + tl); + curContext.quadraticCurveTo(x, y, x + tl, y); + if (!doFill || doStroke) curContext.translate(-0.5, -0.5); + executeContextFill(); + executeContextStroke() + }; + Drawing2D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { + if (!width && !height) return; + if (curRectMode === 1) { + width -= x; + height -= y + } else if (curRectMode === 2) { + width *= 2; + height *= 2; + x -= width / 2; + y -= height / 2 + } else if (curRectMode === 3) { + x -= width / 2; + y -= height / 2 + } + x = Math.round(x); + y = Math.round(y); + width = Math.round(width); + height = Math.round(height); + if (tl !== undef) { + roundedRect$2d(x, y, width, height, tl, tr, br, bl); + return + } + if (doStroke && lineWidth % 2 === 1) curContext.translate(0.5, 0.5); + curContext.beginPath(); + curContext.rect(x, y, width, height); + executeContextFill(); + executeContextStroke(); + if (doStroke && lineWidth % 2 === 1) curContext.translate(-0.5, -0.5) + }; + Drawing3D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { + if (tl !== undef) throw "rect() with rounded corners is not supported in 3D mode"; + if (curRectMode === 1) { + width -= x; + height -= y + } else if (curRectMode === 2) { + width *= 2; + height *= 2; + x -= width / 2; + y -= height / 2 + } else if (curRectMode === 3) { + x -= width / 2; + y -= height / 2 + } + var model = new PMatrix3D; + model.translate(x, y, 0); + model.scale(width, height, 1); + model.transpose(); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + if (lineWidth > 0 && doStroke) { + curContext.useProgram(programObject2D); + uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + uniformf("uColor2d", programObject2D, "uColor", strokeStyle); + uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); + vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, rectBuffer); + disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); + curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3) + } + if (doFill) { + curContext.useProgram(programObject3D); + uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); + uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); + curContext.enable(curContext.POLYGON_OFFSET_FILL); + curContext.polygonOffset(1, 1); + uniformf("color3d", programObject3D, "uColor", fillStyle); + if (lightCount > 0) { + var v = new PMatrix3D; + v.set(view); + var m = new PMatrix3D; + m.set(model); + v.mult(m); + var normalMatrix = new PMatrix3D; + normalMatrix.set(v); + normalMatrix.invert(); + normalMatrix.transpose(); + uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); + vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, rectNormBuffer) + } else disableVertexAttribPointer("normal3d", programObject3D, "aNormal"); + vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, rectBuffer); + curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3); + curContext.disable(curContext.POLYGON_OFFSET_FILL) + } + }; + Drawing2D.prototype.ellipse = function(x, y, width, height) { + x = x || 0; + y = y || 0; + if (width <= 0 && height <= 0) return; + if (curEllipseMode === 2) { + width *= 2; + height *= 2 + } else if (curEllipseMode === 1) { + width = width - x; + height = height - y; + x += width / 2; + y += height / 2 + } else if (curEllipseMode === 0) { + x += width / 2; + y += height / 2 + } + if (width === height) { + curContext.beginPath(); + curContext.arc(x, y, width / 2, 0, 6.283185307179586, false); + executeContextFill(); + executeContextStroke() + } else { + var w = width / 2, + h = height / 2, + C = 0.5522847498307933, + c_x = C * w, + c_y = C * h; + p.beginShape(); + p.vertex(x + w, y); + p.bezierVertex(x + w, y - c_y, x + c_x, y - h, x, y - h); + p.bezierVertex(x - c_x, y - h, x - w, y - c_y, x - w, y); + p.bezierVertex(x - w, y + c_y, x - c_x, y + h, x, y + h); + p.bezierVertex(x + c_x, y + h, x + w, y + c_y, x + w, y); + p.endShape() + } + }; + Drawing3D.prototype.ellipse = function(x, y, width, height) { + x = x || 0; + y = y || 0; + if (width <= 0 && height <= 0) return; + if (curEllipseMode === 2) { + width *= 2; + height *= 2 + } else if (curEllipseMode === 1) { + width = width - x; + height = height - y; + x += width / 2; + y += height / 2 + } else if (curEllipseMode === 0) { + x += width / 2; + y += height / 2 + } + var w = width / 2, + h = height / 2, + C = 0.5522847498307933, + c_x = C * w, + c_y = C * h; + p.beginShape(); + p.vertex(x + w, y); + p.bezierVertex(x + w, y - c_y, 0, x + c_x, y - h, 0, x, y - h, 0); + p.bezierVertex(x - c_x, y - h, 0, x - w, y - c_y, 0, x - w, y, 0); + p.bezierVertex(x - w, y + c_y, 0, x - c_x, y + h, 0, x, y + h, 0); + p.bezierVertex(x + c_x, y + h, 0, x + w, y + c_y, 0, x + w, y, 0); + p.endShape(); + if (doFill) { + var xAv = 0, + yAv = 0, + i, j; + for (i = 0; i < vertArray.length; i++) { + xAv += vertArray[i][0]; + yAv += vertArray[i][1] + } + xAv /= vertArray.length; + yAv /= vertArray.length; + var vert = [], + fillVertArray = [], + colorVertArray = []; + vert[0] = xAv; + vert[1] = yAv; + vert[2] = 0; + vert[3] = 0; + vert[4] = 0; + vert[5] = fillStyle[0]; + vert[6] = fillStyle[1]; + vert[7] = fillStyle[2]; + vert[8] = fillStyle[3]; + vert[9] = strokeStyle[0]; + vert[10] = strokeStyle[1]; + vert[11] = strokeStyle[2]; + vert[12] = strokeStyle[3]; + vert[13] = normalX; + vert[14] = normalY; + vert[15] = normalZ; + vertArray.unshift(vert); + for (i = 0; i < vertArray.length; i++) { + for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); + for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]) + } + fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray) + } + }; + p.normal = function(nx, ny, nz) { + if (arguments.length !== 3 || !(typeof nx === "number" && typeof ny === "number" && typeof nz === "number")) throw "normal() requires three numeric arguments."; + normalX = nx; + normalY = ny; + normalZ = nz; + if (curShape !== 0) if (normalMode === 0) normalMode = 1; + else if (normalMode === 1) normalMode = 2 + }; + p.save = function(file, img) { + if (img !== undef) return window.open(img.toDataURL(), "_blank"); + return window.open(p.externals.canvas.toDataURL(), "_blank") + }; + var saveNumber = 0; + p.saveFrame = function(file) { + if (file === undef) file = "screen-####.png"; + var frameFilename = file.replace(/#+/, function(all) { + var s = "" + saveNumber++; + while (s.length < all.length) s = "0" + s; + return s + }); + p.save(frameFilename) + }; + var utilityContext2d = document.createElement("canvas").getContext("2d"); + var canvasDataCache = [undef, undef, undef]; + + function getCanvasData(obj, w, h) { + var canvasData = canvasDataCache.shift(); + if (canvasData === undef) { + canvasData = {}; + canvasData.canvas = document.createElement("canvas"); + canvasData.context = canvasData.canvas.getContext("2d") + } + canvasDataCache.push(canvasData); + var canvas = canvasData.canvas, + context = canvasData.context, + width = w || obj.width, + height = h || obj.height; + canvas.width = width; + canvas.height = height; + if (!obj) context.clearRect(0, 0, width, height); + else if ("data" in obj) context.putImageData(obj, 0, 0); + else { + context.clearRect(0, 0, width, height); + context.drawImage(obj, 0, 0, width, height) + } + return canvasData + } + function buildPixelsObject(pImage) { + return { + getLength: function(aImg) { + return function() { + if (aImg.isRemote) throw "Image is loaded remotely. Cannot get length."; + else return aImg.imageData.data.length ? aImg.imageData.data.length / 4 : 0 + } + }(pImage), + getPixel: function(aImg) { + return function(i) { + var offset = i * 4, + data = aImg.imageData.data; + if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixels."; + return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 + } + }(pImage), + setPixel: function(aImg) { + return function(i, c) { + var offset = i * 4, + data = aImg.imageData.data; + if (aImg.isRemote) throw "Image is loaded remotely. Cannot set pixel."; + data[offset + 0] = (c >> 16) & 255; + data[offset + 1] = (c >> 8) & 255; + data[offset + 2] = c & 255; + data[offset + 3] = (c >> 24) & 255; + aImg.__isDirty = true + } + }(pImage), + toArray: function(aImg) { + return function() { + var arr = [], + data = aImg.imageData.data, + length = aImg.width * aImg.height; + if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixels."; + for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push((data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255); + return arr + } + }(pImage), + set: function(aImg) { + return function(arr) { + var offset, data, c; + if (this.isRemote) throw "Image is loaded remotely. Cannot set pixels."; + data = aImg.imageData.data; + for (var i = 0, aL = arr.length; i < aL; i++) { + c = arr[i]; + offset = i * 4; + data[offset + 0] = (c >> 16) & 255; + data[offset + 1] = (c >> 8) & 255; + data[offset + 2] = c & 255; + data[offset + 3] = (c >> 24) & 255 + } + aImg.__isDirty = true + } + }(pImage) + } + } + var PImage = function(aWidth, aHeight, aFormat) { + this.__isDirty = false; + if (aWidth instanceof HTMLImageElement) this.fromHTMLImageData(aWidth); + else if (aHeight || aFormat) { + this.width = aWidth || 1; + this.height = aHeight || 1; + var canvas = this.sourceImg = document.createElement("canvas"); + canvas.width = this.width; + canvas.height = this.height; + var imageData = this.imageData = canvas.getContext("2d").createImageData(this.width, this.height); + this.format = aFormat === 2 || aFormat === 4 ? aFormat : 1; + if (this.format === 1) for (var i = 3, data = this.imageData.data, len = data.length; i < len; i += 4) data[i] = 255; + this.__isDirty = true; + this.updatePixels() + } else { + this.width = 0; + this.height = 0; + this.imageData = utilityContext2d.createImageData(1, 1); + this.format = 2 + } + this.pixels = buildPixelsObject(this) + }; + PImage.prototype = { + __isPImage: true, + updatePixels: function() { + var canvas = this.sourceImg; + if (canvas && canvas instanceof HTMLCanvasElement && this.__isDirty) canvas.getContext("2d").putImageData(this.imageData, 0, 0); + this.__isDirty = false + }, + fromHTMLImageData: function(htmlImg) { + var canvasData = getCanvasData(htmlImg); + try { + var imageData = canvasData.context.getImageData(0, 0, htmlImg.width, htmlImg.height); + this.fromImageData(imageData) + } catch(e) { + if (htmlImg.width && htmlImg.height) { + this.isRemote = true; + this.width = htmlImg.width; + this.height = htmlImg.height + } + } + this.sourceImg = htmlImg + }, + "get": function(x, y, w, h) { + if (!arguments.length) return p.get(this); + if (arguments.length === 2) return p.get(x, y, this); + if (arguments.length === 4) return p.get(x, y, w, h, this) + }, + "set": function(x, y, c) { + p.set(x, y, c, this); + this.__isDirty = true + }, + blend: function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE) { + if (arguments.length === 9) p.blend(this, srcImg, x, y, width, height, dx, dy, dwidth, dheight, this); + else if (arguments.length === 10) p.blend(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE, this); + delete this.sourceImg + }, + copy: function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) { + if (arguments.length === 8) p.blend(this, srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, 0, this); + else if (arguments.length === 9) p.blend(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight, 0, this); + delete this.sourceImg + }, + filter: function(mode, param) { + if (arguments.length === 2) p.filter(mode, param, this); + else if (arguments.length === 1) p.filter(mode, null, this); + delete this.sourceImg + }, + save: function(file) { + p.save(file, this) + }, + resize: function(w, h) { + if (this.isRemote) throw "Image is loaded remotely. Cannot resize."; + if (this.width !== 0 || this.height !== 0) { + if (w === 0 && h !== 0) w = Math.floor(this.width / this.height * h); + else if (h === 0 && w !== 0) h = Math.floor(this.height / this.width * w); + var canvas = getCanvasData(this.imageData).canvas; + var imageData = getCanvasData(canvas, w, h).context.getImageData(0, 0, w, h); + this.fromImageData(imageData) + } + }, + mask: function(mask) { + var obj = this.toImageData(), + i, size; + if (mask instanceof PImage || mask.__isPImage) if (mask.width === this.width && mask.height === this.height) { + mask = mask.toImageData(); + for (i = 2, size = this.width * this.height * 4; i < size; i += 4) obj.data[i + 1] = mask.data[i] + } else throw "mask must have the same dimensions as PImage."; + else if (mask instanceof + Array) if (this.width * this.height === mask.length) for (i = 0, size = mask.length; i < size; ++i) obj.data[i * 4 + 3] = mask[i]; + else throw "mask array must be the same length as PImage pixels array."; + this.fromImageData(obj) + }, + loadPixels: nop, + toImageData: function() { + if (this.isRemote) return this.sourceImg; + if (!this.__isDirty) return this.imageData; + var canvasData = getCanvasData(this.sourceImg); + return canvasData.context.getImageData(0, 0, this.width, this.height) + }, + toDataURL: function() { + if (this.isRemote) throw "Image is loaded remotely. Cannot create dataURI."; + var canvasData = getCanvasData(this.imageData); + return canvasData.canvas.toDataURL() + }, + fromImageData: function(canvasImg) { + var w = canvasImg.width, + h = canvasImg.height, + canvas = document.createElement("canvas"), + ctx = canvas.getContext("2d"); + this.width = canvas.width = w; + this.height = canvas.height = h; + ctx.putImageData(canvasImg, 0, 0); + this.format = 2; + this.imageData = canvasImg; + this.sourceImg = canvas + } + }; + p.PImage = PImage; + p.createImage = function(w, h, mode) { + return new PImage(w, h, mode) + }; + p.loadImage = function(file, type, callback) { + if (type) file = file + "." + type; + var pimg; + if (curSketch.imageCache.images[file]) { + pimg = new PImage(curSketch.imageCache.images[file]); + pimg.loaded = true; + return pimg + } + pimg = new PImage; + var img = document.createElement("img"); + pimg.sourceImg = img; + img.onload = function(aImage, aPImage, aCallback) { + var image = aImage; + var pimg = aPImage; + var callback = aCallback; + return function() { + pimg.fromHTMLImageData(image); + pimg.loaded = true; + if (callback) callback() + } + }(img, pimg, callback); + img.src = file; + return pimg + }; + p.requestImage = p.loadImage; + + function get$2(x, y) { + var data; + if (x >= p.width || x < 0 || y < 0 || y >= p.height) return 0; + if (isContextReplaced) { + var offset = ((0 | x) + p.width * (0 | y)) * 4; + data = p.imageData.data; + return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 + } + data = p.toImageData(0 | x, 0 | y, 1, 1).data; + return (data[3] & 255) << 24 | (data[0] & 255) << 16 | (data[1] & 255) << 8 | data[2] & 255 + } + function get$3(x, y, img) { + if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y."; + var offset = y * img.width * 4 + x * 4, + data = img.imageData.data; + return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 + } + function get$4(x, y, w, h) { + var c = new PImage(w, h, 2); + c.fromImageData(p.toImageData(x, y, w, h)); + return c + } + function get$5(x, y, w, h, img) { + if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y,w,h."; + var c = new PImage(w, h, 2), + cData = c.imageData.data, + imgWidth = img.width, + imgHeight = img.height, + imgData = img.imageData.data; + var startRow = Math.max(0, -y), + startColumn = Math.max(0, -x), + stopRow = Math.min(h, imgHeight - y), + stopColumn = Math.min(w, imgWidth - x); + for (var i = startRow; i < stopRow; ++i) { + var sourceOffset = ((y + i) * imgWidth + (x + startColumn)) * 4; + var targetOffset = (i * w + startColumn) * 4; + for (var j = startColumn; j < stopColumn; ++j) { + cData[targetOffset++] = imgData[sourceOffset++]; + cData[targetOffset++] = imgData[sourceOffset++]; + cData[targetOffset++] = imgData[sourceOffset++]; + cData[targetOffset++] = imgData[sourceOffset++] + } + } + c.__isDirty = true; + return c + } + p.get = function(x, y, w, h, img) { + if (img !== undefined) return get$5(x, y, w, h, img); + if (h !== undefined) return get$4(x, y, w, h); + if (w !== undefined) return get$3(x, y, w); + if (y !== undefined) return get$2(x, y); + if (x !== undefined) return get$5(0, 0, x.width, x.height, x); + return get$4(0, 0, p.width, p.height) + }; + p.createGraphics = function(w, h, render) { + var pg = new Processing; + pg.size(w, h, render); + pg.background(0, 0); + return pg + }; + + function resetContext() { + if (isContextReplaced) { + curContext = originalContext; + isContextReplaced = false; + p.updatePixels() + } + } + + function SetPixelContextWrapper() { + function wrapFunction(newContext, name) { + function wrapper() { + resetContext(); + curContext[name].apply(curContext, arguments) + } + newContext[name] = wrapper + } + function wrapProperty(newContext, name) { + function getter() { + resetContext(); + return curContext[name] + } + function setter(value) { + resetContext(); + curContext[name] = value + } + p.defineProperty(newContext, name, { + get: getter, + set: setter + }) + } + for (var n in curContext) if (typeof curContext[n] === "function") wrapFunction(this, n); + else wrapProperty(this, n) + } + function replaceContext() { + if (isContextReplaced) return; + p.loadPixels(); + if (proxyContext === null) { + originalContext = curContext; + proxyContext = new SetPixelContextWrapper + } + isContextReplaced = true; + curContext = proxyContext; + setPixelsCached = 0 + } + function set$3(x, y, c) { + if (x < p.width && x >= 0 && y >= 0 && y < p.height) { + replaceContext(); + p.pixels.setPixel((0 | x) + p.width * (0 | y), c); + if (++setPixelsCached > maxPixelsCached) resetContext() + } + } + function set$4(x, y, obj, img) { + if (img.isRemote) throw "Image is loaded remotely. Cannot set x,y."; + var c = p.color.toArray(obj); + var offset = y * img.width * 4 + x * 4; + var data = img.imageData.data; + data[offset] = c[0]; + data[offset + 1] = c[1]; + data[offset + 2] = c[2]; + data[offset + 3] = c[3] + } + p.set = function(x, y, obj, img) { + var color, oldFill; + if (arguments.length === 3) if (typeof obj === "number") set$3(x, y, obj); + else { + if (obj instanceof PImage || obj.__isPImage) p.image(obj, x, y) + } else if (arguments.length === 4) set$4(x, y, obj, img) + }; + p.imageData = {}; + p.pixels = { + getLength: function() { + return p.imageData.data.length ? p.imageData.data.length / 4 : 0 + }, + getPixel: function(i) { + var offset = i * 4, + data = p.imageData.data; + return data[offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255 + }, + setPixel: function(i, c) { + var offset = i * 4, + data = p.imageData.data; + data[offset + 0] = (c & 16711680) >>> 16; + data[offset + 1] = (c & 65280) >>> 8; + data[offset + 2] = c & 255; + data[offset + 3] = (c & 4278190080) >>> 24 + }, + toArray: function() { + var arr = [], + length = p.imageData.width * p.imageData.height, + data = p.imageData.data; + for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push(data[offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255); + return arr + }, + set: function(arr) { + for (var i = 0, aL = arr.length; i < aL; i++) this.setPixel(i, arr[i]) + } + }; + p.loadPixels = function() { + p.imageData = drawing.$ensureContext().getImageData(0, 0, p.width, p.height) + }; + p.updatePixels = function() { + if (p.imageData) drawing.$ensureContext().putImageData(p.imageData, 0, 0) + }; + p.hint = function(which) { + var curContext = drawing.$ensureContext(); + if (which === 4) { + curContext.disable(curContext.DEPTH_TEST); + curContext.depthMask(false); + curContext.clear(curContext.DEPTH_BUFFER_BIT) + } else if (which === -4) { + curContext.enable(curContext.DEPTH_TEST); + curContext.depthMask(true) + } else if (which === -1 || which === 2) renderSmooth = true; + else if (which === 1) renderSmooth = false + }; + var backgroundHelper = function(arg1, arg2, arg3, arg4) { + var obj; + if (arg1 instanceof PImage || arg1.__isPImage) { + obj = arg1; + if (!obj.loaded) throw "Error using image in background(): PImage not loaded."; + if (obj.width !== p.width || obj.height !== p.height) throw "Background image must be the same dimensions as the canvas."; + } else obj = p.color(arg1, arg2, arg3, arg4); + backgroundObj = obj + }; + Drawing2D.prototype.background = function(arg1, arg2, arg3, arg4) { + if (arg1 !== undef) backgroundHelper(arg1, arg2, arg3, arg4); + if (backgroundObj instanceof PImage || backgroundObj.__isPImage) { + saveContext(); + curContext.setTransform(1, 0, 0, 1, 0, 0); + p.image(backgroundObj, 0, 0); + restoreContext() + } else { + saveContext(); + curContext.setTransform(1, 0, 0, 1, 0, 0); + if (p.alpha(backgroundObj) !== colorModeA) curContext.clearRect(0, 0, p.width, p.height); + curContext.fillStyle = p.color.toString(backgroundObj); + curContext.fillRect(0, 0, p.width, p.height); + isFillDirty = true; + restoreContext() + } + }; + Drawing3D.prototype.background = function(arg1, arg2, arg3, arg4) { + if (arguments.length > 0) backgroundHelper(arg1, arg2, arg3, arg4); + var c = p.color.toGLArray(backgroundObj); + curContext.clearColor(c[0], c[1], c[2], c[3]); + curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT) + }; + Drawing2D.prototype.image = function(img, x, y, w, h) { + x = Math.round(x); + y = Math.round(y); + if (img.width > 0) { + var wid = w || img.width; + var hgt = h || img.height; + var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.height, arguments.length < 4); + var fastImage = !!img.sourceImg && curTint === null; + if (fastImage) { + var htmlElement = img.sourceImg; + if (img.__isDirty) img.updatePixels(); + curContext.drawImage(htmlElement, 0, 0, htmlElement.width, htmlElement.height, bounds.x, bounds.y, bounds.w, bounds.h) + } else { + var obj = img.toImageData(); + if (curTint !== null) { + curTint(obj); + img.__isDirty = true + } + curContext.drawImage(getCanvasData(obj).canvas, 0, 0, img.width, img.height, bounds.x, bounds.y, bounds.w, bounds.h) + } + } + }; + Drawing3D.prototype.image = function(img, x, y, w, h) { + if (img.width > 0) { + x = Math.round(x); + y = Math.round(y); + w = w || img.width; + h = h || img.height; + p.beginShape(p.QUADS); + p.texture(img); + p.vertex(x, y, 0, 0, 0); + p.vertex(x, y + h, 0, 0, h); + p.vertex(x + w, y + h, 0, w, h); + p.vertex(x + w, y, 0, w, 0); + p.endShape() + } + }; + p.tint = function(a1, a2, a3, a4) { + var tintColor = p.color(a1, a2, a3, a4); + var r = p.red(tintColor) / colorModeX; + var g = p.green(tintColor) / colorModeY; + var b = p.blue(tintColor) / colorModeZ; + var a = p.alpha(tintColor) / colorModeA; + curTint = function(obj) { + var data = obj.data, + length = 4 * obj.width * obj.height; + for (var i = 0; i < length;) { + data[i++] *= r; + data[i++] *= g; + data[i++] *= b; + data[i++] *= a + } + }; + curTint3d = function(data) { + for (var i = 0; i < data.length;) { + data[i++] = r; + data[i++] = g; + data[i++] = b; + data[i++] = a + } + } + }; + p.noTint = function() { + curTint = null; + curTint3d = null + }; + p.copy = function(src, sx, sy, sw, sh, dx, dy, dw, dh) { + if (dh === undef) { + dh = dw; + dw = dy; + dy = dx; + dx = sh; + sh = sw; + sw = sy; + sy = sx; + sx = src; + src = p + } + p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, 0) + }; + p.blend = function(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) { + if (src.isRemote) throw "Image is loaded remotely. Cannot blend image."; + if (mode === undef) { + mode = dh; + dh = dw; + dw = dy; + dy = dx; + dx = sh; + sh = sw; + sw = sy; + sy = sx; + sx = src; + src = p + } + var sx2 = sx + sw, + sy2 = sy + sh, + dx2 = dx + dw, + dy2 = dy + dh, + dest = pimgdest || p; + if (pimgdest === undef || mode === undef) p.loadPixels(); + src.loadPixels(); + if (src === p && p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), 0, 0, sx2 - sx - 1, sy2 - sy - 1, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); + else p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); + if (pimgdest === undef) p.updatePixels() + }; + var buildBlurKernel = function(r) { + var radius = p.floor(r * 3.5), + i, radiusi; + radius = radius < 1 ? 1 : radius < 248 ? radius : 248; + if (p.shared.blurRadius !== radius) { + p.shared.blurRadius = radius; + p.shared.blurKernelSize = 1 + (p.shared.blurRadius << 1); + p.shared.blurKernel = new Float32Array(p.shared.blurKernelSize); + var sharedBlurKernal = p.shared.blurKernel; + var sharedBlurKernelSize = p.shared.blurKernelSize; + var sharedBlurRadius = p.shared.blurRadius; + for (i = 0; i < sharedBlurKernelSize; i++) sharedBlurKernal[i] = 0; + var radiusiSquared = (radius - 1) * (radius - 1); + for (i = 1; i < radius; i++) sharedBlurKernal[radius + i] = sharedBlurKernal[radiusi] = radiusiSquared; + sharedBlurKernal[radius] = radius * radius + } + }; + var blurARGB = function(r, aImg) { + var sum, cr, cg, cb, ca, c, m; + var read, ri, ym, ymi, bk0; + var wh = aImg.pixels.getLength(); + var r2 = new Float32Array(wh); + var g2 = new Float32Array(wh); + var b2 = new Float32Array(wh); + var a2 = new Float32Array(wh); + var yi = 0; + var x, y, i, offset; + buildBlurKernel(r); + var aImgHeight = aImg.height; + var aImgWidth = aImg.width; + var sharedBlurKernelSize = p.shared.blurKernelSize; + var sharedBlurRadius = p.shared.blurRadius; + var sharedBlurKernal = p.shared.blurKernel; + var pix = aImg.imageData.data; + for (y = 0; y < aImgHeight; y++) { + for (x = 0; x < aImgWidth; x++) { + cb = cg = cr = ca = sum = 0; + read = x - sharedBlurRadius; + if (read < 0) { + bk0 = -read; + read = 0 + } else { + if (read >= aImgWidth) break; + bk0 = 0 + } + for (i = bk0; i < sharedBlurKernelSize; i++) { + if (read >= aImgWidth) break; + offset = (read + yi) * 4; + m = sharedBlurKernal[i]; + ca += m * pix[offset + 3]; + cr += m * pix[offset]; + cg += m * pix[offset + 1]; + cb += m * pix[offset + 2]; + sum += m; + read++ + } + ri = yi + x; + a2[ri] = ca / sum; + r2[ri] = cr / sum; + g2[ri] = cg / sum; + b2[ri] = cb / sum + } + yi += aImgWidth + } + yi = 0; + ym = -sharedBlurRadius; + ymi = ym * aImgWidth; + for (y = 0; y < aImgHeight; y++) { + for (x = 0; x < aImgWidth; x++) { + cb = cg = cr = ca = sum = 0; + if (ym < 0) { + bk0 = ri = -ym; + read = x + } else { + if (ym >= aImgHeight) break; + bk0 = 0; + ri = ym; + read = x + ymi + } + for (i = bk0; i < sharedBlurKernelSize; i++) { + if (ri >= aImgHeight) break; + m = sharedBlurKernal[i]; + ca += m * a2[read]; + cr += m * r2[read]; + cg += m * g2[read]; + cb += m * b2[read]; + sum += m; + ri++; + read += aImgWidth + } + offset = (x + yi) * 4; + pix[offset] = cr / sum; + pix[offset + 1] = cg / sum; + pix[offset + 2] = cb / sum; + pix[offset + 3] = ca / sum + } + yi += aImgWidth; + ymi += aImgWidth; + ym++ + } + }; + var dilate = function(isInverted, aImg) { + var currIdx = 0; + var maxIdx = aImg.pixels.getLength(); + var out = new Int32Array(maxIdx); + var currRowIdx, maxRowIdx, colOrig, colOut, currLum; + var idxRight, idxLeft, idxUp, idxDown, colRight, colLeft, colUp, colDown, lumRight, lumLeft, lumUp, lumDown; + if (!isInverted) while (currIdx < maxIdx) { + currRowIdx = currIdx; + maxRowIdx = currIdx + aImg.width; + while (currIdx < maxRowIdx) { + colOrig = colOut = aImg.pixels.getPixel(currIdx); + idxLeft = currIdx - 1; + idxRight = currIdx + 1; + idxUp = currIdx - aImg.width; + idxDown = currIdx + aImg.width; + if (idxLeft < currRowIdx) idxLeft = currIdx; + if (idxRight >= maxRowIdx) idxRight = currIdx; + if (idxUp < 0) idxUp = 0; + if (idxDown >= maxIdx) idxDown = currIdx; + colUp = aImg.pixels.getPixel(idxUp); + colLeft = aImg.pixels.getPixel(idxLeft); + colDown = aImg.pixels.getPixel(idxDown); + colRight = aImg.pixels.getPixel(idxRight); + currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); + lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); + lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); + lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (colUp & 255); + lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); + if (lumLeft > currLum) { + colOut = colLeft; + currLum = lumLeft + } + if (lumRight > currLum) { + colOut = colRight; + currLum = lumRight + } + if (lumUp > currLum) { + colOut = colUp; + currLum = lumUp + } + if (lumDown > currLum) { + colOut = colDown; + currLum = lumDown + } + out[currIdx++] = colOut + } + } else while (currIdx < maxIdx) { + currRowIdx = currIdx; + maxRowIdx = currIdx + aImg.width; + while (currIdx < maxRowIdx) { + colOrig = colOut = aImg.pixels.getPixel(currIdx); + idxLeft = currIdx - 1; + idxRight = currIdx + 1; + idxUp = currIdx - aImg.width; + idxDown = currIdx + aImg.width; + if (idxLeft < currRowIdx) idxLeft = currIdx; + if (idxRight >= maxRowIdx) idxRight = currIdx; + if (idxUp < 0) idxUp = 0; + if (idxDown >= maxIdx) idxDown = currIdx; + colUp = aImg.pixels.getPixel(idxUp); + colLeft = aImg.pixels.getPixel(idxLeft); + colDown = aImg.pixels.getPixel(idxDown); + colRight = aImg.pixels.getPixel(idxRight); + currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); + lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); + lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); + lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (colUp & 255); + lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); + if (lumLeft < currLum) { + colOut = colLeft; + currLum = lumLeft + } + if (lumRight < currLum) { + colOut = colRight; + currLum = lumRight + } + if (lumUp < currLum) { + colOut = colUp; + currLum = lumUp + } + if (lumDown < currLum) { + colOut = colDown; + currLum = lumDown + } + out[currIdx++] = colOut + } + } + aImg.pixels.set(out) + }; + p.filter = function(kind, param, aImg) { + var img, col, lum, i; + if (arguments.length === 3) { + aImg.loadPixels(); + img = aImg + } else { + p.loadPixels(); + img = p + } + if (param === undef) param = null; + if (img.isRemote) throw "Image is loaded remotely. Cannot filter image."; + var imglen = img.pixels.getLength(); + switch (kind) { + case 11: + var radius = param || 1; + blurARGB(radius, img); + break; + case 12: + if (img.format === 4) { + for (i = 0; i < imglen; i++) { + col = 255 - img.pixels.getPixel(i); + img.pixels.setPixel(i, 4278190080 | col << 16 | col << 8 | col) + } + img.format = 1 + } else for (i = 0; i < imglen; i++) { + col = img.pixels.getPixel(i); + lum = 77 * (col >> 16 & 255) + 151 * (col >> 8 & 255) + 28 * (col & 255) >> 8; + img.pixels.setPixel(i, col & 4278190080 | lum << 16 | lum << 8 | lum) + } + break; + case 13: + for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel(i) ^ 16777215); + break; + case 15: + if (param === null) throw "Use filter(POSTERIZE, int levels) instead of filter(POSTERIZE)"; + var levels = p.floor(param); + if (levels < 2 || levels > 255) throw "Levels must be between 2 and 255 for filter(POSTERIZE, levels)"; + var levels1 = levels - 1; + for (i = 0; i < imglen; i++) { + var rlevel = img.pixels.getPixel(i) >> 16 & 255; + var glevel = img.pixels.getPixel(i) >> 8 & 255; + var blevel = img.pixels.getPixel(i) & 255; + rlevel = (rlevel * levels >> 8) * 255 / levels1; + glevel = (glevel * levels >> 8) * 255 / levels1; + blevel = (blevel * levels >> 8) * 255 / levels1; + img.pixels.setPixel(i, 4278190080 & img.pixels.getPixel(i) | rlevel << 16 | glevel << 8 | blevel) + } + break; + case 14: + for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel(i) | 4278190080); + img.format = 1; + break; + case 16: + if (param === null) param = 0.5; + if (param < 0 || param > 1) throw "Level must be between 0 and 1 for filter(THRESHOLD, level)"; + var thresh = p.floor(param * 255); + for (i = 0; i < imglen; i++) { + var max = p.max((img.pixels.getPixel(i) & 16711680) >> 16, p.max((img.pixels.getPixel(i) & 65280) >> 8, img.pixels.getPixel(i) & 255)); + img.pixels.setPixel(i, img.pixels.getPixel(i) & 4278190080 | (max < thresh ? 0 : 16777215)) + } + break; + case 17: + dilate(true, img); + break; + case 18: + dilate(false, img); + break + } + img.updatePixels() + }; + p.shared = { + fracU: 0, + ifU: 0, + fracV: 0, + ifV: 0, + u1: 0, + u2: 0, + v1: 0, + v2: 0, + sX: 0, + sY: 0, + iw: 0, + iw1: 0, + ih1: 0, + ul: 0, + ll: 0, + ur: 0, + lr: 0, + cUL: 0, + cLL: 0, + cUR: 0, + cLR: 0, + srcXOffset: 0, + srcYOffset: 0, + r: 0, + g: 0, + b: 0, + a: 0, + srcBuffer: null, + blurRadius: 0, + blurKernelSize: 0, + blurKernel: null + }; + p.intersect = function(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { + var sw = sx2 - sx1 + 1; + var sh = sy2 - sy1 + 1; + var dw = dx2 - dx1 + 1; + var dh = dy2 - dy1 + 1; + if (dx1 < sx1) { + dw += dx1 - sx1; + if (dw > sw) dw = sw + } else { + var w = sw + sx1 - dx1; + if (dw > w) dw = w + } + if (dy1 < sy1) { + dh += dy1 - sy1; + if (dh > sh) dh = sh + } else { + var h = sh + sy1 - dy1; + if (dh > h) dh = h + } + return ! (dw <= 0 || dh <= 0) + }; + var blendFuncs = {}; + blendFuncs[1] = p.modes.blend; + blendFuncs[2] = p.modes.add; + blendFuncs[4] = p.modes.subtract; + blendFuncs[8] = p.modes.lightest; + blendFuncs[16] = p.modes.darkest; + blendFuncs[0] = p.modes.replace; + blendFuncs[32] = p.modes.difference; + blendFuncs[64] = p.modes.exclusion; + blendFuncs[128] = p.modes.multiply; + blendFuncs[256] = p.modes.screen; + blendFuncs[512] = p.modes.overlay; + blendFuncs[1024] = p.modes.hard_light; + blendFuncs[2048] = p.modes.soft_light; + blendFuncs[4096] = p.modes.dodge; + blendFuncs[8192] = p.modes.burn; + p.blit_resize = function(img, srcX1, srcY1, srcX2, srcY2, destPixels, screenW, screenH, destX1, destY1, destX2, destY2, mode) { + var x, y; + if (srcX1 < 0) srcX1 = 0; + if (srcY1 < 0) srcY1 = 0; + if (srcX2 >= img.width) srcX2 = img.width - 1; + if (srcY2 >= img.height) srcY2 = img.height - 1; + var srcW = srcX2 - srcX1; + var srcH = srcY2 - srcY1; + var destW = destX2 - destX1; + var destH = destY2 - destY1; + if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screenW || destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) return; + var dx = Math.floor(srcW / destW * 32768); + var dy = Math.floor(srcH / destH * 32768); + var pshared = p.shared; + pshared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * 32768); + pshared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * 32768); + if (destX1 < 0) { + destW += destX1; + destX1 = 0 + } + if (destY1 < 0) { + destH += destY1; + destY1 = 0 + } + destW = Math.min(destW, screenW - destX1); + destH = Math.min(destH, screenH - destY1); + var destOffset = destY1 * screenW + destX1; + var destColor; + pshared.srcBuffer = img.imageData.data; + pshared.iw = img.width; + pshared.iw1 = img.width - 1; + pshared.ih1 = img.height - 1; + var filterBilinear = p.filter_bilinear, + filterNewScanline = p.filter_new_scanline, + blendFunc = blendFuncs[mode], + blendedColor, idx, cULoffset, cURoffset, cLLoffset, cLRoffset, ALPHA_MASK = 4278190080, + RED_MASK = 16711680, + GREEN_MASK = 65280, + BLUE_MASK = 255, + PREC_MAXVAL = 32767, + PRECISIONB = 15, + PREC_RED_SHIFT = 1, + PREC_ALPHA_SHIFT = 9, + srcBuffer = pshared.srcBuffer, + min = Math.min; + for (y = 0; y < destH; y++) { + pshared.sX = pshared.srcXOffset; + pshared.fracV = pshared.srcYOffset & PREC_MAXVAL; + pshared.ifV = PREC_MAXVAL - pshared.fracV; + pshared.v1 = (pshared.srcYOffset >> PRECISIONB) * pshared.iw; + pshared.v2 = min((pshared.srcYOffset >> PRECISIONB) + 1, pshared.ih1) * pshared.iw; + for (x = 0; x < destW; x++) { + idx = (destOffset + x) * 4; + destColor = destPixels[idx + 3] << 24 & ALPHA_MASK | destPixels[idx] << 16 & RED_MASK | destPixels[idx + 1] << 8 & GREEN_MASK | destPixels[idx + 2] & BLUE_MASK; + pshared.fracU = pshared.sX & PREC_MAXVAL; + pshared.ifU = PREC_MAXVAL - pshared.fracU; + pshared.ul = pshared.ifU * pshared.ifV >> PRECISIONB; + pshared.ll = pshared.ifU * pshared.fracV >> PRECISIONB; + pshared.ur = pshared.fracU * pshared.ifV >> PRECISIONB; + pshared.lr = pshared.fracU * pshared.fracV >> PRECISIONB; + pshared.u1 = pshared.sX >> PRECISIONB; + pshared.u2 = min(pshared.u1 + 1, pshared.iw1); + cULoffset = (pshared.v1 + pshared.u1) * 4; + cURoffset = (pshared.v1 + pshared.u2) * 4; + cLLoffset = (pshared.v2 + pshared.u1) * 4; + cLRoffset = (pshared.v2 + pshared.u2) * 4; + pshared.cUL = srcBuffer[cULoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cULoffset] << 16 & RED_MASK | srcBuffer[cULoffset + 1] << 8 & GREEN_MASK | srcBuffer[cULoffset + 2] & BLUE_MASK; + pshared.cUR = srcBuffer[cURoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cURoffset] << 16 & RED_MASK | srcBuffer[cURoffset + 1] << 8 & GREEN_MASK | srcBuffer[cURoffset + 2] & BLUE_MASK; + pshared.cLL = srcBuffer[cLLoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cLLoffset] << 16 & RED_MASK | srcBuffer[cLLoffset + 1] << 8 & GREEN_MASK | srcBuffer[cLLoffset + 2] & BLUE_MASK; + pshared.cLR = srcBuffer[cLRoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cLRoffset] << 16 & RED_MASK | srcBuffer[cLRoffset + 1] << 8 & GREEN_MASK | srcBuffer[cLRoffset + 2] & BLUE_MASK; + pshared.r = pshared.ul * ((pshared.cUL & RED_MASK) >> 16) + pshared.ll * ((pshared.cLL & RED_MASK) >> 16) + pshared.ur * ((pshared.cUR & RED_MASK) >> 16) + pshared.lr * ((pshared.cLR & RED_MASK) >> 16) << PREC_RED_SHIFT & RED_MASK; + pshared.g = pshared.ul * (pshared.cUL & GREEN_MASK) + pshared.ll * (pshared.cLL & GREEN_MASK) + pshared.ur * (pshared.cUR & GREEN_MASK) + pshared.lr * (pshared.cLR & GREEN_MASK) >>> PRECISIONB & GREEN_MASK; + pshared.b = pshared.ul * (pshared.cUL & BLUE_MASK) + pshared.ll * (pshared.cLL & BLUE_MASK) + pshared.ur * (pshared.cUR & BLUE_MASK) + pshared.lr * (pshared.cLR & BLUE_MASK) >>> PRECISIONB; + pshared.a = pshared.ul * ((pshared.cUL & ALPHA_MASK) >>> 24) + pshared.ll * ((pshared.cLL & ALPHA_MASK) >>> 24) + pshared.ur * ((pshared.cUR & ALPHA_MASK) >>> 24) + pshared.lr * ((pshared.cLR & ALPHA_MASK) >>> 24) << PREC_ALPHA_SHIFT & ALPHA_MASK; + blendedColor = blendFunc(destColor, pshared.a | pshared.r | pshared.g | pshared.b); + destPixels[idx] = (blendedColor & RED_MASK) >>> 16; + destPixels[idx + 1] = (blendedColor & GREEN_MASK) >>> 8; + destPixels[idx + 2] = blendedColor & BLUE_MASK; + destPixels[idx + 3] = (blendedColor & ALPHA_MASK) >>> 24; + pshared.sX += dx + } + destOffset += screenW; + pshared.srcYOffset += dy + } + }; + p.loadFont = function(name, size) { + if (name === undef) throw "font name required in loadFont."; + if (name.indexOf(".svg") === -1) { + if (size === undef) size = curTextFont.size; + return PFont.get(name, size) + } + var font = p.loadGlyphs(name); + return { + name: name, + css: "12px sans-serif", + glyph: true, + units_per_em: font.units_per_em, + horiz_adv_x: 1 / font.units_per_em * font.horiz_adv_x, + ascent: font.ascent, + descent: font.descent, + width: function(str) { + var width = 0; + var len = str.length; + for (var i = 0; i < len; i++) try { + width += parseFloat(p.glyphLook(p.glyphTable[name], str[i]).horiz_adv_x) + } catch(e) { + Processing.debug(e) + } + return width / p.glyphTable[name].units_per_em + } + } + }; + p.createFont = function(name, size) { + return p.loadFont(name, size) + }; + p.textFont = function(pfont, size) { + if (size !== undef) { + if (!pfont.glyph) pfont = PFont.get(pfont.name, size); + curTextSize = size + } + curTextFont = pfont; + curFontName = curTextFont.name; + curTextAscent = curTextFont.ascent; + curTextDescent = curTextFont.descent; + curTextLeading = curTextFont.leading; + var curContext = drawing.$ensureContext(); + curContext.font = curTextFont.css + }; + p.textSize = function(size) { + curTextFont = PFont.get(curFontName, size); + curTextSize = size; + curTextAscent = curTextFont.ascent; + curTextDescent = curTextFont.descent; + curTextLeading = curTextFont.leading; + var curContext = drawing.$ensureContext(); + curContext.font = curTextFont.css + }; + p.textAscent = function() { + return curTextAscent + }; + p.textDescent = function() { + return curTextDescent + }; + p.textLeading = function(leading) { + curTextLeading = leading + }; + p.textAlign = function(xalign, yalign) { + horizontalTextAlignment = xalign; + verticalTextAlignment = yalign || 0 + }; + + function toP5String(obj) { + if (obj instanceof String) return obj; + if (typeof obj === "number") { + if (obj === (0 | obj)) return obj.toString(); + return p.nf(obj, 0, 3) + } + if (obj === null || obj === undef) return ""; + return obj.toString() + } + Drawing2D.prototype.textWidth = function(str) { + var lines = toP5String(str).split(/\r?\n/g), + width = 0; + var i, linesCount = lines.length; + curContext.font = curTextFont.css; + for (i = 0; i < linesCount; ++i) width = Math.max(width, curTextFont.measureTextWidth(lines[i])); + return width | 0 + }; + Drawing3D.prototype.textWidth = function(str) { + var lines = toP5String(str).split(/\r?\n/g), + width = 0; + var i, linesCount = lines.length; + if (textcanvas === undef) textcanvas = document.createElement("canvas"); + var textContext = textcanvas.getContext("2d"); + textContext.font = curTextFont.css; + for (i = 0; i < linesCount; ++i) width = Math.max(width, textContext.measureText(lines[i]).width); + return width | 0 + }; + p.glyphLook = function(font, chr) { + try { + switch (chr) { + case "1": + return font.one; + case "2": + return font.two; + case "3": + return font.three; + case "4": + return font.four; + case "5": + return font.five; + case "6": + return font.six; + case "7": + return font.seven; + case "8": + return font.eight; + case "9": + return font.nine; + case "0": + return font.zero; + case " ": + return font.space; + case "$": + return font.dollar; + case "!": + return font.exclam; + case '"': + return font.quotedbl; + case "#": + return font.numbersign; + case "%": + return font.percent; + case "&": + return font.ampersand; + case "'": + return font.quotesingle; + case "(": + return font.parenleft; + case ")": + return font.parenright; + case "*": + return font.asterisk; + case "+": + return font.plus; + case ",": + return font.comma; + case "-": + return font.hyphen; + case ".": + return font.period; + case "/": + return font.slash; + case "_": + return font.underscore; + case ":": + return font.colon; + case ";": + return font.semicolon; + case "<": + return font.less; + case "=": + return font.equal; + case ">": + return font.greater; + case "?": + return font.question; + case "@": + return font.at; + case "[": + return font.bracketleft; + case "\\": + return font.backslash; + case "]": + return font.bracketright; + case "^": + return font.asciicircum; + case "`": + return font.grave; + case "{": + return font.braceleft; + case "|": + return font.bar; + case "}": + return font.braceright; + case "~": + return font.asciitilde; + default: + return font[chr] + } + } catch(e) { + Processing.debug(e) + } + }; + Drawing2D.prototype.text$line = function(str, x, y, z, align) { + var textWidth = 0, + xOffset = 0; + if (!curTextFont.glyph) { + if (str && "fillText" in curContext) { + if (isFillDirty) { + curContext.fillStyle = p.color.toString(currentFillColor); + isFillDirty = false + } + if (align === 39 || align === 3) { + textWidth = curTextFont.measureTextWidth(str); + if (align === 39) xOffset = -textWidth; + else xOffset = -textWidth / 2 + } + curContext.fillText(str, x + xOffset, y) + } + } else { + var font = p.glyphTable[curFontName]; + saveContext(); + curContext.translate(x, y + curTextSize); + if (align === 39 || align === 3) { + textWidth = font.width(str); + if (align === 39) xOffset = -textWidth; + else xOffset = -textWidth / 2 + } + var upem = font.units_per_em, + newScale = 1 / upem * curTextSize; + curContext.scale(newScale, newScale); + for (var i = 0, len = str.length; i < len; i++) try { + p.glyphLook(font, str[i]).draw() + } catch(e) { + Processing.debug(e) + } + restoreContext() + } + }; + Drawing3D.prototype.text$line = function(str, x, y, z, align) { + if (textcanvas === undef) textcanvas = document.createElement("canvas"); + var oldContext = curContext; + curContext = textcanvas.getContext("2d"); + curContext.font = curTextFont.css; + var textWidth = curTextFont.measureTextWidth(str); + textcanvas.width = textWidth; + textcanvas.height = curTextSize; + curContext = textcanvas.getContext("2d"); + curContext.font = curTextFont.css; + curContext.textBaseline = "top"; + Drawing2D.prototype.text$line(str, 0, 0, 0, 37); + var aspect = textcanvas.width / textcanvas.height; + curContext = oldContext; + curContext.bindTexture(curContext.TEXTURE_2D, textTex); + curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, textcanvas); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); + curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); + var xOffset = 0; + if (align === 39) xOffset = -textWidth; + else if (align === 3) xOffset = -textWidth / 2; + var model = new PMatrix3D; + var scalefactor = curTextSize * 0.5; + model.translate(x + xOffset - scalefactor / 2, y - scalefactor, z); + model.scale(-aspect * scalefactor, -scalefactor, scalefactor); + model.translate(-1, -1, -1); + model.transpose(); + var view = new PMatrix3D; + view.scale(1, -1, 1); + view.apply(modelView.array()); + view.transpose(); + curContext.useProgram(programObject2D); + vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, textBuffer); + vertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord", 2, textureBuffer); + uniformi("uSampler2d", programObject2D, "uSampler", [0]); + uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", true); + uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); + uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); + uniformf("uColor2d", programObject2D, "uColor", fillStyle); + curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); + curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT, 0) + }; + + function text$4(str, x, y, z) { + var lines, linesCount; + if (str.indexOf("\n") < 0) { + lines = [str]; + linesCount = 1 + } else { + lines = str.split(/\r?\n/g); + linesCount = lines.length + } + var yOffset = 0; + if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescent; + else if (verticalTextAlignment === 3) yOffset = curTextAscent / 2 - (linesCount - 1) * curTextLeading / 2; + else if (verticalTextAlignment === 102) yOffset = -(curTextDescent + (linesCount - 1) * curTextLeading); + for (var i = 0; i < linesCount; ++i) { + var line = lines[i]; + drawing.text$line(line, x, y + yOffset, z, horizontalTextAlignment); + yOffset += curTextLeading + } + } + function text$6(str, x, y, width, height, z) { + if (str.length === 0 || width === 0 || height === 0) return; + if (curTextSize > height) return; + var spaceMark = -1; + var start = 0; + var lineWidth = 0; + var drawCommands = []; + for (var charPos = 0, len = str.length; charPos < len; charPos++) { + var currentChar = str[charPos]; + var spaceChar = currentChar === " "; + var letterWidth = curTextFont.measureTextWidth(currentChar); + if (currentChar !== "\n" && lineWidth + letterWidth <= width) { + if (spaceChar) spaceMark = charPos; + lineWidth += letterWidth + } else { + if (spaceMark + 1 === start) if (charPos > 0) spaceMark = charPos; + else return; + if (currentChar === "\n") { + drawCommands.push({ + text: str.substring(start, charPos), + width: lineWidth + }); + start = charPos + 1 + } else { + drawCommands.push({ + text: str.substring(start, spaceMark + 1), + width: lineWidth + }); + start = spaceMark + 1 + } + lineWidth = 0; + charPos = start - 1 + } + } + if (start < len) drawCommands.push({ + text: str.substring(start), + width: lineWidth + }); + var xOffset = 1, + yOffset = curTextAscent; + if (horizontalTextAlignment === 3) xOffset = width / 2; + else if (horizontalTextAlignment === 39) xOffset = width; + var linesCount = drawCommands.length, + visibleLines = Math.min(linesCount, Math.floor(height / curTextLeading)); + if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescent; + else if (verticalTextAlignment === 3) yOffset = height / 2 - curTextLeading * (visibleLines / 2 - 1); + else if (verticalTextAlignment === 102) yOffset = curTextDescent + curTextLeading; + var command, drawCommand, leading; + for (command = 0; command < linesCount; command++) { + leading = command * curTextLeading; + if (yOffset + leading > height - curTextDescent) break; + drawCommand = drawCommands[command]; + drawing.text$line(drawCommand.text, x + xOffset, y + yOffset + leading, z, horizontalTextAlignment) + } + } + p.text = function() { + if (textMode === 5) return; + if (arguments.length === 3) text$4(toP5String(arguments[0]), arguments[1], arguments[2], 0); + else if (arguments.length === 4) text$4(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3]); + else if (arguments.length === 5) text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], 0); + else if (arguments.length === 6) text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]) + }; + p.textMode = function(mode) { + textMode = mode + }; + p.loadGlyphs = function(url) { + var x, y, cx, cy, nx, ny, d, a, lastCom, lenC, horiz_adv_x, getXY = "[0-9\\-]+", + path; + var regex = function(needle, hay) { + var i = 0, + results = [], + latest, regexp = new RegExp(needle, "g"); + latest = results[i] = regexp.exec(hay); + while (latest) { + i++; + latest = results[i] = regexp.exec(hay) + } + return results + }; + var buildPath = function(d) { + var c = regex("[A-Za-z][0-9\\- ]+|Z", d); + var beforePathDraw = function() { + saveContext(); + return drawing.$ensureContext() + }; + var afterPathDraw = function() { + executeContextFill(); + executeContextStroke(); + restoreContext() + }; + path = "return {draw:function(){var curContext=beforePathDraw();curContext.beginPath();"; + x = 0; + y = 0; + cx = 0; + cy = 0; + nx = 0; + ny = 0; + d = 0; + a = 0; + lastCom = ""; + lenC = c.length - 1; + for (var j = 0; j < lenC; j++) { + var com = c[j][0], + xy = regex(getXY, com); + switch (com[0]) { + case "M": + x = parseFloat(xy[0][0]); + y = parseFloat(xy[1][0]); + path += "curContext.moveTo(" + x + "," + -y + ");"; + break; + case "L": + x = parseFloat(xy[0][0]); + y = parseFloat(xy[1][0]); + path += "curContext.lineTo(" + x + "," + -y + ");"; + break; + case "H": + x = parseFloat(xy[0][0]); + path += "curContext.lineTo(" + x + "," + -y + ");"; + break; + case "V": + y = parseFloat(xy[0][0]); + path += "curContext.lineTo(" + x + "," + -y + ");"; + break; + case "T": + nx = parseFloat(xy[0][0]); + ny = parseFloat(xy[1][0]); + if (lastCom === "Q" || lastCom === "T") { + d = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(cy - y, 2)); + a = Math.PI + Math.atan2(cx - x, cy - y); + cx = x + Math.sin(a) * d; + cy = y + Math.cos(a) * d + } else { + cx = x; + cy = y + } + path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");"; + x = nx; + y = ny; + break; + case "Q": + cx = parseFloat(xy[0][0]); + cy = parseFloat(xy[1][0]); + nx = parseFloat(xy[2][0]); + ny = parseFloat(xy[3][0]); + path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");"; + x = nx; + y = ny; + break; + case "Z": + path += "curContext.closePath();"; + break + } + lastCom = com[0] + } + path += "afterPathDraw();"; + path += "curContext.translate(" + horiz_adv_x + ",0);"; + path += "}}"; + return (new Function("beforePathDraw", "afterPathDraw", path))(beforePathDraw, afterPathDraw) + }; + var parseSVGFont = function(svg) { + var font = svg.getElementsByTagName("font"); + p.glyphTable[url].horiz_adv_x = font[0].getAttribute("horiz-adv-x"); + var font_face = svg.getElementsByTagName("font-face")[0]; + p.glyphTable[url].units_per_em = parseFloat(font_face.getAttribute("units-per-em")); + p.glyphTable[url].ascent = parseFloat(font_face.getAttribute("ascent")); + p.glyphTable[url].descent = parseFloat(font_face.getAttribute("descent")); + var glyph = svg.getElementsByTagName("glyph"), + len = glyph.length; + for (var i = 0; i < len; i++) { + var unicode = glyph[i].getAttribute("unicode"); + var name = glyph[i].getAttribute("glyph-name"); + horiz_adv_x = glyph[i].getAttribute("horiz-adv-x"); + if (horiz_adv_x === null) horiz_adv_x = p.glyphTable[url].horiz_adv_x; + d = glyph[i].getAttribute("d"); + if (d !== undef) { + path = buildPath(d); + p.glyphTable[url][name] = { + name: name, + unicode: unicode, + horiz_adv_x: horiz_adv_x, + draw: path.draw + } + } + } + }; + var loadXML = function() { + var xmlDoc; + try { + xmlDoc = document.implementation.createDocument("", "", null) + } catch(e_fx_op) { + Processing.debug(e_fx_op.message); + return + } + try { + xmlDoc.async = false; + xmlDoc.load(url); + parseSVGFont(xmlDoc.getElementsByTagName("svg")[0]) + } catch(e_sf_ch) { + Processing.debug(e_sf_ch); + try { + var xmlhttp = new window.XMLHttpRequest; + xmlhttp.open("GET", url, false); + xmlhttp.send(null); + parseSVGFont(xmlhttp.responseXML.documentElement) + } catch(e) { + Processing.debug(e_sf_ch) + } + } + }; + p.glyphTable[url] = {}; + loadXML(url); + return p.glyphTable[url] + }; + p.param = function(name) { + var attributeName = "data-processing-" + name; + if (curElement.hasAttribute(attributeName)) return curElement.getAttribute(attributeName); + for (var i = 0, len = curElement.childNodes.length; i < len; ++i) { + var item = curElement.childNodes.item(i); + if (item.nodeType !== 1 || item.tagName.toLowerCase() !== "param") continue; + if (item.getAttribute("name") === name) return item.getAttribute("value") + } + if (curSketch.params.hasOwnProperty(name)) return curSketch.params[name]; + return null + }; + + function wireDimensionalFunctions(mode) { + if (mode === "3D") drawing = new Drawing3D; + else if (mode === "2D") drawing = new Drawing2D; + else drawing = new DrawingPre; + for (var i in DrawingPre.prototype) if (DrawingPre.prototype.hasOwnProperty(i) && i.indexOf("$") < 0) p[i] = drawing[i]; + drawing.$init() + } + function createDrawingPreFunction(name) { + return function() { + wireDimensionalFunctions("2D"); + return drawing[name].apply(this, arguments) + } + } + DrawingPre.prototype.translate = createDrawingPreFunction("translate"); + DrawingPre.prototype.transform = createDrawingPreFunction("transform"); + DrawingPre.prototype.scale = createDrawingPreFunction("scale"); + DrawingPre.prototype.pushMatrix = createDrawingPreFunction("pushMatrix"); + DrawingPre.prototype.popMatrix = createDrawingPreFunction("popMatrix"); + DrawingPre.prototype.resetMatrix = createDrawingPreFunction("resetMatrix"); + DrawingPre.prototype.applyMatrix = createDrawingPreFunction("applyMatrix"); + DrawingPre.prototype.rotate = createDrawingPreFunction("rotate"); + DrawingPre.prototype.rotateZ = createDrawingPreFunction("rotateZ"); + DrawingPre.prototype.shearX = createDrawingPreFunction("shearX"); + DrawingPre.prototype.shearY = createDrawingPreFunction("shearY"); + DrawingPre.prototype.redraw = createDrawingPreFunction("redraw"); + DrawingPre.prototype.toImageData = createDrawingPreFunction("toImageData"); + DrawingPre.prototype.ambientLight = createDrawingPreFunction("ambientLight"); + DrawingPre.prototype.directionalLight = createDrawingPreFunction("directionalLight"); + DrawingPre.prototype.lightFalloff = createDrawingPreFunction("lightFalloff"); + DrawingPre.prototype.lightSpecular = createDrawingPreFunction("lightSpecular"); + DrawingPre.prototype.pointLight = createDrawingPreFunction("pointLight"); + DrawingPre.prototype.noLights = createDrawingPreFunction("noLights"); + DrawingPre.prototype.spotLight = createDrawingPreFunction("spotLight"); + DrawingPre.prototype.beginCamera = createDrawingPreFunction("beginCamera"); + DrawingPre.prototype.endCamera = createDrawingPreFunction("endCamera"); + DrawingPre.prototype.frustum = createDrawingPreFunction("frustum"); + DrawingPre.prototype.box = createDrawingPreFunction("box"); + DrawingPre.prototype.sphere = createDrawingPreFunction("sphere"); + DrawingPre.prototype.ambient = createDrawingPreFunction("ambient"); + DrawingPre.prototype.emissive = createDrawingPreFunction("emissive"); + DrawingPre.prototype.shininess = createDrawingPreFunction("shininess"); + DrawingPre.prototype.specular = createDrawingPreFunction("specular"); + DrawingPre.prototype.fill = createDrawingPreFunction("fill"); + DrawingPre.prototype.stroke = createDrawingPreFunction("stroke"); + DrawingPre.prototype.strokeWeight = createDrawingPreFunction("strokeWeight"); + DrawingPre.prototype.smooth = createDrawingPreFunction("smooth"); + DrawingPre.prototype.noSmooth = createDrawingPreFunction("noSmooth"); + DrawingPre.prototype.point = createDrawingPreFunction("point"); + DrawingPre.prototype.vertex = createDrawingPreFunction("vertex"); + DrawingPre.prototype.endShape = createDrawingPreFunction("endShape"); + DrawingPre.prototype.bezierVertex = createDrawingPreFunction("bezierVertex"); + DrawingPre.prototype.curveVertex = createDrawingPreFunction("curveVertex"); + DrawingPre.prototype.curve = createDrawingPreFunction("curve"); + DrawingPre.prototype.line = createDrawingPreFunction("line"); + DrawingPre.prototype.bezier = createDrawingPreFunction("bezier"); + DrawingPre.prototype.rect = createDrawingPreFunction("rect"); + DrawingPre.prototype.ellipse = createDrawingPreFunction("ellipse"); + DrawingPre.prototype.background = createDrawingPreFunction("background"); + DrawingPre.prototype.image = createDrawingPreFunction("image"); + DrawingPre.prototype.textWidth = createDrawingPreFunction("textWidth"); + DrawingPre.prototype.text$line = createDrawingPreFunction("text$line"); + DrawingPre.prototype.$ensureContext = createDrawingPreFunction("$ensureContext"); + DrawingPre.prototype.$newPMatrix = createDrawingPreFunction("$newPMatrix"); + DrawingPre.prototype.size = function(aWidth, aHeight, aMode) { + wireDimensionalFunctions(aMode === 2 ? "3D" : "2D"); + p.size(aWidth, aHeight, aMode) + }; + DrawingPre.prototype.$init = nop; + Drawing2D.prototype.$init = function() { + p.size(p.width, p.height); + curContext.lineCap = "round"; + p.noSmooth(); + p.disableContextMenu() + }; + Drawing3D.prototype.$init = function() { + p.use3DContext = true; + p.disableContextMenu() + }; + DrawingShared.prototype.$ensureContext = function() { + return curContext + }; + + function calculateOffset(curElement, event) { + var element = curElement, + offsetX = 0, + offsetY = 0; + p.pmouseX = p.mouseX; + p.pmouseY = p.mouseY; + if (element.offsetParent) { + do { + offsetX += element.offsetLeft; + offsetY += element.offsetTop + } while ( !! (element = element.offsetParent)) + } + element = curElement; + do { + offsetX -= element.scrollLeft || 0; + offsetY -= element.scrollTop || 0 + } while ( !! (element = element.parentNode)); + offsetX += stylePaddingLeft; + offsetY += stylePaddingTop; + offsetX += styleBorderLeft; + offsetY += styleBorderTop; + offsetX += window.pageXOffset; + offsetY += window.pageYOffset; + return { + "X": offsetX, + "Y": offsetY + } + } + function updateMousePosition(curElement, event) { + var offset = calculateOffset(curElement, event); + p.mouseX = event.pageX - offset.X; + p.mouseY = event.pageY - offset.Y + } + function addTouchEventOffset(t) { + var offset = calculateOffset(t.changedTouches[0].target, t.changedTouches[0]), + i; + for (i = 0; i < t.touches.length; i++) { + var touch = t.touches[i]; + touch.offsetX = touch.pageX - offset.X; + touch.offsetY = touch.pageY - offset.Y + } + for (i = 0; i < t.targetTouches.length; i++) { + var targetTouch = t.targetTouches[i]; + targetTouch.offsetX = targetTouch.pageX - offset.X; + targetTouch.offsetY = targetTouch.pageY - offset.Y + } + for (i = 0; i < t.changedTouches.length; i++) { + var changedTouch = t.changedTouches[i]; + changedTouch.offsetX = changedTouch.pageX - offset.X; + changedTouch.offsetY = changedTouch.pageY - offset.Y + } + return t + } + attachEventHandler(curElement, "touchstart", function(t) { + curElement.setAttribute("style", "-webkit-user-select: none"); + curElement.setAttribute("onclick", "void(0)"); + curElement.setAttribute("style", "-webkit-tap-highlight-color:rgba(0,0,0,0)"); + for (var i = 0, ehl = eventHandlers.length; i < ehl; i++) { + var type = eventHandlers[i].type; + if (type === "mouseout" || type === "mousemove" || type === "mousedown" || type === "mouseup" || type === "DOMMouseScroll" || type === "mousewheel" || type === "touchstart") detachEventHandler(eventHandlers[i]) + } + if (p.touchStart !== undef || p.touchMove !== undef || p.touchEnd !== undef || p.touchCancel !== undef) { + attachEventHandler(curElement, "touchstart", function(t) { + if (p.touchStart !== undef) { + t = addTouchEventOffset(t); + p.touchStart(t) + } + }); + attachEventHandler(curElement, "touchmove", function(t) { + if (p.touchMove !== undef) { + t.preventDefault(); + t = addTouchEventOffset(t); + p.touchMove(t) + } + }); + attachEventHandler(curElement, "touchend", function(t) { + if (p.touchEnd !== undef) { + t = addTouchEventOffset(t); + p.touchEnd(t) + } + }); + attachEventHandler(curElement, "touchcancel", function(t) { + if (p.touchCancel !== undef) { + t = addTouchEventOffset(t); + p.touchCancel(t) + } + }) + } else { + attachEventHandler(curElement, "touchstart", function(e) { + updateMousePosition(curElement, e.touches[0]); + p.__mousePressed = true; + p.mouseDragging = false; + p.mouseButton = 37; + if (typeof p.mousePressed === "function") p.mousePressed() + }); + attachEventHandler(curElement, "touchmove", function(e) { + e.preventDefault(); + updateMousePosition(curElement, e.touches[0]); + if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMoved(); + if (typeof p.mouseDragged === "function" && p.__mousePressed) { + p.mouseDragged(); + p.mouseDragging = true + } + }); + attachEventHandler(curElement, "touchend", function(e) { + p.__mousePressed = false; + if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseClicked(); + if (typeof p.mouseReleased === "function") p.mouseReleased() + }) + } + curElement.dispatchEvent(t) + }); + (function() { + var enabled = true, + contextMenu = function(e) { + e.preventDefault(); + e.stopPropagation() + }; + p.disableContextMenu = function() { + if (!enabled) return; + attachEventHandler(curElement, "contextmenu", contextMenu); + enabled = false + }; + p.enableContextMenu = function() { + if (enabled) return; + detachEventHandler({ + elem: curElement, + type: "contextmenu", + fn: contextMenu + }); + enabled = true + } + })(); + attachEventHandler(curElement, "mousemove", function(e) { + updateMousePosition(curElement, e); + if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMoved(); + if (typeof p.mouseDragged === "function" && p.__mousePressed) { + p.mouseDragged(); + p.mouseDragging = true + } + }); + attachEventHandler(curElement, "mouseout", function(e) { + if (typeof p.mouseOut === "function") p.mouseOut() + }); + attachEventHandler(curElement, "mouseover", function(e) { + updateMousePosition(curElement, e); + if (typeof p.mouseOver === "function") p.mouseOver() + }); + curElement.onmousedown = function() { + curElement.focus(); + return false + }; + attachEventHandler(curElement, "mousedown", function(e) { + p.__mousePressed = true; + p.mouseDragging = false; + switch (e.which) { + case 1: + p.mouseButton = 37; + break; + case 2: + p.mouseButton = 3; + break; + case 3: + p.mouseButton = 39; + break + } + if (typeof p.mousePressed === "function") p.mousePressed() + }); + attachEventHandler(curElement, "mouseup", function(e) { + p.__mousePressed = false; + if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseClicked(); + if (typeof p.mouseReleased === "function") p.mouseReleased() + }); + var mouseWheelHandler = function(e) { + var delta = 0; + if (e.wheelDelta) { + delta = e.wheelDelta / 120; + if (window.opera) delta = -delta + } else if (e.detail) delta = -e.detail / 3; + p.mouseScroll = delta; + if (delta && typeof p.mouseScrolled === "function") p.mouseScrolled() + }; + attachEventHandler(document, "DOMMouseScroll", mouseWheelHandler); + attachEventHandler(document, "mousewheel", mouseWheelHandler); + if (!curElement.getAttribute("tabindex")) curElement.setAttribute("tabindex", 0); + + function getKeyCode(e) { + var code = e.which || e.keyCode; + switch (code) { + case 13: + return 10; + case 91: + case 93: + case 224: + return 157; + case 57392: + return 17; + case 46: + return 127; + case 45: + return 155 + } + return code + } + function getKeyChar(e) { + var c = e.which || e.keyCode; + var anyShiftPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey; + switch (c) { + case 13: + c = anyShiftPressed ? 13 : 10; + break; + case 8: + c = anyShiftPressed ? 127 : 8; + break + } + return new Char(c) + } + function suppressKeyEvent(e) { + if (typeof e.preventDefault === "function") e.preventDefault(); + else if (typeof e.stopPropagation === "function") e.stopPropagation(); + return false + } + function updateKeyPressed() { + var ch; + for (ch in pressedKeysMap) if (pressedKeysMap.hasOwnProperty(ch)) { + p.__keyPressed = true; + return + } + p.__keyPressed = false + } + function resetKeyPressed() { + p.__keyPressed = false; + pressedKeysMap = []; + lastPressedKeyCode = null + } + function simulateKeyTyped(code, c) { + pressedKeysMap[code] = c; + lastPressedKeyCode = null; + p.key = c; + p.keyCode = code; + p.keyPressed(); + p.keyCode = 0; + p.keyTyped(); + updateKeyPressed() + } + function handleKeydown(e) { + var code = getKeyCode(e); + if (code === 127) { + simulateKeyTyped(code, new Char(127)); + return + } + if (codedKeys.indexOf(code) < 0) { + lastPressedKeyCode = code; + return + } + var c = new Char(65535); + p.key = c; + p.keyCode = code; + pressedKeysMap[code] = c; + p.keyPressed(); + lastPressedKeyCode = null; + updateKeyPressed(); + return suppressKeyEvent(e) + } + function handleKeypress(e) { + if (lastPressedKeyCode === null) return; + var code = lastPressedKeyCode, + c = getKeyChar(e); + simulateKeyTyped(code, c); + return suppressKeyEvent(e) + } + function handleKeyup(e) { + var code = getKeyCode(e), + c = pressedKeysMap[code]; + if (c === undef) return; + p.key = c; + p.keyCode = code; + p.keyReleased(); + delete pressedKeysMap[code]; + updateKeyPressed() + } + if (!pgraphicsMode) { + if (aCode instanceof Processing.Sketch) curSketch = aCode; + else if (typeof aCode === "function") curSketch = new Processing.Sketch(aCode); + else if (!aCode) curSketch = new Processing.Sketch(function() {}); + else curSketch = Processing.compile(aCode); + p.externals.sketch = curSketch; + wireDimensionalFunctions(); + curElement.onfocus = function() { + p.focused = true + }; + curElement.onblur = function() { + p.focused = false; + if (!curSketch.options.globalKeyEvents) resetKeyPressed() + }; + if (curSketch.options.pauseOnBlur) { + attachEventHandler(window, "focus", function() { + if (doLoop) p.loop() + }); + attachEventHandler(window, "blur", function() { + if (doLoop && loopStarted) { + p.noLoop(); + doLoop = true + } + resetKeyPressed() + }) + } + var keyTrigger = curSketch.options.globalKeyEvents ? window : curElement; + attachEventHandler(keyTrigger, "keydown", handleKeydown); + attachEventHandler(keyTrigger, "keypress", handleKeypress); + attachEventHandler(keyTrigger, "keyup", handleKeyup); + for (var i in Processing.lib) if (Processing.lib.hasOwnProperty(i)) if (Processing.lib[i].hasOwnProperty("attach")) Processing.lib[i].attach(p); + else if (Processing.lib[i] instanceof Function) Processing.lib[i].call(this); + var retryInterval = 100; + var executeSketch = function(processing) { + if (! (curSketch.imageCache.pending || PFont.preloading.pending(retryInterval))) { + if (window.opera) { + var link, element, operaCache = curSketch.imageCache.operaCache; + for (link in operaCache) if (operaCache.hasOwnProperty(link)) { + element = operaCache[link]; + if (element !== null) document.body.removeChild(element); + delete operaCache[link] + } + } + curSketch.attach(processing, defaultScope); + curSketch.onLoad(processing); + if (processing.setup) { + processing.setup(); + processing.resetMatrix(); + curSketch.onSetup() + } + resetContext(); + if (processing.draw) if (!doLoop) processing.redraw(); + else processing.loop() + } else window.setTimeout(function() { + executeSketch(processing) + }, + retryInterval) + }; + addInstance(this); + executeSketch(p) + } else { + curSketch = new Processing.Sketch; + wireDimensionalFunctions(); + p.size = function(w, h, render) { + if (render && render === 2) wireDimensionalFunctions("3D"); + else wireDimensionalFunctions("2D"); + p.size(w, h, render) + } + } + }; + Processing.debug = debug; + Processing.prototype = defaultScope; + + function getGlobalMembers() { + var names = ["abs", "acos", "alpha", "ambient", "ambientLight", "append", + "applyMatrix", "arc", "arrayCopy", "asin", "atan", "atan2", "background", "beginCamera", "beginDraw", "beginShape", "bezier", "bezierDetail", "bezierPoint", "bezierTangent", "bezierVertex", "binary", "blend", "blendColor", "blit_resize", "blue", "box", "breakShape", "brightness", "camera", "ceil", "Character", "color", "colorMode", "concat", "constrain", "copy", "cos", "createFont", "createGraphics", "createImage", "cursor", "curve", "curveDetail", "curvePoint", "curveTangent", "curveTightness", "curveVertex", "day", "degrees", "directionalLight", + "disableContextMenu", "dist", "draw", "ellipse", "ellipseMode", "emissive", "enableContextMenu", "endCamera", "endDraw", "endShape", "exit", "exp", "expand", "externals", "fill", "filter", "floor", "focused", "frameCount", "frameRate", "frustum", "get", "glyphLook", "glyphTable", "green", "height", "hex", "hint", "hour", "hue", "image", "imageMode", "intersect", "join", "key", "keyCode", "keyPressed", "keyReleased", "keyTyped", "lerp", "lerpColor", "lightFalloff", "lights", "lightSpecular", "line", "link", "loadBytes", "loadFont", "loadGlyphs", + "loadImage", "loadPixels", "loadShape", "loadXML", "loadStrings", "log", "loop", "mag", "map", "match", "matchAll", "max", "millis", "min", "minute", "mix", "modelX", "modelY", "modelZ", "modes", "month", "mouseButton", "mouseClicked", "mouseDragged", "mouseMoved", "mouseOut", "mouseOver", "mousePressed", "mouseReleased", "mouseScroll", "mouseScrolled", "mouseX", "mouseY", "name", "nf", "nfc", "nfp", "nfs", "noCursor", "noFill", "noise", "noiseDetail", "noiseSeed", "noLights", "noLoop", "norm", "normal", "noSmooth", "noStroke", "noTint", "ortho", + "param", "parseBoolean", "parseByte", "parseChar", "parseFloat", "parseInt", "peg", "perspective", "PImage", "pixels", "PMatrix2D", "PMatrix3D", "PMatrixStack", "pmouseX", "pmouseY", "point", "pointLight", "popMatrix", "popStyle", "pow", "print", "printCamera", "println", "printMatrix", "printProjection", "PShape", "PShapeSVG", "pushMatrix", "pushStyle", "quad", "radians", "random", "Random", "randomSeed", "rect", "rectMode", "red", "redraw", "requestImage", "resetMatrix", "reverse", "rotate", "rotateX", "rotateY", "rotateZ", "round", "saturation", + "save", "saveFrame", "saveStrings", "scale", "screenX", "screenY", "screenZ", "second", "set", "setup", "shape", "shapeMode", "shared", "shearX", "shearY", "shininess", "shorten", "sin", "size", "smooth", "sort", "specular", "sphere", "sphereDetail", "splice", "split", "splitTokens", "spotLight", "sq", "sqrt", "status", "str", "stroke", "strokeCap", "strokeJoin", "strokeWeight", "subset", "tan", "text", "textAlign", "textAscent", "textDescent", "textFont", "textLeading", "textMode", "textSize", "texture", "textureMode", "textWidth", "tint", "toImageData", + "touchCancel", "touchEnd", "touchMove", "touchStart", "translate", "transform", "triangle", "trim", "unbinary", "unhex", "updatePixels", "use3DContext", "vertex", "width", "XMLElement", "XML", "year", "__contains", "__equals", "__equalsIgnoreCase", "__frameRate", "__hashCode", "__int_cast", "__instanceof", "__keyPressed", "__mousePressed", "__printStackTrace", "__replace", "__replaceAll", "__replaceFirst", "__toCharArray", "__split", "__codePointAt", "__startsWith", "__endsWith", "__matches"]; + var members = {}; + var i, l; + for (i = 0, l = names.length; i < l; ++i) members[names[i]] = null; + for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if (Processing.lib[lib].exports) { + var exportedNames = Processing.lib[lib].exports; + for (i = 0, l = exportedNames.length; i < l; ++i) members[exportedNames[i]] = null + } + return members + } + function parseProcessing(code) { + var globalMembers = getGlobalMembers(); + + function splitToAtoms(code) { + var atoms = []; + var items = code.split(/([\{\[\(\)\]\}])/); + var result = items[0]; + var stack = []; + for (var i = 1; i < items.length; i += 2) { + var item = items[i]; + if (item === "[" || item === "{" || item === "(") { + stack.push(result); + result = item + } else if (item === "]" || item === "}" || item === ")") { + var kind = item === "}" ? "A" : item === ")" ? "B" : "C"; + var index = atoms.length; + atoms.push(result + item); + result = stack.pop() + '"' + kind + (index + 1) + '"' + } + result += items[i + 1] + } + atoms.unshift(result); + return atoms + } + function injectStrings(code, strings) { + return code.replace(/'(\d+)'/g, function(all, index) { + var val = strings[index]; + if (val.charAt(0) === "/") return val; + return /^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/.test(val) ? "(new $p.Character(" + val + "))" : val + }) + } + function trimSpaces(string) { + var m1 = /^\s*/.exec(string), + result; + if (m1[0].length === string.length) result = { + left: m1[0], + middle: "", + right: "" + }; + else { + var m2 = /\s*$/.exec(string); + result = { + left: m1[0], + middle: string.substring(m1[0].length, m2.index), + right: m2[0] + } + } + result.untrim = function(t) { + return this.left + t + this.right + }; + return result + } + function trim(string) { + return string.replace(/^\s+/, "").replace(/\s+$/, "") + } + function appendToLookupTable(table, array) { + for (var i = 0, l = array.length; i < l; ++i) table[array[i]] = null; + return table + } + function isLookupTableEmpty(table) { + for (var i in table) if (table.hasOwnProperty(i)) return false; + return true + } + function getAtomIndex(templ) { + return templ.substring(2, templ.length - 1) + } + var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n"); + var strings = []; + var codeWoStrings = codeWoExtraCr.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g, function(all, quoted, aposed, regexCtx, prefix, regex, singleComment, comment) { + var index; + if (quoted || aposed) { + index = strings.length; + strings.push(all); + return "'" + index + "'" + } + if (regexCtx) { + index = strings.length; + strings.push(regex); + return prefix + "'" + index + "'" + } + return comment !== "" ? " " : "\n" + }); + codeWoStrings = codeWoStrings.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { + return "__x005F_x" + hexCode + }); + codeWoStrings = codeWoStrings.replace(/\$/g, "__x0024"); + var genericsWereRemoved; + var codeWoGenerics = codeWoStrings; + var replaceFunc = function(all, before, types, after) { + if ( !! before || !!after) return all; + genericsWereRemoved = true; + return "" + }; + do { + genericsWereRemoved = false; + codeWoGenerics = codeWoGenerics.replace(/([<]?)<\s*((?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?(?:\s*,\s*(?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?)*)\s*>([=]?)/g, replaceFunc) + } while (genericsWereRemoved); + var atoms = splitToAtoms(codeWoGenerics); + var replaceContext; + var declaredClasses = {}, + currentClassId, classIdSeed = 0; + + function addAtom(text, type) { + var lastIndex = atoms.length; + atoms.push(text); + return '"' + type + lastIndex + '"' + } + function generateClassId() { + return "class" + ++classIdSeed + } + function appendClass(class_, classId, scopeId) { + class_.classId = classId; + class_.scopeId = scopeId; + declaredClasses[classId] = class_ + } + var transformClassBody, transformInterfaceBody, transformStatementsBlock, transformStatements, transformMain, transformExpression; + var classesRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)(class|interface)\s+([A-Za-z_$][\w$]*\b)(\s+extends\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?(\s+implements\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?\s*("A\d+")/g; + var methodsRegex = /\b((?:(?:public|private|final|protected|static|abstract|synchronized)\s+)*)((?!(?:else|new|return|throw|function|public|private|protected)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+"|;)/g; + var fieldTest = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:else|new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*(?:"C\d+"\s*)*([=,]|$)/; + var cstrsRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+")/g; + var attrAndTypeRegex = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*/; + var functionsRegex = /\bfunction(?:\s+([A-Za-z_$][\w$]*))?\s*("B\d+")\s*("A\d+")/g; + + function extractClassesAndMethods(code) { + var s = code; + s = s.replace(classesRegex, function(all) { + return addAtom(all, "E") + }); + s = s.replace(methodsRegex, function(all) { + return addAtom(all, "D") + }); + s = s.replace(functionsRegex, function(all) { + return addAtom(all, "H") + }); + return s + } + function extractConstructors(code, className) { + var result = code.replace(cstrsRegex, function(all, attr, name, params, throws_, body) { + if (name !== className) return all; + return addAtom(all, "G") + }); + return result + } + function AstParam(name) { + this.name = name + } + AstParam.prototype.toString = function() { + return this.name + }; + + function AstParams(params, methodArgsParam) { + this.params = params; + this.methodArgsParam = methodArgsParam + } + AstParams.prototype.getNames = function() { + var names = []; + for (var i = 0, l = this.params.length; i < l; ++i) names.push(this.params[i].name); + return names + }; + AstParams.prototype.prependMethodArgs = function(body) { + if (!this.methodArgsParam) return body; + return "{\nvar " + this.methodArgsParam.name + " = Array.prototype.slice.call(arguments, " + this.params.length + ");\n" + body.substring(1) + }; + AstParams.prototype.toString = function() { + if (this.params.length === 0) return "()"; + var result = "("; + for (var i = 0, l = this.params.length; i < l; ++i) result += this.params[i] + ", "; + return result.substring(0, result.length - 2) + ")" + }; + + function transformParams(params) { + var paramsWoPars = trim(params.substring(1, params.length - 1)); + var result = [], + methodArgsParam = null; + if (paramsWoPars !== "") { + var paramList = paramsWoPars.split(","); + for (var i = 0; i < paramList.length; ++i) { + var param = /\b([A-Za-z_$][\w$]*\b)(\s*"[ABC][\d]*")*\s*$/.exec(paramList[i]); + if (i === paramList.length - 1 && paramList[i].indexOf("...") >= 0) { + methodArgsParam = new AstParam(param[1]); + break + } + result.push(new AstParam(param[1])) + } + } + return new AstParams(result, methodArgsParam) + } + function preExpressionTransform(expr) { + var s = expr; + s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"C\d+")+\s*("A\d+")/g, function(all, type, init) { + return init + }); + s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"B\d+")\s*("A\d+")/g, function(all, type, init) { + return addAtom(all, "F") + }); + s = s.replace(functionsRegex, function(all) { + return addAtom(all, "H") + }); + s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*("C\d+"(?:\s*"C\d+")*)/g, function(all, type, index) { + var args = index.replace(/"C(\d+)"/g, function(all, j) { + return atoms[j] + }).replace(/\[\s*\]/g, "[null]").replace(/\s*\]\s*\[\s*/g, ", "); + var arrayInitializer = "{" + args.substring(1, args.length - 1) + "}"; + var createArrayArgs = "('" + type + "', " + addAtom(arrayInitializer, "A") + ")"; + return "$p.createJavaArray" + addAtom(createArrayArgs, "B") + }); + s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1"); + s = s.replace(/#([0-9A-Fa-f]{6})\b/g, function(all, digits) { + return "0xFF" + digits + }); + s = s.replace(/"B(\d+)"(\s*(?:[\w$']|"B))/g, function(all, index, next) { + var atom = atoms[index]; + if (!/^\(\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\s*(?:"C\d+"\s*)*\)$/.test(atom)) return all; + if (/^\(\s*int\s*\)$/.test(atom)) return "(int)" + next; + var indexParts = atom.split(/"C(\d+)"/g); + if (indexParts.length > 1) if (!/^\[\s*\]$/.test(atoms[indexParts[1]])) return all; + return "" + next + }); + s = s.replace(/\(int\)([^,\]\)\}\?\:\*\+\-\/\^\|\%\&\~<\>\=]+)/g, function(all, arg) { + var trimmed = trimSpaces(arg); + return trimmed.untrim("__int_cast(" + trimmed.middle + ")") + }); + s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s*\.)/g, "$$super$1"); + s = s.replace(/\b0+((\d*)(?:\.[\d*])?(?:[eE][\-\+]?\d+)?[fF]?)\b/, function(all, numberWo0, intPart) { + if (numberWo0 === intPart) return all; + return intPart === "" ? "0" + numberWo0 : numberWo0 + }); + s = s.replace(/\b(\.?\d+\.?)[fF]\b/g, "$1"); + s = s.replace(/([^\s])%([^=\s])/g, "$1 % $2"); + s = s.replace(/\b(frameRate|keyPressed|mousePressed)\b(?!\s*"B)/g, "__$1"); + s = s.replace(/\b(boolean|byte|char|float|int)\s*"B/g, function(all, name) { + return "parse" + name.substring(0, 1).toUpperCase() + name.substring(1) + '"B' + }); + s = s.replace(/\bpixels\b\s*(("C(\d+)")|\.length)?(\s*=(?!=)([^,\]\)\}]+))?/g, function(all, indexOrLength, index, atomIndex, equalsPart, rightSide) { + if (index) { + var atom = atoms[atomIndex]; + if (equalsPart) return "pixels.setPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + "," + rightSide + ")", "B"); + return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + ")", "B") + } + if (indexOrLength) return "pixels.getLength" + addAtom("()", "B"); + if (equalsPart) return "pixels.set" + addAtom("(" + rightSide + ")", "B"); + return "pixels.toArray" + addAtom("()", "B") + }); + var repeatJavaReplacement; + + function replacePrototypeMethods(all, subject, method, atomIndex) { + var atom = atoms[atomIndex]; + repeatJavaReplacement = true; + var trimmed = trimSpaces(atom.substring(1, atom.length - 1)); + return "__" + method + (trimmed.middle === "" ? addAtom("(" + subject.replace(/\.\s*$/, "") + ")", "B") : addAtom("(" + subject.replace(/\.\s*$/, "") + "," + trimmed.middle + ")", "B")) + } + do { + repeatJavaReplacement = false; + s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*\.\s*(?:[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*\.\s*)*)(replace|replaceAll|replaceFirst|contains|equals|equalsIgnoreCase|hashCode|toCharArray|printStackTrace|split|startsWith|endsWith|codePointAt|matches)\s*"B(\d+)"/g, replacePrototypeMethods) + } while (repeatJavaReplacement); + + function replaceInstanceof(all, subject, type) { + repeatJavaReplacement = true; + return "__instanceof" + addAtom("(" + subject + ", " + type + ")", "B") + } + do { + repeatJavaReplacement = false; + s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*(?:\.\s*[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*)*)instanceof\s+([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)/g, replaceInstanceof) + } while (repeatJavaReplacement); + s = s.replace(/\bthis(\s*"B\d+")/g, "$$constr$1"); + return s + } + function AstInlineClass(baseInterfaceName, body) { + this.baseInterfaceName = baseInterfaceName; + this.body = body; + body.owner = this + } + AstInlineClass.prototype.toString = function() { + return "new (" + this.body + ")" + }; + + function transformInlineClass(class_) { + var m = (new RegExp(/\bnew\s*([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)\s*"B\d+"\s*"A(\d+)"/)).exec(class_); + var oldClassId = currentClassId, + newClassId = generateClassId(); + currentClassId = newClassId; + var uniqueClassName = m[1] + "$" + newClassId; + var inlineClass = new AstInlineClass(uniqueClassName, transformClassBody(atoms[m[2]], uniqueClassName, "", "implements " + m[1])); + appendClass(inlineClass, newClassId, oldClassId); + currentClassId = oldClassId; + return inlineClass + } + + function AstFunction(name, params, body) { + this.name = name; + this.params = params; + this.body = body + } + AstFunction.prototype.toString = function() { + var oldContext = replaceContext; + var names = appendToLookupTable({ + "this": null + }, + this.params.getNames()); + replaceContext = function(subject) { + return names.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) + }; + var result = "function"; + if (this.name) result += " " + this.name; + var body = this.params.prependMethodArgs(this.body.toString()); + result += this.params + " " + body; + replaceContext = oldContext; + return result + }; + + function transformFunction(class_) { + var m = (new RegExp(/\b([A-Za-z_$][\w$]*)\s*"B(\d+)"\s*"A(\d+)"/)).exec(class_); + return new AstFunction(m[1] !== "function" ? m[1] : null, transformParams(atoms[m[2]]), transformStatementsBlock(atoms[m[3]])) + } + function AstInlineObject(members) { + this.members = members + } + AstInlineObject.prototype.toString = function() { + var oldContext = replaceContext; + replaceContext = function(subject) { + return subject.name === "this" ? "this" : oldContext(subject) + }; + var result = ""; + for (var i = 0, l = this.members.length; i < l; ++i) { + if (this.members[i].label) result += this.members[i].label + ": "; + result += this.members[i].value.toString() + ", " + } + replaceContext = oldContext; + return result.substring(0, result.length - 2) + }; + + function transformInlineObject(obj) { + var members = obj.split(","); + for (var i = 0; i < members.length; ++i) { + var label = members[i].indexOf(":"); + if (label < 0) members[i] = { + value: transformExpression(members[i]) + }; + else members[i] = { + label: trim(members[i].substring(0, label)), + value: transformExpression(trim(members[i].substring(label + 1))) + } + } + return new AstInlineObject(members) + } + + function expandExpression(expr) { + if (expr.charAt(0) === "(" || expr.charAt(0) === "[") return expr.charAt(0) + expandExpression(expr.substring(1, expr.length - 1)) + expr.charAt(expr.length - 1); + if (expr.charAt(0) === "{") { + if (/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) return "{" + addAtom(expr.substring(1, expr.length - 1), "I") + "}"; + return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]" + } + var trimmed = trimSpaces(expr); + var result = preExpressionTransform(trimmed.middle); + result = result.replace(/"[ABC](\d+)"/g, function(all, index) { + return expandExpression(atoms[index]) + }); + return trimmed.untrim(result) + } + function replaceContextInVars(expr) { + return expr.replace(/(\.\s*)?((?:\b[A-Za-z_]|\$)[\w$]*)(\s*\.\s*([A-Za-z_$][\w$]*)(\s*\()?)?/g, function(all, memberAccessSign, identifier, suffix, subMember, callSign) { + if (memberAccessSign) return all; + var subject = { + name: identifier, + member: subMember, + callSign: !!callSign + }; + return replaceContext(subject) + (suffix === undef ? "" : suffix) + }) + } + function AstExpression(expr, transforms) { + this.expr = expr; + this.transforms = transforms + } + AstExpression.prototype.toString = function() { + var transforms = this.transforms; + var expr = replaceContextInVars(this.expr); + return expr.replace(/"!(\d+)"/g, function(all, index) { + return transforms[index].toString() + }) + }; + transformExpression = function(expr) { + var transforms = []; + var s = expandExpression(expr); + s = s.replace(/"H(\d+)"/g, function(all, index) { + transforms.push(transformFunction(atoms[index])); + return '"!' + (transforms.length - 1) + '"' + }); + s = s.replace(/"F(\d+)"/g, function(all, index) { + transforms.push(transformInlineClass(atoms[index])); + return '"!' + (transforms.length - 1) + '"' + }); + s = s.replace(/"I(\d+)"/g, function(all, index) { + transforms.push(transformInlineObject(atoms[index])); + return '"!' + (transforms.length - 1) + '"' + }); + return new AstExpression(s, transforms) + }; + + function AstVarDefinition(name, value, isDefault) { + this.name = name; + this.value = value; + this.isDefault = isDefault + } + AstVarDefinition.prototype.toString = function() { + return this.name + " = " + this.value + }; + + function transformVarDefinition(def, defaultTypeValue) { + var eqIndex = def.indexOf("="); + var name, value, isDefault; + if (eqIndex < 0) { + name = def; + value = defaultTypeValue; + isDefault = true + } else { + name = def.substring(0, eqIndex); + value = transformExpression(def.substring(eqIndex + 1)); + isDefault = false + } + return new AstVarDefinition(trim(name.replace(/(\s*"C\d+")+/g, "")), value, isDefault) + } + function getDefaultValueForType(type) { + if (type === "int" || type === "float") return "0"; + if (type === "boolean") return "false"; + if (type === "color") return "0x00000000"; + return "null" + } + function AstVar(definitions, varType) { + this.definitions = definitions; + this.varType = varType + } + AstVar.prototype.getNames = function() { + var names = []; + for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.definitions[i].name); + return names + }; + AstVar.prototype.toString = function() { + return "var " + this.definitions.join(",") + }; + + function AstStatement(expression) { + this.expression = expression + } + AstStatement.prototype.toString = function() { + return this.expression.toString() + }; + + function transformStatement(statement) { + if (fieldTest.test(statement)) { + var attrAndType = attrAndTypeRegex.exec(statement); + var definitions = statement.substring(attrAndType[0].length).split(","); + var defaultTypeValue = getDefaultValueForType(attrAndType[2]); + for (var i = 0; i < definitions.length; ++i) definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); + return new AstVar(definitions, attrAndType[2]) + } + return new AstStatement(transformExpression(statement)) + } + function AstForExpression(initStatement, condition, step) { + this.initStatement = initStatement; + this.condition = condition; + this.step = step + } + AstForExpression.prototype.toString = function() { + return "(" + this.initStatement + "; " + this.condition + "; " + this.step + ")" + }; + + function AstForInExpression(initStatement, container) { + this.initStatement = initStatement; + this.container = container + } + AstForInExpression.prototype.toString = function() { + var init = this.initStatement.toString(); + if (init.indexOf("=") >= 0) init = init.substring(0, init.indexOf("=")); + return "(" + init + " in " + this.container + ")" + }; + + function AstForEachExpression(initStatement, container) { + this.initStatement = initStatement; + this.container = container + } + AstForEachExpression.iteratorId = 0; + AstForEachExpression.prototype.toString = function() { + var init = this.initStatement.toString(); + var iterator = "$it" + AstForEachExpression.iteratorId++; + var variableName = init.replace(/^\s*var\s*/, "").split("=")[0]; + var initIteratorAndVariable = "var " + iterator + " = new $p.ObjectIterator(" + this.container + "), " + variableName + " = void(0)"; + var nextIterationCondition = iterator + ".hasNext() && ((" + variableName + " = " + iterator + ".next()) || true)"; + return "(" + initIteratorAndVariable + "; " + nextIterationCondition + ";)" + }; + + function transformForExpression(expr) { + var content; + if (/\bin\b/.test(expr)) { + content = expr.substring(1, expr.length - 1).split(/\bin\b/g); + return new AstForInExpression(transformStatement(trim(content[0])), transformExpression(content[1])) + } + if (expr.indexOf(":") >= 0 && expr.indexOf(";") < 0) { + content = expr.substring(1, expr.length - 1).split(":"); + return new AstForEachExpression(transformStatement(trim(content[0])), transformExpression(content[1])) + } + content = expr.substring(1, expr.length - 1).split(";"); + return new AstForExpression(transformStatement(trim(content[0])), transformExpression(content[1]), transformExpression(content[2])) + } + + function sortByWeight(array) { + array.sort(function(a, b) { + return b.weight - a.weight + }) + } + function AstInnerInterface(name, body, isStatic) { + this.name = name; + this.body = body; + this.isStatic = isStatic; + body.owner = this + } + AstInnerInterface.prototype.toString = function() { + return "" + this.body + }; + + function AstInnerClass(name, body, isStatic) { + this.name = name; + this.body = body; + this.isStatic = isStatic; + body.owner = this + } + AstInnerClass.prototype.toString = function() { + return "" + this.body + }; + + function transformInnerClass(class_) { + var m = classesRegex.exec(class_); + classesRegex.lastIndex = 0; + var isStatic = m[1].indexOf("static") >= 0; + var body = atoms[getAtomIndex(m[6])], + innerClass; + var oldClassId = currentClassId, + newClassId = generateClassId(); + currentClassId = newClassId; + if (m[2] === "interface") innerClass = new AstInnerInterface(m[3], transformInterfaceBody(body, m[3], m[4]), isStatic); + else innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m[4], m[5]), isStatic); + appendClass(innerClass, newClassId, oldClassId); + currentClassId = oldClassId; + return innerClass + } + function AstClassMethod(name, params, body, isStatic) { + this.name = name; + this.params = params; + this.body = body; + this.isStatic = isStatic + } + AstClassMethod.prototype.toString = function() { + var paramNames = appendToLookupTable({}, + this.params.getNames()); + var oldContext = replaceContext; + replaceContext = function(subject) { + return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) + }; + var body = this.params.prependMethodArgs(this.body.toString()); + var result = "function " + this.methodId + this.params + " " + body + "\n"; + replaceContext = oldContext; + return result + }; + + function transformClassMethod(method) { + var m = methodsRegex.exec(method); + methodsRegex.lastIndex = 0; + var isStatic = m[1].indexOf("static") >= 0; + var body = m[6] !== ";" ? atoms[getAtomIndex(m[6])] : "{}"; + return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), transformStatementsBlock(body), isStatic) + } + function AstClassField(definitions, fieldType, isStatic) { + this.definitions = definitions; + this.fieldType = fieldType; + this.isStatic = isStatic + } + AstClassField.prototype.getNames = function() { + var names = []; + for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.definitions[i].name); + return names + }; + AstClassField.prototype.toString = function() { + var thisPrefix = replaceContext({ + name: "[this]" + }); + if (this.isStatic) { + var className = this.owner.name; + var staticDeclarations = []; + for (var i = 0, l = this.definitions.length; i < l; ++i) { + var definition = this.definitions[i]; + var name = definition.name, + staticName = className + "." + name; + var declaration = "if(" + staticName + " === void(0)) {\n" + " " + staticName + " = " + definition.value + "; }\n" + "$p.defineProperty(" + thisPrefix + ", " + "'" + name + "', { get: function(){return " + staticName + ";}, " + "set: function(val){" + staticName + " = val;} });\n"; + staticDeclarations.push(declaration) + } + return staticDeclarations.join("") + } + return thisPrefix + "." + this.definitions.join("; " + thisPrefix + ".") + }; + + function transformClassField(statement) { + var attrAndType = attrAndTypeRegex.exec(statement); + var isStatic = attrAndType[1].indexOf("static") >= 0; + var definitions = statement.substring(attrAndType[0].length).split(/,\s*/g); + var defaultTypeValue = getDefaultValueForType(attrAndType[2]); + for (var i = 0; i < definitions.length; ++i) definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); + return new AstClassField(definitions, attrAndType[2], isStatic) + } + function AstConstructor(params, body) { + this.params = params; + this.body = body + } + AstConstructor.prototype.toString = function() { + var paramNames = appendToLookupTable({}, + this.params.getNames()); + var oldContext = replaceContext; + replaceContext = function(subject) { + return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) + }; + var prefix = "function $constr_" + this.params.params.length + this.params.toString(); + var body = this.params.prependMethodArgs(this.body.toString()); + if (!/\$(superCstr|constr)\b/.test(body)) body = "{\n$superCstr();\n" + body.substring(1); + replaceContext = oldContext; + return prefix + body + "\n" + }; + + function transformConstructor(cstr) { + var m = (new RegExp(/"B(\d+)"\s*"A(\d+)"/)).exec(cstr); + var params = transformParams(atoms[m[1]]); + return new AstConstructor(params, transformStatementsBlock(atoms[m[2]])) + } + function AstInterfaceBody(name, interfacesNames, methodsNames, fields, innerClasses, misc) { + var i, l; + this.name = name; + this.interfacesNames = interfacesNames; + this.methodsNames = methodsNames; + this.fields = fields; + this.innerClasses = innerClasses; + this.misc = misc; + for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this + } + AstInterfaceBody.prototype.getMembers = function(classFields, classMethods, classInners) { + if (this.owner.base) this.owner.base.body.getMembers(classFields, classMethods, classInners); + var i, j, l, m; + for (i = 0, l = this.fields.length; i < l; ++i) { + var fieldNames = this.fields[i].getNames(); + for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j]] = this.fields[i] + } + for (i = 0, l = this.methodsNames.length; i < l; ++i) { + var methodName = this.methodsNames[i]; + classMethods[methodName] = true + } + for (i = 0, l = this.innerClasses.length; i < l; ++i) { + var innerClass = this.innerClasses[i]; + classInners[innerClass.name] = innerClass + } + }; + AstInterfaceBody.prototype.toString = function() { + function getScopeLevel(p) { + var i = 0; + while (p) { + ++i; + p = p.scope + } + return i + } + var scopeLevel = getScopeLevel(this.owner); + var className = this.name; + var staticDefinitions = ""; + var metadata = ""; + var thisClassFields = {}, + thisClassMethods = {}, + thisClassInners = {}; + this.getMembers(thisClassFields, thisClassMethods, thisClassInners); + var i, l, j, m; + if (this.owner.interfaces) { + var resolvedInterfaces = [], + resolvedInterface; + for (i = 0, l = this.interfacesNames.length; i < l; ++i) { + if (!this.owner.interfaces[i]) continue; + resolvedInterface = replaceContext({ + name: this.interfacesNames[i] + }); + resolvedInterfaces.push(resolvedInterface); + staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" + } + metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" + } + metadata += className + ".$isInterface = true;\n"; + metadata += className + ".$methods = ['" + this.methodsNames.join("', '") + "'];\n"; + sortByWeight(this.innerClasses); + for (i = 0, l = this.innerClasses.length; i < l; ++i) { + var innerClass = this.innerClasses[i]; + if (innerClass.isStatic) staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n" + } + for (i = 0, l = this.fields.length; i < l; ++i) { + var field = this.fields[i]; + if (field.isStatic) staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n" + } + return "(function() {\n" + "function " + className + "() { throw 'Unable to create the interface'; }\n" + staticDefinitions + metadata + "return " + className + ";\n" + "})()" + }; + transformInterfaceBody = function(body, name, baseInterfaces) { + var declarations = body.substring(1, body.length - 1); + declarations = extractClassesAndMethods(declarations); + declarations = extractConstructors(declarations, name); + var methodsNames = [], + classes = []; + declarations = declarations.replace(/"([DE])(\d+)"/g, function(all, type, index) { + if (type === "D") methodsNames.push(index); + else if (type === "E") classes.push(index); + return "" + }); + var fields = declarations.split(/;(?:\s*;)*/g); + var baseInterfaceNames; + var i, l; + if (baseInterfaces !== undef) baseInterfaceNames = baseInterfaces.replace(/^\s*extends\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); + for (i = 0, l = methodsNames.length; i < l; ++i) { + var method = transformClassMethod(atoms[methodsNames[i]]); + methodsNames[i] = method.name + } + for (i = 0, l = fields.length - 1; i < l; ++i) { + var field = trimSpaces(fields[i]); + fields[i] = transformClassField(field.middle) + } + var tail = fields.pop(); + for (i = 0, l = classes.length; i < l; ++i) classes[i] = transformInnerClass(atoms[classes[i]]); + return new AstInterfaceBody(name, baseInterfaceNames, methodsNames, fields, classes, { + tail: tail + }) + }; + + function AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, innerClasses, misc) { + var i, l; + this.name = name; + this.baseClassName = baseClassName; + this.interfacesNames = interfacesNames; + this.functions = functions; + this.methods = methods; + this.fields = fields; + this.cstrs = cstrs; + this.innerClasses = innerClasses; + this.misc = misc; + for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this + } + AstClassBody.prototype.getMembers = function(classFields, classMethods, classInners) { + if (this.owner.base) this.owner.base.body.getMembers(classFields, classMethods, classInners); + var i, j, l, m; + for (i = 0, l = this.fields.length; i < l; ++i) { + var fieldNames = this.fields[i].getNames(); + for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j]] = this.fields[i] + } + for (i = 0, l = this.methods.length; i < l; ++i) { + var method = this.methods[i]; + classMethods[method.name] = method + } + for (i = 0, l = this.innerClasses.length; i < l; ++i) { + var innerClass = this.innerClasses[i]; + classInners[innerClass.name] = innerClass + } + }; + AstClassBody.prototype.toString = function() { + function getScopeLevel(p) { + var i = 0; + while (p) { + ++i; + p = p.scope + } + return i + } + var scopeLevel = getScopeLevel(this.owner); + var selfId = "$this_" + scopeLevel; + var className = this.name; + var result = "var " + selfId + " = this;\n"; + var staticDefinitions = ""; + var metadata = ""; + var thisClassFields = {}, + thisClassMethods = {}, + thisClassInners = {}; + this.getMembers(thisClassFields, thisClassMethods, thisClassInners); + var oldContext = replaceContext; + replaceContext = function(subject) { + var name = subject.name; + if (name === "this") return subject.callSign || !subject.member ? selfId + ".$self" : selfId; + if (thisClassFields.hasOwnProperty(name)) return thisClassFields[name].isStatic ? className + "." + name : selfId + "." + name; + if (thisClassInners.hasOwnProperty(name)) return selfId + "." + name; + if (thisClassMethods.hasOwnProperty(name)) return thisClassMethods[name].isStatic ? className + "." + name : selfId + ".$self." + name; + return oldContext(subject) + }; + var resolvedBaseClassName; + if (this.baseClassName) { + resolvedBaseClassName = oldContext({ + name: this.baseClassName + }); + result += "var $super = { $upcast: " + selfId + " };\n"; + result += "function $superCstr(){" + resolvedBaseClassName + ".apply($super,arguments);if(!('$self' in $super)) $p.extendClassChain($super)}\n"; + metadata += className + ".$base = " + resolvedBaseClassName + ";\n" + } else result += "function $superCstr(){$p.extendClassChain(" + selfId + ")}\n"; + if (this.owner.base) staticDefinitions += "$p.extendStaticMembers(" + className + ", " + resolvedBaseClassName + ");\n"; + var i, l, j, m; + if (this.owner.interfaces) { + var resolvedInterfaces = [], + resolvedInterface; + for (i = 0, l = this.interfacesNames.length; i < l; ++i) { + if (!this.owner.interfaces[i]) continue; + resolvedInterface = oldContext({ + name: this.interfacesNames[i] + }); + resolvedInterfaces.push(resolvedInterface); + staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" + } + metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" + } + if (this.functions.length > 0) result += this.functions.join("\n") + "\n"; + sortByWeight(this.innerClasses); + for (i = 0, l = this.innerClasses.length; i < l; ++i) { + var innerClass = this.innerClasses[i]; + if (innerClass.isStatic) { + staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n"; + result += selfId + "." + innerClass.name + " = " + className + "." + innerClass.name + ";\n" + } else result += selfId + "." + innerClass.name + " = " + innerClass + ";\n" + } + for (i = 0, l = this.fields.length; i < l; ++i) { + var field = this.fields[i]; + if (field.isStatic) { + staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n"; + for (j = 0, m = field.definitions.length; j < m; ++j) { + var fieldName = field.definitions[j].name, + staticName = className + "." + fieldName; + result += "$p.defineProperty(" + selfId + ", '" + fieldName + "', {" + "get: function(){return " + staticName + "}, " + "set: function(val){" + staticName + " = val}});\n" + } + } else result += selfId + "." + field.definitions.join(";\n" + selfId + ".") + ";\n" + } + var methodOverloads = {}; + for (i = 0, l = this.methods.length; i < l; ++i) { + var method = this.methods[i]; + var overload = methodOverloads[method.name]; + var methodId = method.name + "$" + method.params.params.length; + var hasMethodArgs = !!method.params.methodArgsParam; + if (overload) { + ++overload; + methodId += "_" + overload + } else overload = 1; + method.methodId = methodId; + methodOverloads[method.name] = overload; + if (method.isStatic) { + staticDefinitions += method; + staticDefinitions += "$p.addMethod(" + className + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; + result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n" + } else { + result += method; + result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n" + } + } + result += trim(this.misc.tail); + if (this.cstrs.length > 0) result += this.cstrs.join("\n") + "\n"; + result += "function $constr() {\n"; + var cstrsIfs = []; + for (i = 0, l = this.cstrs.length; i < l; ++i) { + var paramsLength = this.cstrs[i].params.params.length; + var methodArgsPresent = !!this.cstrs[i].params.methodArgsParam; + cstrsIfs.push("if(arguments.length " + (methodArgsPresent ? ">=" : "===") + " " + paramsLength + ") { " + "$constr_" + paramsLength + ".apply(" + selfId + ", arguments); }") + } + if (cstrsIfs.length > 0) result += cstrsIfs.join(" else ") + " else "; + result += "$superCstr();\n}\n"; + result += "$constr.apply(null, arguments);\n"; + replaceContext = oldContext; + return "(function() {\n" + "function " + className + "() {\n" + result + "}\n" + staticDefinitions + metadata + "return " + className + ";\n" + "})()" + }; + transformClassBody = function(body, name, baseName, interfaces) { + var declarations = body.substring(1, body.length - 1); + declarations = extractClassesAndMethods(declarations); + declarations = extractConstructors(declarations, name); + var methods = [], + classes = [], + cstrs = [], + functions = []; + declarations = declarations.replace(/"([DEGH])(\d+)"/g, function(all, type, index) { + if (type === "D") methods.push(index); + else if (type === "E") classes.push(index); + else if (type === "H") functions.push(index); + else cstrs.push(index); + return "" + }); + var fields = declarations.replace(/^(?:\s*;)+/, "").split(/;(?:\s*;)*/g); + var baseClassName, interfacesNames; + var i; + if (baseName !== undef) baseClassName = baseName.replace(/^\s*extends\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*$/g, "$1"); + if (interfaces !== undef) interfacesNames = interfaces.replace(/^\s*implements\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); + for (i = 0; i < functions.length; ++i) functions[i] = transformFunction(atoms[functions[i]]); + for (i = 0; i < methods.length; ++i) methods[i] = transformClassMethod(atoms[methods[i]]); + for (i = 0; i < fields.length - 1; ++i) { + var field = trimSpaces(fields[i]); + fields[i] = transformClassField(field.middle) + } + var tail = fields.pop(); + for (i = 0; i < cstrs.length; ++i) cstrs[i] = transformConstructor(atoms[cstrs[i]]); + for (i = 0; i < classes.length; ++i) classes[i] = transformInnerClass(atoms[classes[i]]); + return new AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, classes, { + tail: tail + }) + }; + + function AstInterface(name, body) { + this.name = name; + this.body = body; + body.owner = this + } + AstInterface.prototype.toString = function() { + return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" + }; + + function AstClass(name, body) { + this.name = name; + this.body = body; + body.owner = this + } + AstClass.prototype.toString = function() { + return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" + }; + + function transformGlobalClass(class_) { + var m = classesRegex.exec(class_); + classesRegex.lastIndex = 0; + var body = atoms[getAtomIndex(m[6])]; + var oldClassId = currentClassId, + newClassId = generateClassId(); + currentClassId = newClassId; + var globalClass; + if (m[2] === "interface") globalClass = new AstInterface(m[3], transformInterfaceBody(body, m[3], m[4])); + else globalClass = new AstClass(m[3], transformClassBody(body, m[3], m[4], m[5])); + appendClass(globalClass, newClassId, oldClassId); + currentClassId = oldClassId; + return globalClass + } + function AstMethod(name, params, body) { + this.name = name; + this.params = params; + this.body = body + } + AstMethod.prototype.toString = function() { + var paramNames = appendToLookupTable({}, + this.params.getNames()); + var oldContext = replaceContext; + replaceContext = function(subject) { + return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) + }; + var body = this.params.prependMethodArgs(this.body.toString()); + var result = "function " + this.name + this.params + " " + body + "\n" + "$p." + this.name + " = " + this.name + ";"; + replaceContext = oldContext; + return result + }; + + function transformGlobalMethod(method) { + var m = methodsRegex.exec(method); + var result = methodsRegex.lastIndex = 0; + return new AstMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), transformStatementsBlock(atoms[getAtomIndex(m[6])])) + } + function preStatementsTransform(statements) { + var s = statements; + s = s.replace(/\b(catch\s*"B\d+"\s*"A\d+")(\s*catch\s*"B\d+"\s*"A\d+")+/g, "$1"); + return s + } + function AstForStatement(argument, misc) { + this.argument = argument; + this.misc = misc + } + AstForStatement.prototype.toString = function() { + return this.misc.prefix + this.argument.toString() + }; + + function AstCatchStatement(argument, misc) { + this.argument = argument; + this.misc = misc + } + AstCatchStatement.prototype.toString = function() { + return this.misc.prefix + this.argument.toString() + }; + + function AstPrefixStatement(name, argument, misc) { + this.name = name; + this.argument = argument; + this.misc = misc + } + AstPrefixStatement.prototype.toString = function() { + var result = this.misc.prefix; + if (this.argument !== undef) result += this.argument.toString(); + return result + }; + + function AstSwitchCase(expr) { + this.expr = expr + } + AstSwitchCase.prototype.toString = function() { + return "case " + this.expr + ":" + }; + + function AstLabel(label) { + this.label = label + } + AstLabel.prototype.toString = function() { + return this.label + }; + transformStatements = function(statements, transformMethod, transformClass) { + var nextStatement = new RegExp(/\b(catch|for|if|switch|while|with)\s*"B(\d+)"|\b(do|else|finally|return|throw|try|break|continue)\b|("[ADEH](\d+)")|\b(case)\s+([^:]+):|\b([A-Za-z_$][\w$]*\s*:)|(;)/g); + var res = []; + statements = preStatementsTransform(statements); + var lastIndex = 0, + m, space; + while ((m = nextStatement.exec(statements)) !== null) { + if (m[1] !== undef) { + var i = statements.lastIndexOf('"B', nextStatement.lastIndex); + var statementsPrefix = statements.substring(lastIndex, i); + if (m[1] === "for") res.push(new AstForStatement(transformForExpression(atoms[m[2]]), { + prefix: statementsPrefix + })); + else if (m[1] === "catch") res.push(new AstCatchStatement(transformParams(atoms[m[2]]), { + prefix: statementsPrefix + })); + else res.push(new AstPrefixStatement(m[1], transformExpression(atoms[m[2]]), { + prefix: statementsPrefix + })) + } else if (m[3] !== undef) res.push(new AstPrefixStatement(m[3], undef, { + prefix: statements.substring(lastIndex, nextStatement.lastIndex) + })); + else if (m[4] !== undef) { + space = statements.substring(lastIndex, nextStatement.lastIndex - m[4].length); + if (trim(space).length !== 0) continue; + res.push(space); + var kind = m[4].charAt(1), + atomIndex = m[5]; + if (kind === "D") res.push(transformMethod(atoms[atomIndex])); + else if (kind === "E") res.push(transformClass(atoms[atomIndex])); + else if (kind === "H") res.push(transformFunction(atoms[atomIndex])); + else res.push(transformStatementsBlock(atoms[atomIndex])) + } else if (m[6] !== undef) res.push(new AstSwitchCase(transformExpression(trim(m[7])))); + else if (m[8] !== undef) { + space = statements.substring(lastIndex, nextStatement.lastIndex - m[8].length); + if (trim(space).length !== 0) continue; + res.push(new AstLabel(statements.substring(lastIndex, nextStatement.lastIndex))) + } else { + var statement = trimSpaces(statements.substring(lastIndex, nextStatement.lastIndex - 1)); + res.push(statement.left); + res.push(transformStatement(statement.middle)); + res.push(statement.right + ";") + } + lastIndex = nextStatement.lastIndex + } + var statementsTail = trimSpaces(statements.substring(lastIndex)); + res.push(statementsTail.left); + if (statementsTail.middle !== "") { + res.push(transformStatement(statementsTail.middle)); + res.push(";" + statementsTail.right) + } + return res + }; + + function getLocalNames(statements) { + var localNames = []; + for (var i = 0, l = statements.length; i < l; ++i) { + var statement = statements[i]; + if (statement instanceof AstVar) localNames = localNames.concat(statement.getNames()); + else if (statement instanceof AstForStatement && statement.argument.initStatement instanceof AstVar) localNames = localNames.concat(statement.argument.initStatement.getNames()); + else if (statement instanceof AstInnerInterface || statement instanceof AstInnerClass || statement instanceof AstInterface || statement instanceof AstClass || statement instanceof AstMethod || statement instanceof AstFunction) localNames.push(statement.name) + } + return appendToLookupTable({}, + localNames) + } + function AstStatementsBlock(statements) { + this.statements = statements + } + AstStatementsBlock.prototype.toString = function() { + var localNames = getLocalNames(this.statements); + var oldContext = replaceContext; + if (!isLookupTableEmpty(localNames)) replaceContext = function(subject) { + return localNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) + }; + var result = "{\n" + this.statements.join("") + "\n}"; + replaceContext = oldContext; + return result + }; + transformStatementsBlock = function(block) { + var content = trimSpaces(block.substring(1, block.length - 1)); + return new AstStatementsBlock(transformStatements(content.middle)) + }; + + function AstRoot(statements) { + this.statements = statements + } + AstRoot.prototype.toString = function() { + var classes = [], + otherStatements = [], + statement; + for (var i = 0, len = this.statements.length; i < len; ++i) { + statement = this.statements[i]; + if (statement instanceof AstClass || statement instanceof AstInterface) classes.push(statement); + else otherStatements.push(statement) + } + sortByWeight(classes); + var localNames = getLocalNames(this.statements); + replaceContext = function(subject) { + var name = subject.name; + if (localNames.hasOwnProperty(name)) return name; + if (globalMembers.hasOwnProperty(name) || PConstants.hasOwnProperty(name) || defaultScope.hasOwnProperty(name)) return "$p." + name; + return name + }; + var result = "// this code was autogenerated from PJS\n" + "(function($p) {\n" + classes.join("") + "\n" + otherStatements.join("") + "\n})"; + replaceContext = null; + return result + }; + transformMain = function() { + var statements = extractClassesAndMethods(atoms[0]); + statements = statements.replace(/\bimport\s+[^;]+;/g, ""); + return new AstRoot(transformStatements(statements, transformGlobalMethod, transformGlobalClass)) + }; + + function generateMetadata(ast) { + var globalScope = {}; + var id, class_; + for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { + class_ = declaredClasses[id]; + var scopeId = class_.scopeId, + name = class_.name; + if (scopeId) { + var scope = declaredClasses[scopeId]; + class_.scope = scope; + if (scope.inScope === undef) scope.inScope = {}; + scope.inScope[name] = class_ + } else globalScope[name] = class_ + } + function findInScopes(class_, name) { + var parts = name.split("."); + var currentScope = class_.scope, + found; + while (currentScope) { + if (currentScope.hasOwnProperty(parts[0])) { + found = currentScope[parts[0]]; + break + } + currentScope = currentScope.scope + } + if (found === undef) found = globalScope[parts[0]]; + for (var i = 1, l = parts.length; i < l && found; ++i) found = found.inScope[parts[i]]; + return found + } + for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { + class_ = declaredClasses[id]; + var baseClassName = class_.body.baseClassName; + if (baseClassName) { + var parent = findInScopes(class_, baseClassName); + if (parent) { + class_.base = parent; + if (!parent.derived) parent.derived = []; + parent.derived.push(class_) + } + } + var interfacesNames = class_.body.interfacesNames, + interfaces = [], + i, l; + if (interfacesNames && interfacesNames.length > 0) { + for (i = 0, l = interfacesNames.length; i < l; ++i) { + var interface_ = findInScopes(class_, interfacesNames[i]); + interfaces.push(interface_); + if (!interface_) continue; + if (!interface_.derived) interface_.derived = []; + interface_.derived.push(class_) + } + if (interfaces.length > 0) class_.interfaces = interfaces + } + } + } + function setWeight(ast) { + var queue = [], + tocheck = {}; + var id, scopeId, class_; + for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { + class_ = declaredClasses[id]; + if (!class_.inScope && !class_.derived) { + queue.push(id); + class_.weight = 0 + } else { + var dependsOn = []; + if (class_.inScope) for (scopeId in class_.inScope) if (class_.inScope.hasOwnProperty(scopeId)) dependsOn.push(class_.inScope[scopeId]); + if (class_.derived) dependsOn = dependsOn.concat(class_.derived); + tocheck[id] = dependsOn + } + } + function removeDependentAndCheck(targetId, from) { + var dependsOn = tocheck[targetId]; + if (!dependsOn) return false; + var i = dependsOn.indexOf(from); + if (i < 0) return false; + dependsOn.splice(i, 1); + if (dependsOn.length > 0) return false; + delete tocheck[targetId]; + return true + } + while (queue.length > 0) { + id = queue.shift(); + class_ = declaredClasses[id]; + if (class_.scopeId && removeDependentAndCheck(class_.scopeId, class_)) { + queue.push(class_.scopeId); + declaredClasses[class_.scopeId].weight = class_.weight + 1 + } + if (class_.base && removeDependentAndCheck(class_.base.classId, class_)) { + queue.push(class_.base.classId); + class_.base.weight = class_.weight + 1 + } + if (class_.interfaces) { + var i, l; + for (i = 0, l = class_.interfaces.length; i < l; ++i) { + if (!class_.interfaces[i] || !removeDependentAndCheck(class_.interfaces[i].classId, class_)) continue; + queue.push(class_.interfaces[i].classId); + class_.interfaces[i].weight = class_.weight + 1 + } + } + } + } + var transformed = transformMain(); + generateMetadata(transformed); + setWeight(transformed); + var redendered = transformed.toString(); + redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n"); + redendered = redendered.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { + return String.fromCharCode(parseInt(hexCode, 16)) + }); + return injectStrings(redendered, strings) + } + + function preprocessCode(aCode, sketch) { + var dm = (new RegExp(/\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g)).exec(aCode); + if (dm && dm.length === 2) { + var jsonItems = [], + directives = dm.splice(1, 2)[0].replace(/\{([\s\S]*?)\}/g, function() { + return function(all, item) { + jsonItems.push(item); + return "{" + (jsonItems.length - 1) + "}" + } + }()).replace("\n", "").replace("\r", "").split(";"); + var clean = function(s) { + return s.replace(/^\s*["']?/, "").replace(/["']?\s*$/, "") + }; + for (var i = 0, dl = directives.length; i < dl; i++) { + var pair = directives[i].split("="); + if (pair && pair.length === 2) { + var key = clean(pair[0]), + value = clean(pair[1]), + list = []; + if (key === "preload") { + list = value.split(","); + for (var j = 0, jl = list.length; j < jl; j++) { + var imageName = clean(list[j]); + sketch.imageCache.add(imageName) + } + } else if (key === "font") { + list = value.split(","); + for (var x = 0, xl = list.length; x < xl; x++) { + var fontName = clean(list[x]), + index = /^\{(\d*?)\}$/.exec(fontName); + PFont.preloading.add(index ? JSON.parse("{" + jsonItems[index[1]] + "}") : fontName) + } + } else if (key === "pauseOnBlur") sketch.options.pauseOnBlur = value === "true"; + else if (key === "globalKeyEvents") sketch.options.globalKeyEvents = value === "true"; + else if (key.substring(0, 6) === "param-") sketch.params[key.substring(6)] = value; + else sketch.options[key] = value + } + } + } + return aCode + } + Processing.compile = function(pdeCode) { + var sketch = new Processing.Sketch; + var code = preprocessCode(pdeCode, sketch); + var compiledPde = parseProcessing(code); + sketch.sourceCode = compiledPde; + return sketch + }; + var tinylogLite = function() { + var tinylogLite = {}, + undef = "undefined", + func = "function", + False = !1, + True = !0, + logLimit = 512, + log = "log"; + if (typeof tinylog !== undef && typeof tinylog[log] === func) tinylogLite[log] = tinylog[log]; + else if (typeof document !== undef && !document.fake)(function() { + var doc = document, + $div = "div", + $style = "style", + $title = "title", + containerStyles = { + zIndex: 1E4, + position: "fixed", + bottom: "0px", + width: "100%", + height: "15%", + fontFamily: "sans-serif", + color: "#ccc", + backgroundColor: "black" + }, + outputStyles = { + position: "relative", + fontFamily: "monospace", + overflow: "auto", + height: "100%", + paddingTop: "5px" + }, + resizerStyles = { + height: "5px", + marginTop: "-5px", + cursor: "n-resize", + backgroundColor: "darkgrey" + }, + closeButtonStyles = { + position: "absolute", + top: "5px", + right: "20px", + color: "#111", + MozBorderRadius: "4px", + webkitBorderRadius: "4px", + borderRadius: "4px", + cursor: "pointer", + fontWeight: "normal", + textAlign: "center", + padding: "3px 5px", + backgroundColor: "#333", + fontSize: "12px" + }, + entryStyles = { + minHeight: "16px" + }, + entryTextStyles = { + fontSize: "12px", + margin: "0 8px 0 8px", + maxWidth: "100%", + whiteSpace: "pre-wrap", + overflow: "auto" + }, + view = doc.defaultView, + docElem = doc.documentElement, + docElemStyle = docElem[$style], + setStyles = function() { + var i = arguments.length, + elemStyle, styles, style; + while (i--) { + styles = arguments[i--]; + elemStyle = arguments[i][$style]; + for (style in styles) if (styles.hasOwnProperty(style)) elemStyle[style] = styles[style] + } + }, + observer = function(obj, event, handler) { + if (obj.addEventListener) obj.addEventListener(event, handler, False); + else if (obj.attachEvent) obj.attachEvent("on" + event, handler); + return [obj, event, handler] + }, + unobserve = function(obj, event, handler) { + if (obj.removeEventListener) obj.removeEventListener(event, handler, False); + else if (obj.detachEvent) obj.detachEvent("on" + event, handler) + }, + clearChildren = function(node) { + var children = node.childNodes, + child = children.length; + while (child--) node.removeChild(children.item(0)) + }, + append = function(to, elem) { + return to.appendChild(elem) + }, + createElement = function(localName) { + return doc.createElement(localName) + }, + createTextNode = function(text) { + return doc.createTextNode(text) + }, + createLog = tinylogLite[log] = function(message) { + var uninit, originalPadding = docElemStyle.paddingBottom, + container = createElement($div), + containerStyle = container[$style], + resizer = append(container, createElement($div)), + output = append(container, createElement($div)), + closeButton = append(container, createElement($div)), + resizingLog = False, + previousHeight = False, + previousScrollTop = False, + messages = 0, + updateSafetyMargin = function() { + docElemStyle.paddingBottom = container.clientHeight + "px" + }, + setContainerHeight = function(height) { + var viewHeight = view.innerHeight, + resizerHeight = resizer.clientHeight; + if (height < 0) height = 0; + else if (height + resizerHeight > viewHeight) height = viewHeight - resizerHeight; + containerStyle.height = height / viewHeight * 100 + "%"; + updateSafetyMargin() + }, + observers = [observer(doc, "mousemove", function(evt) { + if (resizingLog) { + setContainerHeight(view.innerHeight - evt.clientY); + output.scrollTop = previousScrollTop + } + }), observer(doc, "mouseup", function() { + if (resizingLog) resizingLog = previousScrollTop = False + }), observer(resizer, "dblclick", function(evt) { + evt.preventDefault(); + if (previousHeight) { + setContainerHeight(previousHeight); + previousHeight = False + } else { + previousHeight = container.clientHeight; + containerStyle.height = "0px" + } + }), observer(resizer, "mousedown", function(evt) { + evt.preventDefault(); + resizingLog = True; + previousScrollTop = output.scrollTop + }), observer(resizer, "contextmenu", function() { + resizingLog = False + }), observer(closeButton, "click", function() { + uninit() + })]; + uninit = function() { + var i = observers.length; + while (i--) unobserve.apply(tinylogLite, observers[i]); + docElem.removeChild(container); + docElemStyle.paddingBottom = originalPadding; + clearChildren(output); + clearChildren(container); + tinylogLite[log] = createLog + }; + setStyles(container, containerStyles, output, outputStyles, resizer, resizerStyles, closeButton, closeButtonStyles); + closeButton[$title] = "Close Log"; + append(closeButton, createTextNode("\u2716")); + resizer[$title] = "Double-click to toggle log minimization"; + docElem.insertBefore(container, docElem.firstChild); + tinylogLite[log] = function(message) { + if (messages === logLimit) output.removeChild(output.firstChild); + else messages++; + var entry = append(output, createElement($div)), + entryText = append(entry, createElement($div)); + entry[$title] = (new Date).toLocaleTimeString(); + setStyles(entry, entryStyles, entryText, entryTextStyles); + append(entryText, createTextNode(message)); + output.scrollTop = output.scrollHeight + }; + tinylogLite[log](message); + updateSafetyMargin() + } + })(); + else if (typeof print === func) tinylogLite[log] = print; + return tinylogLite + }(); + Processing.logger = tinylogLite; + Processing.version = "1.4.1"; + Processing.lib = {}; + Processing.registerLibrary = function(name, desc) { + Processing.lib[name] = desc; + if (desc.hasOwnProperty("init")) desc.init(defaultScope) + }; + Processing.instances = processingInstances; + Processing.getInstanceById = function(name) { + return processingInstances[processingInstanceIds[name]] + }; + Processing.Sketch = function(attachFunction) { + this.attachFunction = attachFunction; + this.options = { + pauseOnBlur: false, + globalKeyEvents: false + }; + this.onLoad = nop; + this.onSetup = nop; + this.onPause = nop; + this.onLoop = nop; + this.onFrameStart = nop; + this.onFrameEnd = nop; + this.onExit = nop; + this.params = {}; + this.imageCache = { + pending: 0, + images: {}, + operaCache: {}, + add: function(href, img) { + if (this.images[href]) return; + if (!isDOMPresent) this.images[href] = null; + if (!img) { + img = new Image; + img.onload = function(owner) { + return function() { + owner.pending-- + } + }(this); + this.pending++; + img.src = href + } + this.images[href] = img; + if (window.opera) { + var div = document.createElement("div"); + div.appendChild(img); + div.style.position = "absolute"; + div.style.opacity = 0; + div.style.width = "1px"; + div.style.height = "1px"; + if (!this.operaCache[href]) { + document.body.appendChild(div); + this.operaCache[href] = div + } + } + } + }; + this.sourceCode = undefined; + this.attach = function(processing) { + if (typeof this.attachFunction === "function") this.attachFunction(processing); + else if (this.sourceCode) { + var func = (new Function("return (" + this.sourceCode + ");"))(); + func(processing); + this.attachFunction = func + } else throw "Unable to attach sketch to the processing instance"; + }; + this.toString = function() { + var i; + var code = "((function(Sketch) {\n"; + code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n"; + for (i in this.options) if (this.options.hasOwnProperty(i)) { + var value = this.options[i]; + code += "sketch.options." + i + " = " + (typeof value === "string" ? '"' + value + '"' : "" + value) + ";\n" + } + for (i in this.imageCache) if (this.options.hasOwnProperty(i)) code += 'sketch.imageCache.add("' + i + '");\n'; + code += "return sketch;\n})(Processing.Sketch))"; + return code + } + }; + var loadSketchFromSources = function(canvas, sources) { + var code = [], + errors = [], + sourcesCount = sources.length, + loaded = 0; + + function ajaxAsync(url, callback) { + var xhr = new XMLHttpRequest; + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + var error; + if (xhr.status !== 200 && xhr.status !== 0) error = "Invalid XHR status " + xhr.status; + else if (xhr.responseText === "") if ("withCredentials" in new XMLHttpRequest && (new XMLHttpRequest).withCredentials === false && window.location.protocol === "file:") error = "XMLHttpRequest failure, possibly due to a same-origin policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions."; + else error = "File is empty."; + callback(xhr.responseText, error) + } + }; + xhr.open("GET", url, true); + if (xhr.overrideMimeType) xhr.overrideMimeType("application/json"); + xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); + xhr.send(null) + } + function loadBlock(index, filename) { + function callback(block, error) { + code[index] = block; + ++loaded; + if (error) errors.push(filename + " ==> " + error); + if (loaded === sourcesCount) if (errors.length === 0) try { + return new Processing(canvas, code.join("\n")) + } catch(e) { + throw "Processing.js: Unable to execute pjs sketch: " + e; + } else throw "Processing.js: Unable to load pjs sketch files: " + errors.join("\n"); + } + if (filename.charAt(0) === "#") { + var scriptElement = document.getElementById(filename.substring(1)); + if (scriptElement) callback(scriptElement.text || scriptElement.textContent); + else callback("", "Unable to load pjs sketch: element with id '" + filename.substring(1) + "' was not found"); + return + } + ajaxAsync(filename, callback) + } + for (var i = 0; i < sourcesCount; ++i) loadBlock(i, sources[i]) + }; + var init = function() { + document.removeEventListener("DOMContentLoaded", init, false); + processingInstances = []; + var canvas = document.getElementsByTagName("canvas"), + filenames; + for (var i = 0, l = canvas.length; i < l; i++) { + var processingSources = canvas[i].getAttribute("data-processing-sources"); + if (processingSources === null) { + processingSources = canvas[i].getAttribute("data-src"); + if (processingSources === null) processingSources = canvas[i].getAttribute("datasrc") + } + if (processingSources) { + filenames = processingSources.split(/\s+/g); + for (var j = 0; j < filenames.length;) if (filenames[j]) j++; + else filenames.splice(j, 1); + loadSketchFromSources(canvas[i], filenames) + } + } + var s, last, source, instance, nodelist = document.getElementsByTagName("script"), + scripts = []; + for (s = nodelist.length - 1; s >= 0; s--) scripts.push(nodelist[s]); + for (s = 0, last = scripts.length; s < last; s++) { + var script = scripts[s]; + if (!script.getAttribute) continue; + var type = script.getAttribute("type"); + if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase() === "application/processing")) { + var target = script.getAttribute("data-processing-target"); + canvas = undef; + if (target) canvas = document.getElementById(target); + else { + var nextSibling = script.nextSibling; + while (nextSibling && nextSibling.nodeType !== 1) nextSibling = nextSibling.nextSibling; + if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") canvas = nextSibling + } + if (canvas) { + if (script.getAttribute("src")) { + filenames = script.getAttribute("src").split(/\s+/); + loadSketchFromSources(canvas, filenames); + continue + } + source = script.textContent || script.text; + instance = new Processing(canvas, source) + } + } + } + }; + Processing.reload = function() { + if (processingInstances.length > 0) for (var i = processingInstances.length - 1; i >= 0; i--) if (processingInstances[i]) processingInstances[i].exit(); + init() + }; + Processing.loadSketchFromSources = loadSketchFromSources; + Processing.disableInit = function() { + if (isDOMPresent) document.removeEventListener("DOMContentLoaded", init, false) + }; + if (isDOMPresent) { + window["Processing"] = Processing; + document.addEventListener("DOMContentLoaded", init, false) + } else this.Processing = Processing +})(window, window.document, Math); + diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde index e6db3e3df..f75ac71c9 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree2/Branch.pde @@ -7,7 +7,7 @@ // A class for one branch in the system class Branch { - // Each has a location, velocity, and timer + // Each has a location, velocity, and timer // We could implement this same idea with different data PVector loc; PVector vel; @@ -20,12 +20,12 @@ class Branch { timerstart = n; timer = timerstart; } - + // Move location void update() { loc.add(vel); } - + // Draw a dot at location void render() { fill(0); @@ -33,7 +33,7 @@ class Branch { ellipseMode(CENTER); ellipse(loc.x,loc.y,2,2); } - + // Did the timer run out? boolean timeToBranch() { timer--; @@ -47,7 +47,7 @@ class Branch { // Create a new branch at the current location, but change direction by a given angle Branch branch(float angle) { // What is my current heading - float theta = vel.heading(); + float theta = vel.heading2D(); // What is my current speed float mag = vel.mag(); // Turn me @@ -57,5 +57,5 @@ class Branch { // Return a new Branch return new Branch(loc,newvel,timerstart*0.66f); } - + } diff --git a/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde index 21e494375..7c5e8b9c8 100644 --- a/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde +++ b/java/examples/Books/Nature of Code/chp8_fractals/Tree3/Branch.pde @@ -7,7 +7,7 @@ // A class for one branch in the system class Branch { - // Each has a location, velocity, and timer + // Each has a location, velocity, and timer // We could implement this same idea with different data PVector start; PVector end; @@ -44,7 +44,7 @@ class Branch { if (timer < 0 && growing) { growing = false; return true; - } + } else { return false; } @@ -53,7 +53,7 @@ class Branch { // Create a new branch at the current location, but change direction by a given angle Branch branch(float angle) { // What is my current heading - float theta = vel.heading(); + float theta = vel.heading2D(); // What is my current speed float mag = vel.mag(); // Turn me diff --git a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde index a10c48c5b..7bc8a0524 100644 --- a/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde +++ b/java/examples/Books/Nature of Code/chp9_ga/EvolveFlowField/Rocket.pde @@ -34,7 +34,7 @@ class Rocket { recordDist = width; } - // FITNESS FUNCTION + // FITNESS FUNCTION // distance = distance from target // finish = what order did i finish (first, second, etc. . .) // f(distance,finish) = (1.0f / finish^1.5) * (1.0f / distance^6); @@ -121,7 +121,7 @@ class Rocket { //fill(0,150); //stroke(0); //ellipse(location.x,location.y,r,r); - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(200,100); stroke(0); pushMatrix(); @@ -133,8 +133,8 @@ class Rocket { vertex(r, r*2); endShape(); popMatrix(); - - + + } float getFitness() { diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde index bbfa3af6a..2456856e4 100644 --- a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_02_SmartRockets_superbasic/Rocket.pde @@ -24,7 +24,7 @@ class Rocket { int geneCounter = 0; boolean hitTarget = false; // Did I reach the target - + //constructor Rocket(PVector l, DNA dna_) { acceleration = new PVector(); @@ -58,7 +58,7 @@ class Rocket { float d = dist(location.x, location.y, target.x, target.y); if (d < 12) { hitTarget = true; - } + } } void applyForce(PVector f) { @@ -72,7 +72,7 @@ class Rocket { } void display() { - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(200, 100); stroke(0); pushMatrix(); diff --git a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde index 188cbdcc3..5ce1b313b 100644 --- a/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde +++ b/java/examples/Books/Nature of Code/chp9_ga/NOC_9_03_SmartRockets/Rocket.pde @@ -39,7 +39,7 @@ class Rocket { recordDist = 10000; // Some high number that will be beat instantly } - // FITNESS FUNCTION + // FITNESS FUNCTION // distance = distance from target // finish = what order did i finish (first, second, etc. . .) // f(distance,finish) = (1.0f / finish^1.5) * (1.0f / distance^6); @@ -80,7 +80,7 @@ class Rocket { if (target.contains(location) && !hitTarget) { hitTarget = true; - } + } else if (!hitTarget) { finishTime++; } @@ -108,7 +108,7 @@ class Rocket { void display() { //background(255,0,0); - float theta = velocity.heading() + PI/2; + float theta = velocity.heading2D() + PI/2; fill(200, 100); stroke(0); strokeWeight(1); diff --git a/java/examples/Books/Nature of Code/introduction/NOC_I_4_Gaussian/NOC_I_4_Gaussian.pde b/java/examples/Books/Nature of Code/introduction/NOC_I_4_Gaussian/NOC_I_4_Gaussian.pde index 853a11462..f14120284 100644 --- a/java/examples/Books/Nature of Code/introduction/NOC_I_4_Gaussian/NOC_I_4_Gaussian.pde +++ b/java/examples/Books/Nature of Code/introduction/NOC_I_4_Gaussian/NOC_I_4_Gaussian.pde @@ -2,30 +2,24 @@ // Daniel Shiffman // http://natureofcode.com -// Declare a Random number generator object -Random generator; - void setup() { - size(800, 200); + size(640, 360); background(255); - generator = new Random(); // Initialize generator - smooth(); } void draw() { // Get a gaussian random number w/ mean of 0 and standard deviation of 1.0 - float xloc = (float) generator.nextGaussian(); + float xloc = randomGaussian(); float sd = 60; // Define a standard deviation float mean = width/2; // Define a mean value (middle of the screen along the x-axis) xloc = ( xloc * sd ) + mean; // Scale the gaussian random number by standard deviation and mean - noStroke(); + noStroke(); fill(0, 10); noStroke(); ellipse(xloc, height/2, 16, 16); // Draw an ellipse at our "normal" random location - } diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/NoiseWalk_Many.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/NoiseWalk_Many.pde new file mode 100644 index 000000000..9c37a168a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/NoiseWalk_Many.pde @@ -0,0 +1,35 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker[] w; + +int total = 0; + +void setup() { + size(600, 400); + + w = new Walker[10]; + for (int i = 0; i < w.length; i++) { + w[i] = new Walker(); + } +} + +void draw() { + background(255); + int o = int(map(mouseX,0,width,1,8)); + noiseDetail(o,0.3); + + if (frameCount % 30 == 0) { + total = total + 1; + if (total > w.length-1) { + total = w.length-1; + } + } + + for (int i = 0; i < total; i++) { + w[i].walk(); + w[i].display(); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/Walker.pde b/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/Walker.pde new file mode 100644 index 000000000..19a42fd4a --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/NoiseWalk_Many/Walker.pde @@ -0,0 +1,34 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker class! + +class Walker { + PVector location; + + PVector noff; + + Walker() { + location = new PVector(width/2, height/2); + noff = new PVector(random(1000),random(1000)); + } + + void display() { + strokeWeight(2); + fill(127); + stroke(0); + ellipse(location.x, location.y, 48, 48); + } + + // Randomly move up, down, left, right, or stay in one place + void walk() { + + location.x = map(noise(noff.x),0,1,0,width); + location.y = map(noise(noff.y),0,1,0,height); + + noff.x += 0.01; + noff.y += 0.01; + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/RandomWalkTrailCurve.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/RandomWalkTrailCurve.pde new file mode 100644 index 000000000..763c3db0d --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/RandomWalkTrailCurve.pde @@ -0,0 +1,20 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +Walker w; + +void setup() { + size(400, 300); + // Create a walker object + w = new Walker(); +} + +void draw() { + background(255); + + // Run the walker object + w.step(); + w.render(); +} + diff --git a/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/Walker.pde b/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/Walker.pde new file mode 100644 index 000000000..fc5eba07d --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/RandomWalkTrailCurve/Walker.pde @@ -0,0 +1,42 @@ +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// A random walker object! + +class Walker { + PVector position; + + ArrayList history = new ArrayList(); + + Walker() { + position = new PVector(width/2, height/2); + } + + void render() { + stroke(0); + beginShape(); + for (PVector v : history) { + curveVertex(v.x, v.y); + } + endShape(); + + noFill(); + stroke(0); + ellipse(position.x, position.y, 16, 16); + } + + // Randomly move up, down, left, right, or stay in one place + void step() { + + position.x += random(-10, 10); + position.y += random(-10, 10); + + + position.x = constrain(position.x, 0, width-1); + position.y = constrain(position.y, 0, height-1); + + history.add(position.get()); + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/SelfAvoidingWalk.pde b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/SelfAvoidingWalk.pde new file mode 100644 index 000000000..6e7cbb253 --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/SelfAvoidingWalk.pde @@ -0,0 +1,20 @@ +// Daniel Shiffman +// The Nature of Code +// http://www.shiffman.net/ + +Walker w; + +void setup() { + size(600,400); + // Create a walker object + w = new Walker(); + background(255); +} + +void draw() { + // Run the walker object + w.step(); + w.render(); +} + + diff --git a/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/Walker.pde b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/Walker.pde new file mode 100644 index 000000000..b36cdf45b --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/Walker.pde @@ -0,0 +1,73 @@ +// Daniel Shiffman +// The Nature of Code +// http://www.shiffman.net/ + +// A random walker object! + +class Walker { + int x, y; + + boolean[][] grid; + + Walker() { + x = width/2; + y = height/2; + grid = new boolean[width][height]; + } + + void render() { + stroke(0); + line(x,y,x,y); + } + + // Randomly move up, down, left, right, or stay in one place + void step() { + + boolean ok = false; + + int helpme = 0; + + while (!ok) { + + int choice = int(random(4)); + + int saveX = x; + int saveY = y; + + if (choice == 0) { + x++; + } + else if (choice == 1) { + x--; + } + else if (choice == 2) { + y++; + } + else { + y--; + } + + x = constrain(x, 0, width-1); + y = constrain(y, 0, height-1); + + if (grid[x][y] == false) { + ok = true; + grid[x][y] = true; + } + else { + x = saveX; + y = saveY; + } + + + helpme++; + + if (helpme > 1000) { + println("STUCK"); + noLoop(); + ok = true; + } + } + } +} + diff --git a/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/goal.svg b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/goal.svg new file mode 100644 index 000000000..62563a04d --- /dev/null +++ b/java/examples/Books/Nature of Code/introduction/SelfAvoidingWalk/goal.svg @@ -0,0 +1,2353 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3dcfe7236413c7c86eb2940ae5ca4bec58a9a6b2 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 23:07:34 -0500 Subject: [PATCH 12/25] i love removing smooth() --- .../Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pde | 1 - 1 file changed, 1 deletion(-) diff --git a/java/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pde b/java/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pde index fccdc5658..f56783423 100644 --- a/java/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pde +++ b/java/examples/Topics/Simulate/ForcesWithVectors/ForcesWithVectors.pde @@ -20,7 +20,6 @@ Liquid liquid; void setup() { size(640, 360); - smooth(); reset(); // Create liquid object liquid = new Liquid(0, height/2, width, height/2, 0.1); From 30bc7287c14b38a7ed4f978323c2c5a2776d8f30 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Wed, 6 Mar 2013 23:07:45 -0500 Subject: [PATCH 13/25] removing stray web-export really this time --- .../web-export/NOC_8_05_Koch.pde | 176 - .../NOC_8_05_Koch/web-export/processing.js | 10203 ---------------- 2 files changed, 10379 deletions(-) delete mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde delete mode 100644 java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde deleted file mode 100644 index 63e0a2023..000000000 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/NOC_8_05_Koch.pde +++ /dev/null @@ -1,176 +0,0 @@ -// The Nature of Code -// Daniel Shiffman -// http://natureofcode.com -// Koch Curve - -// Renders a simple fractal, the Koch snowflake -// Each recursive level drawn in sequence - -KochFractal k; - -void setup() { - size(800,250); - background(255); - frameRate(1); // Animate slowly - k = new KochFractal(); - smooth(); -} - -void draw() { - background(255); - // Draws the snowflake! - k.render(); - // Iterate - k.nextLevel(); - // Let's not do it more than 5 times. . . - if (k.getCount() > 5) { - k.restart(); - } -} - -// The Nature of Code -// Daniel Shiffman -// http://natureofcode.com - -// Koch Curve -// A class to manage the list of line segments in the snowflake pattern - -class KochFractal { - PVector start; // A PVector for the start - PVector end; // A PVector for the end - ArrayList lines; // A list to keep track of all the lines - int count; - - public KochFractal() { - start = new PVector(0,height-20); - end = new PVector(width,height-20); - lines = new ArrayList(); - restart(); - } - - void nextLevel() { - // For every line that is in the arraylist - // create 4 more lines in a new arraylist - lines = iterate(lines); - count++; - } - - void restart() { - count = 0; // Reset count - lines.clear(); // Empty the array list - lines.add(new KochLine(start,end)); // Add the initial line (from one end PVector to the other) - } - - int getCount() { - return count; - } - - // This is easy, just draw all the lines - void render() { - for(KochLine l : lines) { - l.display(); - } - } - - // This is where the **MAGIC** happens - // Step 1: Create an empty arraylist - // Step 2: For every line currently in the arraylist - // - calculate 4 line segments based on Koch algorithm - // - add all 4 line segments into the new arraylist - // Step 3: Return the new arraylist and it becomes the list of line segments for the structure - - // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . - ArrayList iterate(ArrayList before) { - ArrayList now = new ArrayList(); // Create emtpy list - for(KochLine l : before) { - // Calculate 5 koch PVectors (done for us by the line object) - PVector a = l.start(); - PVector b = l.kochleft(); - PVector c = l.kochmiddle(); - PVector d = l.kochright(); - PVector e = l.end(); - // Make line segments between all the PVectors and add them - now.add(new KochLine(a,b)); - now.add(new KochLine(b,c)); - now.add(new KochLine(c,d)); - now.add(new KochLine(d,e)); - } - return now; - } - -} -// The Nature of Code -// Daniel Shiffman -// http://natureofcode.com - -// Koch Curve -// A class to describe one line segment in the fractal -// Includes methods to calculate midPVectors along the line according to the Koch algorithm - -class KochLine { - - // Two PVectors, - // a is the "left" PVector and - // b is the "right PVector - PVector a; - PVector b; - - KochLine(PVector start, PVector end) { - a = start.get(); - b = end.get(); - } - - void display() { - stroke(0); - line(a.x, a.y, b.x, b.y); - } - - PVector start() { - return a.get(); - } - - PVector end() { - return b.get(); - } - - // This is easy, just 1/3 of the way - PVector kochleft() { - PVector v = PVector.sub(b, a); - v.div(3); - v.add(a); - return v; - } - - // More complicated, have to use a little trig to figure out where this PVector is! - PVector kochmiddle() { - PVector v = PVector.sub(b, a); - v.div(3); - - PVector p = a.get(); - p.add(v); - - rotate(v,-radians(60)); - p.add(v); - - return p; - } - - - // Easy, just 2/3 of the way - PVector kochright() { - PVector v = PVector.sub(a, b); - v.div(3); - v.add(b); - return v; - } -} - - public void rotate(PVector v, float theta) { - float xTemp = v.x; - // Might need to check for rounding errors like with angleBetween function? - v.x = v.x*cos(theta) - v.y*sin(theta); - v.y = xTemp*sin(theta) + v.y*cos(theta); - } - - - diff --git a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js b/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js deleted file mode 100644 index d9b41d7b1..000000000 --- a/java/examples/Books/Nature of Code/chp8_fractals/NOC_8_05_Koch/web-export/processing.js +++ /dev/null @@ -1,10203 +0,0 @@ -/*** - - P R O C E S S I N G . J S - 1.4.1 - a port of the Processing visualization language - - Processing.js is licensed under the MIT License, see LICENSE. - For a list of copyright holders, please refer to AUTHORS. - - http://processingjs.org - -***/ - -(function(window, document, Math, undef) { - var nop = function() {}; - var debug = function() { - if ("console" in window) return function(msg) { - window.console.log("Processing.js: " + msg) - }; - return nop - }(); - var ajax = function(url) { - var xhr = new XMLHttpRequest; - xhr.open("GET", url, false); - if (xhr.overrideMimeType) xhr.overrideMimeType("text/plain"); - xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); - xhr.send(null); - if (xhr.status !== 200 && xhr.status !== 0) throw "XMLHttpRequest failed, status code " + xhr.status; - return xhr.responseText - }; - var isDOMPresent = "document" in this && !("fake" in this.document); - document.head = document.head || document.getElementsByTagName("head")[0]; - - function setupTypedArray(name, fallback) { - if (name in window) return window[name]; - if (typeof window[fallback] === "function") return window[fallback]; - return function(obj) { - if (obj instanceof Array) return obj; - if (typeof obj === "number") { - var arr = []; - arr.length = obj; - return arr - } - } - } - if (document.documentMode >= 9 && !document.doctype) throw "The doctype directive is missing. The recommended doctype in Internet Explorer is the HTML5 doctype: "; - var Float32Array = setupTypedArray("Float32Array", "WebGLFloatArray"), - Int32Array = setupTypedArray("Int32Array", "WebGLIntArray"), - Uint16Array = setupTypedArray("Uint16Array", "WebGLUnsignedShortArray"), - Uint8Array = setupTypedArray("Uint8Array", "WebGLUnsignedByteArray"); - var PConstants = { - X: 0, - Y: 1, - Z: 2, - R: 3, - G: 4, - B: 5, - A: 6, - U: 7, - V: 8, - NX: 9, - NY: 10, - NZ: 11, - EDGE: 12, - SR: 13, - SG: 14, - SB: 15, - SA: 16, - SW: 17, - TX: 18, - TY: 19, - TZ: 20, - VX: 21, - VY: 22, - VZ: 23, - VW: 24, - AR: 25, - AG: 26, - AB: 27, - DR: 3, - DG: 4, - DB: 5, - DA: 6, - SPR: 28, - SPG: 29, - SPB: 30, - SHINE: 31, - ER: 32, - EG: 33, - EB: 34, - BEEN_LIT: 35, - VERTEX_FIELD_COUNT: 36, - P2D: 1, - JAVA2D: 1, - WEBGL: 2, - P3D: 2, - OPENGL: 2, - PDF: 0, - DXF: 0, - OTHER: 0, - WINDOWS: 1, - MAXOSX: 2, - LINUX: 3, - EPSILON: 1.0E-4, - MAX_FLOAT: 3.4028235E38, - MIN_FLOAT: -3.4028235E38, - MAX_INT: 2147483647, - MIN_INT: -2147483648, - PI: Math.PI, - TWO_PI: 2 * Math.PI, - HALF_PI: Math.PI / 2, - THIRD_PI: Math.PI / 3, - QUARTER_PI: Math.PI / 4, - DEG_TO_RAD: Math.PI / 180, - RAD_TO_DEG: 180 / Math.PI, - WHITESPACE: " \t\n\r\u000c\u00a0", - RGB: 1, - ARGB: 2, - HSB: 3, - ALPHA: 4, - CMYK: 5, - TIFF: 0, - TARGA: 1, - JPEG: 2, - GIF: 3, - BLUR: 11, - GRAY: 12, - INVERT: 13, - OPAQUE: 14, - POSTERIZE: 15, - THRESHOLD: 16, - ERODE: 17, - DILATE: 18, - REPLACE: 0, - BLEND: 1 << 0, - ADD: 1 << 1, - SUBTRACT: 1 << 2, - LIGHTEST: 1 << 3, - DARKEST: 1 << 4, - DIFFERENCE: 1 << 5, - EXCLUSION: 1 << 6, - MULTIPLY: 1 << 7, - SCREEN: 1 << 8, - OVERLAY: 1 << 9, - HARD_LIGHT: 1 << 10, - SOFT_LIGHT: 1 << 11, - DODGE: 1 << 12, - BURN: 1 << 13, - ALPHA_MASK: 4278190080, - RED_MASK: 16711680, - GREEN_MASK: 65280, - BLUE_MASK: 255, - CUSTOM: 0, - ORTHOGRAPHIC: 2, - PERSPECTIVE: 3, - POINT: 2, - POINTS: 2, - LINE: 4, - LINES: 4, - TRIANGLE: 8, - TRIANGLES: 9, - TRIANGLE_STRIP: 10, - TRIANGLE_FAN: 11, - QUAD: 16, - QUADS: 16, - QUAD_STRIP: 17, - POLYGON: 20, - PATH: 21, - RECT: 30, - ELLIPSE: 31, - ARC: 32, - SPHERE: 40, - BOX: 41, - GROUP: 0, - PRIMITIVE: 1, - GEOMETRY: 3, - VERTEX: 0, - BEZIER_VERTEX: 1, - CURVE_VERTEX: 2, - BREAK: 3, - CLOSESHAPE: 4, - OPEN: 1, - CLOSE: 2, - CORNER: 0, - CORNERS: 1, - RADIUS: 2, - CENTER_RADIUS: 2, - CENTER: 3, - DIAMETER: 3, - CENTER_DIAMETER: 3, - BASELINE: 0, - TOP: 101, - BOTTOM: 102, - NORMAL: 1, - NORMALIZED: 1, - IMAGE: 2, - MODEL: 4, - SHAPE: 5, - SQUARE: "butt", - ROUND: "round", - PROJECT: "square", - MITER: "miter", - BEVEL: "bevel", - AMBIENT: 0, - DIRECTIONAL: 1, - SPOT: 3, - BACKSPACE: 8, - TAB: 9, - ENTER: 10, - RETURN: 13, - ESC: 27, - DELETE: 127, - CODED: 65535, - SHIFT: 16, - CONTROL: 17, - ALT: 18, - CAPSLK: 20, - PGUP: 33, - PGDN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - F1: 112, - F2: 113, - F3: 114, - F4: 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - NUMLK: 144, - META: 157, - INSERT: 155, - ARROW: "default", - CROSS: "crosshair", - HAND: "pointer", - MOVE: "move", - TEXT: "text", - WAIT: "wait", - NOCURSOR: "url('data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='), auto", - DISABLE_OPENGL_2X_SMOOTH: 1, - ENABLE_OPENGL_2X_SMOOTH: -1, - ENABLE_OPENGL_4X_SMOOTH: 2, - ENABLE_NATIVE_FONTS: 3, - DISABLE_DEPTH_TEST: 4, - ENABLE_DEPTH_TEST: -4, - ENABLE_DEPTH_SORT: 5, - DISABLE_DEPTH_SORT: -5, - DISABLE_OPENGL_ERROR_REPORT: 6, - ENABLE_OPENGL_ERROR_REPORT: -6, - ENABLE_ACCURATE_TEXTURES: 7, - DISABLE_ACCURATE_TEXTURES: -7, - HINT_COUNT: 10, - SINCOS_LENGTH: 720, - PRECISIONB: 15, - PRECISIONF: 1 << 15, - PREC_MAXVAL: (1 << 15) - 1, - PREC_ALPHA_SHIFT: 24 - 15, - PREC_RED_SHIFT: 16 - 15, - NORMAL_MODE_AUTO: 0, - NORMAL_MODE_SHAPE: 1, - NORMAL_MODE_VERTEX: 2, - MAX_LIGHTS: 8 - }; - - function virtHashCode(obj) { - if (typeof obj === "string") { - var hash = 0; - for (var i = 0; i < obj.length; ++i) hash = hash * 31 + obj.charCodeAt(i) & 4294967295; - return hash - } - if (typeof obj !== "object") return obj & 4294967295; - if (obj.hashCode instanceof Function) return obj.hashCode(); - if (obj.$id === undef) obj.$id = Math.floor(Math.random() * 65536) - 32768 << 16 | Math.floor(Math.random() * 65536); - return obj.$id - } - function virtEquals(obj, other) { - if (obj === null || other === null) return obj === null && other === null; - if (typeof obj === "string") return obj === other; - if (typeof obj !== "object") return obj === other; - if (obj.equals instanceof Function) return obj.equals(other); - return obj === other - } - var ObjectIterator = function(obj) { - if (obj.iterator instanceof - Function) return obj.iterator(); - if (obj instanceof Array) { - var index = -1; - this.hasNext = function() { - return ++index < obj.length - }; - this.next = function() { - return obj[index] - } - } else throw "Unable to iterate: " + obj; - }; - var ArrayList = function() { - function Iterator(array) { - var index = 0; - this.hasNext = function() { - return index < array.length - }; - this.next = function() { - return array[index++] - }; - this.remove = function() { - array.splice(index, 1) - } - } - function ArrayList(a) { - var array; - if (a instanceof ArrayList) array = a.toArray(); - else { - array = []; - if (typeof a === "number") array.length = a > 0 ? a : 0 - } - this.get = function(i) { - return array[i] - }; - this.contains = function(item) { - return this.indexOf(item) > -1 - }; - this.indexOf = function(item) { - for (var i = 0, len = array.length; i < len; ++i) if (virtEquals(item, array[i])) return i; - return -1 - }; - this.lastIndexOf = function(item) { - for (var i = array.length - 1; i >= 0; --i) if (virtEquals(item, array[i])) return i; - return -1 - }; - this.add = function() { - if (arguments.length === 1) array.push(arguments[0]); - else if (arguments.length === 2) { - var arg0 = arguments[0]; - if (typeof arg0 === "number") if (arg0 >= 0 && arg0 <= array.length) array.splice(arg0, 0, arguments[1]); - else throw arg0 + " is not a valid index"; - else throw typeof arg0 + " is not a number"; - } else throw "Please use the proper number of parameters."; - }; - this.addAll = function(arg1, arg2) { - var it; - if (typeof arg1 === "number") { - if (arg1 < 0 || arg1 > array.length) throw "Index out of bounds for addAll: " + arg1 + " greater or equal than " + array.length; - it = new ObjectIterator(arg2); - while (it.hasNext()) array.splice(arg1++, 0, it.next()) - } else { - it = new ObjectIterator(arg1); - while (it.hasNext()) array.push(it.next()) - } - }; - this.set = function() { - if (arguments.length === 2) { - var arg0 = arguments[0]; - if (typeof arg0 === "number") if (arg0 >= 0 && arg0 < array.length) array.splice(arg0, 1, arguments[1]); - else throw arg0 + " is not a valid index."; - else throw typeof arg0 + " is not a number"; - } else throw "Please use the proper number of parameters."; - }; - this.size = function() { - return array.length - }; - this.clear = function() { - array.length = 0 - }; - this.remove = function(item) { - if (typeof item === "number") return array.splice(item, 1)[0]; - item = this.indexOf(item); - if (item > -1) { - array.splice(item, 1); - return true - } - return false - }; - this.removeAll = function(c) { - var i, x, item, newList = new ArrayList; - newList.addAll(this); - this.clear(); - for (i = 0, x = 0; i < newList.size(); i++) { - item = newList.get(i); - if (!c.contains(item)) this.add(x++, item) - } - if (this.size() < newList.size()) return true; - return false - }; - this.isEmpty = function() { - return !array.length - }; - this.clone = function() { - return new ArrayList(this) - }; - this.toArray = function() { - return array.slice(0) - }; - this.iterator = function() { - return new Iterator(array) - } - } - return ArrayList - }(); - var HashMap = function() { - function HashMap() { - if (arguments.length === 1 && arguments[0] instanceof HashMap) return arguments[0].clone(); - var initialCapacity = arguments.length > 0 ? arguments[0] : 16; - var loadFactor = arguments.length > 1 ? arguments[1] : 0.75; - var buckets = []; - buckets.length = initialCapacity; - var count = 0; - var hashMap = this; - - function getBucketIndex(key) { - var index = virtHashCode(key) % buckets.length; - return index < 0 ? buckets.length + index : index - } - function ensureLoad() { - if (count <= loadFactor * buckets.length) return; - var allEntries = []; - for (var i = 0; i < buckets.length; ++i) if (buckets[i] !== undef) allEntries = allEntries.concat(buckets[i]); - var newBucketsLength = buckets.length * 2; - buckets = []; - buckets.length = newBucketsLength; - for (var j = 0; j < allEntries.length; ++j) { - var index = getBucketIndex(allEntries[j].key); - var bucket = buckets[index]; - if (bucket === undef) buckets[index] = bucket = []; - bucket.push(allEntries[j]) - } - } - function Iterator(conversion, removeItem) { - var bucketIndex = 0; - var itemIndex = -1; - var endOfBuckets = false; - var currentItem; - - function findNext() { - while (!endOfBuckets) { - ++itemIndex; - if (bucketIndex >= buckets.length) endOfBuckets = true; - else if (buckets[bucketIndex] === undef || itemIndex >= buckets[bucketIndex].length) { - itemIndex = -1; - ++bucketIndex - } else return - } - } - this.hasNext = function() { - return !endOfBuckets - }; - this.next = function() { - currentItem = conversion(buckets[bucketIndex][itemIndex]); - findNext(); - return currentItem - }; - this.remove = function() { - if (currentItem !== undef) { - removeItem(currentItem); - --itemIndex; - findNext() - } - }; - findNext() - } - function Set(conversion, isIn, removeItem) { - this.clear = function() { - hashMap.clear() - }; - this.contains = function(o) { - return isIn(o) - }; - this.containsAll = function(o) { - var it = o.iterator(); - while (it.hasNext()) if (!this.contains(it.next())) return false; - return true - }; - this.isEmpty = function() { - return hashMap.isEmpty() - }; - this.iterator = function() { - return new Iterator(conversion, removeItem) - }; - this.remove = function(o) { - if (this.contains(o)) { - removeItem(o); - return true - } - return false - }; - this.removeAll = function(c) { - var it = c.iterator(); - var changed = false; - while (it.hasNext()) { - var item = it.next(); - if (this.contains(item)) { - removeItem(item); - changed = true - } - } - return true - }; - this.retainAll = function(c) { - var it = this.iterator(); - var toRemove = []; - while (it.hasNext()) { - var entry = it.next(); - if (!c.contains(entry)) toRemove.push(entry) - } - for (var i = 0; i < toRemove.length; ++i) removeItem(toRemove[i]); - return toRemove.length > 0 - }; - this.size = function() { - return hashMap.size() - }; - this.toArray = function() { - var result = []; - var it = this.iterator(); - while (it.hasNext()) result.push(it.next()); - return result - } - } - function Entry(pair) { - this._isIn = function(map) { - return map === hashMap && pair.removed === undef - }; - this.equals = function(o) { - return virtEquals(pair.key, o.getKey()) - }; - this.getKey = function() { - return pair.key - }; - this.getValue = function() { - return pair.value - }; - this.hashCode = function(o) { - return virtHashCode(pair.key) - }; - this.setValue = function(value) { - var old = pair.value; - pair.value = value; - return old - } - } - this.clear = function() { - count = 0; - buckets = []; - buckets.length = initialCapacity - }; - this.clone = function() { - var map = new HashMap; - map.putAll(this); - return map - }; - this.containsKey = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undef) return false; - for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) return true; - return false - }; - this.containsValue = function(value) { - for (var i = 0; i < buckets.length; ++i) { - var bucket = buckets[i]; - if (bucket === undef) continue; - for (var j = 0; j < bucket.length; ++j) if (virtEquals(bucket[j].value, value)) return true - } - return false - }; - this.entrySet = function() { - return new Set(function(pair) { - return new Entry(pair) - }, - - - function(pair) { - return pair instanceof Entry && pair._isIn(hashMap) - }, - - - function(pair) { - return hashMap.remove(pair.getKey()) - }) - }; - this.get = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undef) return null; - for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) return bucket[i].value; - return null - }; - this.isEmpty = function() { - return count === 0 - }; - this.keySet = function() { - return new Set(function(pair) { - return pair.key - }, - - - function(key) { - return hashMap.containsKey(key) - }, - - - function(key) { - return hashMap.remove(key) - }) - }; - this.values = function() { - return new Set(function(pair) { - return pair.value - }, - - - function(value) { - return hashMap.containsValue(value) - }, - - function(value) { - return hashMap.removeByValue(value) - }) - }; - this.put = function(key, value) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undef) { - ++count; - buckets[index] = [{ - key: key, - value: value - }]; - ensureLoad(); - return null - } - for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) { - var previous = bucket[i].value; - bucket[i].value = value; - return previous - }++count; - bucket.push({ - key: key, - value: value - }); - ensureLoad(); - return null - }; - this.putAll = function(m) { - var it = m.entrySet().iterator(); - while (it.hasNext()) { - var entry = it.next(); - this.put(entry.getKey(), entry.getValue()) - } - }; - this.remove = function(key) { - var index = getBucketIndex(key); - var bucket = buckets[index]; - if (bucket === undef) return null; - for (var i = 0; i < bucket.length; ++i) if (virtEquals(bucket[i].key, key)) { - --count; - var previous = bucket[i].value; - bucket[i].removed = true; - if (bucket.length > 1) bucket.splice(i, 1); - else buckets[index] = undef; - return previous - } - return null - }; - this.removeByValue = function(value) { - var bucket, i, ilen, pair; - for (bucket in buckets) if (buckets.hasOwnProperty(bucket)) for (i = 0, ilen = buckets[bucket].length; i < ilen; i++) { - pair = buckets[bucket][i]; - if (pair.value === value) { - buckets[bucket].splice(i, 1); - return true - } - } - return false - }; - this.size = function() { - return count - } - } - return HashMap - }(); - var PVector = function() { - function PVector(x, y, z) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0 - } - PVector.dist = function(v1, v2) { - return v1.dist(v2) - }; - PVector.dot = function(v1, v2) { - return v1.dot(v2) - }; - PVector.cross = function(v1, v2) { - return v1.cross(v2) - }; - PVector.angleBetween = function(v1, v2) { - return Math.acos(v1.dot(v2) / (v1.mag() * v2.mag())) - }; - PVector.prototype = { - set: function(v, y, z) { - if (arguments.length === 1) this.set(v.x || v[0] || 0, v.y || v[1] || 0, v.z || v[2] || 0); - else { - this.x = v; - this.y = y; - this.z = z - } - }, - get: function() { - return new PVector(this.x, this.y, this.z) - }, - mag: function() { - var x = this.x, - y = this.y, - z = this.z; - return Math.sqrt(x * x + y * y + z * z) - }, - add: function(v, y, z) { - if (arguments.length === 1) { - this.x += v.x; - this.y += v.y; - this.z += v.z - } else { - this.x += v; - this.y += y; - this.z += z - } - }, - sub: function(v, y, z) { - if (arguments.length === 1) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z - } else { - this.x -= v; - this.y -= y; - this.z -= z - } - }, - mult: function(v) { - if (typeof v === "number") { - this.x *= v; - this.y *= v; - this.z *= v - } else { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z - } - }, - div: function(v) { - if (typeof v === "number") { - this.x /= v; - this.y /= v; - this.z /= v - } else { - this.x /= v.x; - this.y /= v.y; - this.z /= v.z - } - }, - dist: function(v) { - var dx = this.x - v.x, - dy = this.y - v.y, - dz = this.z - v.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz) - }, - dot: function(v, y, z) { - if (arguments.length === 1) return this.x * v.x + this.y * v.y + this.z * v.z; - return this.x * v + this.y * y + this.z * z - }, - cross: function(v) { - var x = this.x, - y = this.y, - z = this.z; - return new PVector(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y) - }, - normalize: function() { - var m = this.mag(); - if (m > 0) this.div(m) - }, - limit: function(high) { - if (this.mag() > high) { - this.normalize(); - this.mult(high) - } - }, - heading2D: function() { - return -Math.atan2(-this.y, this.x) - }, - toString: function() { - return "[" + this.x + ", " + this.y + ", " + this.z + "]" - }, - array: function() { - return [this.x, this.y, this.z] - } - }; - - function createPVectorMethod(method) { - return function(v1, v2) { - var v = v1.get(); - v[method](v2); - return v - } - } - for (var method in PVector.prototype) if (PVector.prototype.hasOwnProperty(method) && !PVector.hasOwnProperty(method)) PVector[method] = createPVectorMethod(method); - return PVector - }(); - - function DefaultScope() {} - DefaultScope.prototype = PConstants; - var defaultScope = new DefaultScope; - defaultScope.ArrayList = ArrayList; - defaultScope.HashMap = HashMap; - defaultScope.PVector = PVector; - defaultScope.ObjectIterator = ObjectIterator; - defaultScope.PConstants = PConstants; - defaultScope.defineProperty = function(obj, name, desc) { - if ("defineProperty" in Object) Object.defineProperty(obj, name, desc); - else { - if (desc.hasOwnProperty("get")) obj.__defineGetter__(name, desc.get); - if (desc.hasOwnProperty("set")) obj.__defineSetter__(name, desc.set) - } - }; - - function overloadBaseClassFunction(object, name, basefn) { - if (!object.hasOwnProperty(name) || typeof object[name] !== "function") { - object[name] = basefn; - return - } - var fn = object[name]; - if ("$overloads" in fn) { - fn.$defaultOverload = basefn; - return - } - if (! ("$overloads" in basefn) && fn.length === basefn.length) return; - var overloads, defaultOverload; - if ("$overloads" in basefn) { - overloads = basefn.$overloads.slice(0); - overloads[fn.length] = fn; - defaultOverload = basefn.$defaultOverload - } else { - overloads = []; - overloads[basefn.length] = basefn; - overloads[fn.length] = fn; - defaultOverload = fn - } - var hubfn = function() { - var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$methodArgsIndex] : null) || hubfn.$defaultOverload; - return fn.apply(this, arguments) - }; - hubfn.$overloads = overloads; - if ("$methodArgsIndex" in basefn) hubfn.$methodArgsIndex = basefn.$methodArgsIndex; - hubfn.$defaultOverload = defaultOverload; - hubfn.name = name; - object[name] = hubfn - } - function extendClass(subClass, baseClass) { - function extendGetterSetter(propertyName) { - defaultScope.defineProperty(subClass, propertyName, { - get: function() { - return baseClass[propertyName] - }, - set: function(v) { - baseClass[propertyName] = v - }, - enumerable: true - }) - } - var properties = []; - for (var propertyName in baseClass) if (typeof baseClass[propertyName] === "function") overloadBaseClassFunction(subClass, propertyName, baseClass[propertyName]); - else if (propertyName.charAt(0) !== "$" && !(propertyName in subClass)) properties.push(propertyName); - while (properties.length > 0) extendGetterSetter(properties.shift()); - subClass.$super = baseClass - } - defaultScope.extendClassChain = function(base) { - var path = [base]; - for (var self = base.$upcast; self; self = self.$upcast) { - extendClass(self, base); - path.push(self); - base = self - } - while (path.length > 0) path.pop().$self = base - }; - defaultScope.extendStaticMembers = function(derived, base) { - extendClass(derived, base) - }; - defaultScope.extendInterfaceMembers = function(derived, base) { - extendClass(derived, base) - }; - defaultScope.addMethod = function(object, name, fn, hasMethodArgs) { - var existingfn = object[name]; - if (existingfn || hasMethodArgs) { - var args = fn.length; - if ("$overloads" in existingfn) existingfn.$overloads[args] = fn; - else { - var hubfn = function() { - var fn = hubfn.$overloads[arguments.length] || ("$methodArgsIndex" in hubfn && arguments.length > hubfn.$methodArgsIndex ? hubfn.$overloads[hubfn.$methodArgsIndex] : null) || hubfn.$defaultOverload; - return fn.apply(this, arguments) - }; - var overloads = []; - if (existingfn) overloads[existingfn.length] = existingfn; - overloads[args] = fn; - hubfn.$overloads = overloads; - hubfn.$defaultOverload = existingfn || fn; - if (hasMethodArgs) hubfn.$methodArgsIndex = args; - hubfn.name = name; - object[name] = hubfn - } - } else object[name] = fn - }; - - function isNumericalJavaType(type) { - if (typeof type !== "string") return false; - return ["byte", "int", "char", "color", "float", "long", "double"].indexOf(type) !== -1 - } - defaultScope.createJavaArray = function(type, bounds) { - var result = null, - defaultValue = null; - if (typeof type === "string") if (type === "boolean") defaultValue = false; - else if (isNumericalJavaType(type)) defaultValue = 0; - if (typeof bounds[0] === "number") { - var itemsCount = 0 | bounds[0]; - if (bounds.length <= 1) { - result = []; - result.length = itemsCount; - for (var i = 0; i < itemsCount; ++i) result[i] = defaultValue - } else { - result = []; - var newBounds = bounds.slice(1); - for (var j = 0; j < itemsCount; ++j) result.push(defaultScope.createJavaArray(type, newBounds)) - } - } - return result - }; - var colors = { - aliceblue: "#f0f8ff", - antiquewhite: "#faebd7", - aqua: "#00ffff", - aquamarine: "#7fffd4", - azure: "#f0ffff", - beige: "#f5f5dc", - bisque: "#ffe4c4", - black: "#000000", - blanchedalmond: "#ffebcd", - blue: "#0000ff", - blueviolet: "#8a2be2", - brown: "#a52a2a", - burlywood: "#deb887", - cadetblue: "#5f9ea0", - chartreuse: "#7fff00", - chocolate: "#d2691e", - coral: "#ff7f50", - cornflowerblue: "#6495ed", - cornsilk: "#fff8dc", - crimson: "#dc143c", - cyan: "#00ffff", - darkblue: "#00008b", - darkcyan: "#008b8b", - darkgoldenrod: "#b8860b", - darkgray: "#a9a9a9", - darkgreen: "#006400", - darkkhaki: "#bdb76b", - darkmagenta: "#8b008b", - darkolivegreen: "#556b2f", - darkorange: "#ff8c00", - darkorchid: "#9932cc", - darkred: "#8b0000", - darksalmon: "#e9967a", - darkseagreen: "#8fbc8f", - darkslateblue: "#483d8b", - darkslategray: "#2f4f4f", - darkturquoise: "#00ced1", - darkviolet: "#9400d3", - deeppink: "#ff1493", - deepskyblue: "#00bfff", - dimgray: "#696969", - dodgerblue: "#1e90ff", - firebrick: "#b22222", - floralwhite: "#fffaf0", - forestgreen: "#228b22", - fuchsia: "#ff00ff", - gainsboro: "#dcdcdc", - ghostwhite: "#f8f8ff", - gold: "#ffd700", - goldenrod: "#daa520", - gray: "#808080", - green: "#008000", - greenyellow: "#adff2f", - honeydew: "#f0fff0", - hotpink: "#ff69b4", - indianred: "#cd5c5c", - indigo: "#4b0082", - ivory: "#fffff0", - khaki: "#f0e68c", - lavender: "#e6e6fa", - lavenderblush: "#fff0f5", - lawngreen: "#7cfc00", - lemonchiffon: "#fffacd", - lightblue: "#add8e6", - lightcoral: "#f08080", - lightcyan: "#e0ffff", - lightgoldenrodyellow: "#fafad2", - lightgrey: "#d3d3d3", - lightgreen: "#90ee90", - lightpink: "#ffb6c1", - lightsalmon: "#ffa07a", - lightseagreen: "#20b2aa", - lightskyblue: "#87cefa", - lightslategray: "#778899", - lightsteelblue: "#b0c4de", - lightyellow: "#ffffe0", - lime: "#00ff00", - limegreen: "#32cd32", - linen: "#faf0e6", - magenta: "#ff00ff", - maroon: "#800000", - mediumaquamarine: "#66cdaa", - mediumblue: "#0000cd", - mediumorchid: "#ba55d3", - mediumpurple: "#9370d8", - mediumseagreen: "#3cb371", - mediumslateblue: "#7b68ee", - mediumspringgreen: "#00fa9a", - mediumturquoise: "#48d1cc", - mediumvioletred: "#c71585", - midnightblue: "#191970", - mintcream: "#f5fffa", - mistyrose: "#ffe4e1", - moccasin: "#ffe4b5", - navajowhite: "#ffdead", - navy: "#000080", - oldlace: "#fdf5e6", - olive: "#808000", - olivedrab: "#6b8e23", - orange: "#ffa500", - orangered: "#ff4500", - orchid: "#da70d6", - palegoldenrod: "#eee8aa", - palegreen: "#98fb98", - paleturquoise: "#afeeee", - palevioletred: "#d87093", - papayawhip: "#ffefd5", - peachpuff: "#ffdab9", - peru: "#cd853f", - pink: "#ffc0cb", - plum: "#dda0dd", - powderblue: "#b0e0e6", - purple: "#800080", - red: "#ff0000", - rosybrown: "#bc8f8f", - royalblue: "#4169e1", - saddlebrown: "#8b4513", - salmon: "#fa8072", - sandybrown: "#f4a460", - seagreen: "#2e8b57", - seashell: "#fff5ee", - sienna: "#a0522d", - silver: "#c0c0c0", - skyblue: "#87ceeb", - slateblue: "#6a5acd", - slategray: "#708090", - snow: "#fffafa", - springgreen: "#00ff7f", - steelblue: "#4682b4", - tan: "#d2b48c", - teal: "#008080", - thistle: "#d8bfd8", - tomato: "#ff6347", - turquoise: "#40e0d0", - violet: "#ee82ee", - wheat: "#f5deb3", - white: "#ffffff", - whitesmoke: "#f5f5f5", - yellow: "#ffff00", - yellowgreen: "#9acd32" - }; - (function(Processing) { - var unsupportedP5 = ("open() createOutput() createInput() BufferedReader selectFolder() " + "dataPath() createWriter() selectOutput() beginRecord() " + "saveStream() endRecord() selectInput() saveBytes() createReader() " + "beginRaw() endRaw() PrintWriter delay()").split(" "), - count = unsupportedP5.length, - prettyName, p5Name; - - function createUnsupportedFunc(n) { - return function() { - throw "Processing.js does not support " + n + "."; - } - } - while (count--) { - prettyName = unsupportedP5[count]; - p5Name = prettyName.replace("()", ""); - Processing[p5Name] = createUnsupportedFunc(prettyName) - } - })(defaultScope); - defaultScope.defineProperty(defaultScope, "screenWidth", { - get: function() { - return window.innerWidth - } - }); - defaultScope.defineProperty(defaultScope, "screenHeight", { - get: function() { - return window.innerHeight - } - }); - defaultScope.defineProperty(defaultScope, "online", { - get: function() { - return true - } - }); - var processingInstances = []; - var processingInstanceIds = {}; - var removeInstance = function(id) { - processingInstances.splice(processingInstanceIds[id], 1); - delete processingInstanceIds[id] - }; - var addInstance = function(processing) { - if (processing.externals.canvas.id === undef || !processing.externals.canvas.id.length) processing.externals.canvas.id = "__processing" + processingInstances.length; - processingInstanceIds[processing.externals.canvas.id] = processingInstances.length; - processingInstances.push(processing) - }; - - function computeFontMetrics(pfont) { - var emQuad = 250, - correctionFactor = pfont.size / emQuad, - canvas = document.createElement("canvas"); - canvas.width = 2 * emQuad; - canvas.height = 2 * emQuad; - canvas.style.opacity = 0; - var cfmFont = pfont.getCSSDefinition(emQuad + "px", "normal"), - ctx = canvas.getContext("2d"); - ctx.font = cfmFont; - var protrusions = "dbflkhyjqpg"; - canvas.width = ctx.measureText(protrusions).width; - ctx.font = cfmFont; - var leadDiv = document.createElement("div"); - leadDiv.style.position = "absolute"; - leadDiv.style.opacity = 0; - leadDiv.style.fontFamily = '"' + pfont.name + '"'; - leadDiv.style.fontSize = emQuad + "px"; - leadDiv.innerHTML = protrusions + "
" + protrusions; - document.body.appendChild(leadDiv); - var w = canvas.width, - h = canvas.height, - baseline = h / 2; - ctx.fillStyle = "white"; - ctx.fillRect(0, 0, w, h); - ctx.fillStyle = "black"; - ctx.fillText(protrusions, 0, baseline); - var pixelData = ctx.getImageData(0, 0, w, h).data; - var i = 0, - w4 = w * 4, - len = pixelData.length; - while (++i < len && pixelData[i] === 255) nop(); - var ascent = Math.round(i / w4); - i = len - 1; - while (--i > 0 && pixelData[i] === 255) nop(); - var descent = Math.round(i / w4); - pfont.ascent = correctionFactor * (baseline - ascent); - pfont.descent = correctionFactor * (descent - baseline); - if (document.defaultView.getComputedStyle) { - var leadDivHeight = document.defaultView.getComputedStyle(leadDiv, null).getPropertyValue("height"); - leadDivHeight = correctionFactor * leadDivHeight.replace("px", ""); - if (leadDivHeight >= pfont.size * 2) pfont.leading = Math.round(leadDivHeight / 2) - } - document.body.removeChild(leadDiv); - if (pfont.caching) return ctx - } - function PFont(name, size) { - if (name === undef) name = ""; - this.name = name; - if (size === undef) size = 0; - this.size = size; - this.glyph = false; - this.ascent = 0; - this.descent = 0; - this.leading = 1.2 * size; - var illegalIndicator = name.indexOf(" Italic Bold"); - if (illegalIndicator !== -1) name = name.substring(0, illegalIndicator); - this.style = "normal"; - var italicsIndicator = name.indexOf(" Italic"); - if (italicsIndicator !== -1) { - name = name.substring(0, italicsIndicator); - this.style = "italic" - } - this.weight = "normal"; - var boldIndicator = name.indexOf(" Bold"); - if (boldIndicator !== -1) { - name = name.substring(0, boldIndicator); - this.weight = "bold" - } - this.family = "sans-serif"; - if (name !== undef) switch (name) { - case "sans-serif": - case "serif": - case "monospace": - case "fantasy": - case "cursive": - this.family = name; - break; - default: - this.family = '"' + name + '", sans-serif'; - break - } - this.context2d = computeFontMetrics(this); - this.css = this.getCSSDefinition(); - if (this.context2d) this.context2d.font = this.css - } - PFont.prototype.caching = true; - PFont.prototype.getCSSDefinition = function(fontSize, lineHeight) { - if (fontSize === undef) fontSize = this.size + "px"; - if (lineHeight === undef) lineHeight = this.leading + "px"; - var components = [this.style, "normal", this.weight, fontSize + "/" + lineHeight, this.family]; - return components.join(" ") - }; - PFont.prototype.measureTextWidth = function(string) { - return this.context2d.measureText(string).width - }; - PFont.prototype.measureTextWidthFallback = function(string) { - var canvas = document.createElement("canvas"), - ctx = canvas.getContext("2d"); - ctx.font = this.css; - return ctx.measureText(string).width - }; - PFont.PFontCache = { - length: 0 - }; - PFont.get = function(fontName, fontSize) { - fontSize = (fontSize * 10 + 0.5 | 0) / 10; - var cache = PFont.PFontCache, - idx = fontName + "/" + fontSize; - if (!cache[idx]) { - cache[idx] = new PFont(fontName, fontSize); - cache.length++; - if (cache.length === 50) { - PFont.prototype.measureTextWidth = PFont.prototype.measureTextWidthFallback; - PFont.prototype.caching = false; - var entry; - for (entry in cache) if (entry !== "length") cache[entry].context2d = null; - return new PFont(fontName, fontSize) - } - if (cache.length === 400) { - PFont.PFontCache = {}; - PFont.get = PFont.getFallback; - return new PFont(fontName, fontSize) - } - } - return cache[idx] - }; - PFont.getFallback = function(fontName, fontSize) { - return new PFont(fontName, fontSize) - }; - PFont.list = function() { - return ["sans-serif", "serif", "monospace", "fantasy", "cursive"] - }; - PFont.preloading = { - template: {}, - initialized: false, - initialize: function() { - var generateTinyFont = function() { - var encoded = "#E3KAI2wAgT1MvMg7Eo3VmNtYX7ABi3CxnbHlm" + "7Abw3kaGVhZ7ACs3OGhoZWE7A53CRobXR47AY3" + "AGbG9jYQ7G03Bm1heH7ABC3CBuYW1l7Ae3AgcG" + "9zd7AI3AE#B3AQ2kgTY18PPPUACwAg3ALSRoo3" + "#yld0xg32QAB77#E777773B#E3C#I#Q77773E#" + "Q7777777772CMAIw7AB77732B#M#Q3wAB#g3B#" + "E#E2BB//82BB////w#B7#gAEg3E77x2B32B#E#" + "Q#MTcBAQ32gAe#M#QQJ#E32M#QQJ#I#g32Q77#"; - var expand = function(input) { - return "AAAAAAAA".substr(~~input ? 7 - input : 6) - }; - return encoded.replace(/[#237]/g, expand) - }; - var fontface = document.createElement("style"); - fontface.setAttribute("type", "text/css"); - fontface.innerHTML = "@font-face {\n" + ' font-family: "PjsEmptyFont";' + "\n" + " src: url('data:application/x-font-ttf;base64," + generateTinyFont() + "')\n" + " format('truetype');\n" + "}"; - document.head.appendChild(fontface); - var element = document.createElement("span"); - element.style.cssText = 'position: absolute; top: 0; left: 0; opacity: 0; font-family: "PjsEmptyFont", fantasy;'; - element.innerHTML = "AAAAAAAA"; - document.body.appendChild(element); - this.template = element; - this.initialized = true - }, - getElementWidth: function(element) { - return document.defaultView.getComputedStyle(element, "").getPropertyValue("width") - }, - timeAttempted: 0, - pending: function(intervallength) { - if (!this.initialized) this.initialize(); - var element, computedWidthFont, computedWidthRef = this.getElementWidth(this.template); - for (var i = 0; i < this.fontList.length; i++) { - element = this.fontList[i]; - computedWidthFont = this.getElementWidth(element); - if (this.timeAttempted < 4E3 && computedWidthFont === computedWidthRef) { - this.timeAttempted += intervallength; - return true - } else { - document.body.removeChild(element); - this.fontList.splice(i--, 1); - this.timeAttempted = 0 - } - } - if (this.fontList.length === 0) return false; - return true - }, - fontList: [], - addedList: {}, - add: function(fontSrc) { - if (!this.initialized) this.initialize(); - var fontName = typeof fontSrc === "object" ? fontSrc.fontFace : fontSrc, - fontUrl = typeof fontSrc === "object" ? fontSrc.url : fontSrc; - if (this.addedList[fontName]) return; - var style = document.createElement("style"); - style.setAttribute("type", "text/css"); - style.innerHTML = "@font-face{\n font-family: '" + fontName + "';\n src: url('" + fontUrl + "');\n}\n"; - document.head.appendChild(style); - this.addedList[fontName] = true; - var element = document.createElement("span"); - element.style.cssText = "position: absolute; top: 0; left: 0; opacity: 0;"; - element.style.fontFamily = '"' + fontName + '", "PjsEmptyFont", fantasy'; - element.innerHTML = "AAAAAAAA"; - document.body.appendChild(element); - this.fontList.push(element) - } - }; - defaultScope.PFont = PFont; - var Processing = this.Processing = function(aCanvas, aCode) { - if (! (this instanceof - Processing)) throw "called Processing constructor as if it were a function: missing 'new'."; - var curElement, pgraphicsMode = aCanvas === undef && aCode === undef; - if (pgraphicsMode) curElement = document.createElement("canvas"); - else curElement = typeof aCanvas === "string" ? document.getElementById(aCanvas) : aCanvas; - if (! (curElement instanceof HTMLCanvasElement)) throw "called Processing constructor without passing canvas element reference or id."; - - function unimplemented(s) { - Processing.debug("Unimplemented - " + s) - } - var p = this; - p.externals = { - canvas: curElement, - context: undef, - sketch: undef - }; - p.name = "Processing.js Instance"; - p.use3DContext = false; - p.focused = false; - p.breakShape = false; - p.glyphTable = {}; - p.pmouseX = 0; - p.pmouseY = 0; - p.mouseX = 0; - p.mouseY = 0; - p.mouseButton = 0; - p.mouseScroll = 0; - p.mouseClicked = undef; - p.mouseDragged = undef; - p.mouseMoved = undef; - p.mousePressed = undef; - p.mouseReleased = undef; - p.mouseScrolled = undef; - p.mouseOver = undef; - p.mouseOut = undef; - p.touchStart = undef; - p.touchEnd = undef; - p.touchMove = undef; - p.touchCancel = undef; - p.key = undef; - p.keyCode = undef; - p.keyPressed = nop; - p.keyReleased = nop; - p.keyTyped = nop; - p.draw = undef; - p.setup = undef; - p.__mousePressed = false; - p.__keyPressed = false; - p.__frameRate = 60; - p.frameCount = 0; - p.width = 100; - p.height = 100; - var curContext, curSketch, drawing, online = true, - doFill = true, - fillStyle = [1, 1, 1, 1], - currentFillColor = 4294967295, - isFillDirty = true, - doStroke = true, - strokeStyle = [0, 0, 0, 1], - currentStrokeColor = 4278190080, - isStrokeDirty = true, - lineWidth = 1, - loopStarted = false, - renderSmooth = false, - doLoop = true, - looping = 0, - curRectMode = 0, - curEllipseMode = 3, - normalX = 0, - normalY = 0, - normalZ = 0, - normalMode = 0, - curFrameRate = 60, - curMsPerFrame = 1E3 / curFrameRate, - curCursor = 'default', - oldCursor = curElement.style.cursor, - curShape = 20, - curShapeCount = 0, - curvePoints = [], - curTightness = 0, - curveDet = 20, - curveInited = false, - backgroundObj = -3355444, - bezDetail = 20, - colorModeA = 255, - colorModeX = 255, - colorModeY = 255, - colorModeZ = 255, - pathOpen = false, - mouseDragging = false, - pmouseXLastFrame = 0, - pmouseYLastFrame = 0, - curColorMode = 1, - curTint = null, - curTint3d = null, - getLoaded = false, - start = Date.now(), - timeSinceLastFPS = start, - framesSinceLastFPS = 0, - textcanvas, curveBasisMatrix, curveToBezierMatrix, curveDrawMatrix, bezierDrawMatrix, bezierBasisInverse, bezierBasisMatrix, curContextCache = { - attributes: {}, - locations: {} - }, - programObject3D, programObject2D, programObjectUnlitShape, boxBuffer, boxNormBuffer, boxOutlineBuffer, rectBuffer, rectNormBuffer, sphereBuffer, lineBuffer, fillBuffer, fillColorBuffer, strokeColorBuffer, pointBuffer, shapeTexVBO, canTex, textTex, curTexture = { - width: 0, - height: 0 - }, - curTextureMode = 2, - usingTexture = false, - textBuffer, textureBuffer, indexBuffer, horizontalTextAlignment = 37, - verticalTextAlignment = 0, - textMode = 4, - curFontName = "Arial", - curTextSize = 12, - curTextAscent = 9, - curTextDescent = 2, - curTextLeading = 14, - curTextFont = PFont.get(curFontName, curTextSize), - originalContext, proxyContext = null, - isContextReplaced = false, - setPixelsCached, maxPixelsCached = 1E3, - pressedKeysMap = [], - lastPressedKeyCode = null, - codedKeys = [16, - 17, 18, 20, 33, 34, 35, 36, 37, 38, 39, 40, 144, 155, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 157]; - var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop; - if (document.defaultView && document.defaultView.getComputedStyle) { - stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(curElement, null)["paddingLeft"], 10) || 0; - stylePaddingTop = parseInt(document.defaultView.getComputedStyle(curElement, null)["paddingTop"], 10) || 0; - styleBorderLeft = parseInt(document.defaultView.getComputedStyle(curElement, null)["borderLeftWidth"], 10) || 0; - styleBorderTop = parseInt(document.defaultView.getComputedStyle(curElement, null)["borderTopWidth"], 10) || 0 - } - var lightCount = 0; - var sphereDetailV = 0, - sphereDetailU = 0, - sphereX = [], - sphereY = [], - sphereZ = [], - sinLUT = new Float32Array(720), - cosLUT = new Float32Array(720), - sphereVerts, sphereNorms; - var cam, cameraInv, modelView, modelViewInv, userMatrixStack, userReverseMatrixStack, inverseCopy, projection, manipulatingCamera = false, - frustumMode = false, - cameraFOV = 60 * (Math.PI / 180), - cameraX = p.width / 2, - cameraY = p.height / 2, - cameraZ = cameraY / Math.tan(cameraFOV / 2), - cameraNear = cameraZ / 10, - cameraFar = cameraZ * 10, - cameraAspect = p.width / p.height; - var vertArray = [], - curveVertArray = [], - curveVertCount = 0, - isCurve = false, - isBezier = false, - firstVert = true; - var curShapeMode = 0; - var styleArray = []; - var boxVerts = new Float32Array([0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, - 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]); - var boxOutlineVerts = new Float32Array([0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5]); - var boxNorms = new Float32Array([0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0]); - var rectVerts = new Float32Array([0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0]); - var rectNorms = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); - var vertexShaderSrcUnlitShape = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec4 aColor;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform float uPointSize;" + "void main(void) {" + " vFrontColor = aColor;" + " gl_PointSize = uPointSize;" + " gl_Position = uProjection * uView * vec4(aVertex, 1.0);" + "}"; - var fragmentShaderSrcUnlitShape = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl_PointCoord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " gl_FragColor = vFrontColor;" + "}"; - var vertexShaderSrc2D = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec2 aTextureCoord;" + "uniform vec4 uColor;" + "uniform mat4 uModel;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform float uPointSize;" + "varying vec2 vTextureCoord;" + "void main(void) {" + " gl_PointSize = uPointSize;" + " vFrontColor = uColor;" + " gl_Position = uProjection * uView * uModel * vec4(aVertex, 1.0);" + " vTextureCoord = aTextureCoord;" + "}"; - var fragmentShaderSrc2D = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "varying vec2 vTextureCoord;" + "uniform sampler2D uSampler;" + "uniform int uIsDrawingText;" + "uniform bool uSmooth;" + "void main(void){" + " if(uSmooth == true){" + " float dist = distance(gl_PointCoord, vec2(0.5));" + " if(dist > 0.5){" + " discard;" + " }" + " }" + " if(uIsDrawingText == 1){" + " float alpha = texture2D(uSampler, vTextureCoord).a;" + " gl_FragColor = vec4(vFrontColor.rgb * alpha, alpha);" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; - var webglMaxTempsWorkaround = /Windows/.test(navigator.userAgent); - var vertexShaderSrc3D = "varying vec4 vFrontColor;" + "attribute vec3 aVertex;" + "attribute vec3 aNormal;" + "attribute vec4 aColor;" + "attribute vec2 aTexture;" + "varying vec2 vTexture;" + "uniform vec4 uColor;" + "uniform bool uUsingMat;" + "uniform vec3 uSpecular;" + "uniform vec3 uMaterialEmissive;" + "uniform vec3 uMaterialAmbient;" + "uniform vec3 uMaterialSpecular;" + "uniform float uShininess;" + "uniform mat4 uModel;" + "uniform mat4 uView;" + "uniform mat4 uProjection;" + "uniform mat4 uNormalTransform;" + "uniform int uLightCount;" + "uniform vec3 uFalloff;" + "struct Light {" + " int type;" + " vec3 color;" + " vec3 position;" + " vec3 direction;" + " float angle;" + " vec3 halfVector;" + " float concentration;" + "};" + "uniform Light uLights0;" + "uniform Light uLights1;" + "uniform Light uLights2;" + "uniform Light uLights3;" + "uniform Light uLights4;" + "uniform Light uLights5;" + "uniform Light uLights6;" + "uniform Light uLights7;" + "Light getLight(int index){" + " if(index == 0) return uLights0;" + " if(index == 1) return uLights1;" + " if(index == 2) return uLights2;" + " if(index == 3) return uLights3;" + " if(index == 4) return uLights4;" + " if(index == 5) return uLights5;" + " if(index == 6) return uLights6;" + " return uLights7;" + "}" + "void AmbientLight( inout vec3 totalAmbient, in vec3 ecPos, in Light light ) {" + " float d = length( light.position - ecPos );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + " totalAmbient += light.color * attenuation;" + "}" + "void DirectionalLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float powerFactor = 0.0;" + " float nDotVP = max(0.0, dot( vertNormal, normalize(-light.position) ));" + " float nDotVH = max(0.0, dot( vertNormal, normalize(-light.position-normalize(ecPos) )));" + " if( nDotVP != 0.0 ){" + " powerFactor = pow( nDotVH, uShininess );" + " }" + " col += light.color * nDotVP;" + " spec += uSpecular * powerFactor;" + "}" + "void PointLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float powerFactor;" + " vec3 VP = light.position - ecPos;" + " float d = length( VP ); " + " VP = normalize( VP );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ));" + " float nDotVP = max( 0.0, dot( vertNormal, VP ));" + " vec3 halfVector = normalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0, dot( vertNormal, halfVector ));" + " if( nDotVP == 0.0 ) {" + " powerFactor = 0.0;" + " }" + " else {" + " powerFactor = pow( nDotHV, uShininess );" + " }" + " spec += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void SpotLight( inout vec3 col, inout vec3 spec, in vec3 vertNormal, in vec3 ecPos, in Light light ) {" + " float spotAttenuation;" + " float powerFactor = 0.0;" + " vec3 VP = light.position - ecPos;" + " vec3 ldir = normalize( -light.direction );" + " float d = length( VP );" + " VP = normalize( VP );" + " float attenuation = 1.0 / ( uFalloff[0] + ( uFalloff[1] * d ) + ( uFalloff[2] * d * d ) );" + " float spotDot = dot( VP, ldir );" + (webglMaxTempsWorkaround ? " spotAttenuation = 1.0; " : " if( spotDot > cos( light.angle ) ) {" + " spotAttenuation = pow( spotDot, light.concentration );" + " }" + " else{" + " spotAttenuation = 0.0;" + " }" + " attenuation *= spotAttenuation;" + "") + " float nDotVP = max( 0.0, dot( vertNormal, VP ) );" + " vec3 halfVector = normalize( VP - normalize(ecPos) );" + " float nDotHV = max( 0.0, dot( vertNormal, halfVector ) );" + " if( nDotVP != 0.0 ) {" + " powerFactor = pow( nDotHV, uShininess );" + " }" + " spec += uSpecular * powerFactor * attenuation;" + " col += light.color * nDotVP * attenuation;" + "}" + "void main(void) {" + " vec3 finalAmbient = vec3( 0.0 );" + " vec3 finalDiffuse = vec3( 0.0 );" + " vec3 finalSpecular = vec3( 0.0 );" + " vec4 col = uColor;" + " if ( uColor[0] == -1.0 ){" + " col = aColor;" + " }" + " vec3 norm = normalize(vec3( uNormalTransform * vec4( aNormal, 0.0 ) ));" + " vec4 ecPos4 = uView * uModel * vec4(aVertex, 1.0);" + " vec3 ecPos = (vec3(ecPos4))/ecPos4.w;" + " if( uLightCount == 0 ) {" + " vFrontColor = col + vec4(uMaterialSpecular, 1.0);" + " }" + " else {" + " for( int i = 0; i < 8; i++ ) {" + " Light l = getLight(i);" + " if( i >= uLightCount ){" + " break;" + " }" + " if( l.type == 0 ) {" + " AmbientLight( finalAmbient, ecPos, l );" + " }" + " else if( l.type == 1 ) {" + " DirectionalLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else if( l.type == 2 ) {" + " PointLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " else {" + " SpotLight( finalDiffuse, finalSpecular, norm, ecPos, l );" + " }" + " }" + " if( uUsingMat == false ) {" + " vFrontColor = vec4(" + " vec3( col ) * finalAmbient +" + " vec3( col ) * finalDiffuse +" + " vec3( col ) * finalSpecular," + " col[3] );" + " }" + " else{" + " vFrontColor = vec4( " + " uMaterialEmissive + " + " (vec3(col) * uMaterialAmbient * finalAmbient ) + " + " (vec3(col) * finalDiffuse) + " + " (uMaterialSpecular * finalSpecular), " + " col[3] );" + " }" + " }" + " vTexture.xy = aTexture.xy;" + " gl_Position = uProjection * uView * uModel * vec4( aVertex, 1.0 );" + "}"; - var fragmentShaderSrc3D = "#ifdef GL_ES\n" + "precision highp float;\n" + "#endif\n" + "varying vec4 vFrontColor;" + "uniform sampler2D uSampler;" + "uniform bool uUsingTexture;" + "varying vec2 vTexture;" + "void main(void){" + " if( uUsingTexture ){" + " gl_FragColor = vec4(texture2D(uSampler, vTexture.xy)) * vFrontColor;" + " }" + " else{" + " gl_FragColor = vFrontColor;" + " }" + "}"; - - function uniformf(cacheId, programObj, varName, varValue) { - var varLocation = curContextCache.locations[cacheId]; - if (varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation - } - if (varLocation !== null) if (varValue.length === 4) curContext.uniform4fv(varLocation, varValue); - else if (varValue.length === 3) curContext.uniform3fv(varLocation, varValue); - else if (varValue.length === 2) curContext.uniform2fv(varLocation, varValue); - else curContext.uniform1f(varLocation, varValue) - } - function uniformi(cacheId, programObj, varName, varValue) { - var varLocation = curContextCache.locations[cacheId]; - if (varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation - } - if (varLocation !== null) if (varValue.length === 4) curContext.uniform4iv(varLocation, varValue); - else if (varValue.length === 3) curContext.uniform3iv(varLocation, varValue); - else if (varValue.length === 2) curContext.uniform2iv(varLocation, varValue); - else curContext.uniform1i(varLocation, varValue) - } - function uniformMatrix(cacheId, programObj, varName, transpose, matrix) { - var varLocation = curContextCache.locations[cacheId]; - if (varLocation === undef) { - varLocation = curContext.getUniformLocation(programObj, varName); - curContextCache.locations[cacheId] = varLocation - } - if (varLocation !== -1) if (matrix.length === 16) curContext.uniformMatrix4fv(varLocation, transpose, matrix); - else if (matrix.length === 9) curContext.uniformMatrix3fv(varLocation, transpose, matrix); - else curContext.uniformMatrix2fv(varLocation, transpose, matrix) - } - function vertexAttribPointer(cacheId, programObj, varName, size, VBO) { - var varLocation = curContextCache.attributes[cacheId]; - if (varLocation === undef) { - varLocation = curContext.getAttribLocation(programObj, varName); - curContextCache.attributes[cacheId] = varLocation - } - if (varLocation !== -1) { - curContext.bindBuffer(curContext.ARRAY_BUFFER, VBO); - curContext.vertexAttribPointer(varLocation, size, curContext.FLOAT, false, 0, 0); - curContext.enableVertexAttribArray(varLocation) - } - } - function disableVertexAttribPointer(cacheId, programObj, varName) { - var varLocation = curContextCache.attributes[cacheId]; - if (varLocation === undef) { - varLocation = curContext.getAttribLocation(programObj, varName); - curContextCache.attributes[cacheId] = varLocation - } - if (varLocation !== -1) curContext.disableVertexAttribArray(varLocation) - } - var createProgramObject = function(curContext, vetexShaderSource, fragmentShaderSource) { - var vertexShaderObject = curContext.createShader(curContext.VERTEX_SHADER); - curContext.shaderSource(vertexShaderObject, vetexShaderSource); - curContext.compileShader(vertexShaderObject); - if (!curContext.getShaderParameter(vertexShaderObject, curContext.COMPILE_STATUS)) throw curContext.getShaderInfoLog(vertexShaderObject); - var fragmentShaderObject = curContext.createShader(curContext.FRAGMENT_SHADER); - curContext.shaderSource(fragmentShaderObject, fragmentShaderSource); - curContext.compileShader(fragmentShaderObject); - if (!curContext.getShaderParameter(fragmentShaderObject, curContext.COMPILE_STATUS)) throw curContext.getShaderInfoLog(fragmentShaderObject); - var programObject = curContext.createProgram(); - curContext.attachShader(programObject, vertexShaderObject); - curContext.attachShader(programObject, fragmentShaderObject); - curContext.linkProgram(programObject); - if (!curContext.getProgramParameter(programObject, curContext.LINK_STATUS)) throw "Error linking shaders."; - return programObject - }; - var imageModeCorner = function(x, y, w, h, whAreSizes) { - return { - x: x, - y: y, - w: w, - h: h - } - }; - var imageModeConvert = imageModeCorner; - var imageModeCorners = function(x, y, w, h, whAreSizes) { - return { - x: x, - y: y, - w: whAreSizes ? w : w - x, - h: whAreSizes ? h : h - y - } - }; - var imageModeCenter = function(x, y, w, h, whAreSizes) { - return { - x: x - w / 2, - y: y - h / 2, - w: w, - h: h - } - }; - var DrawingShared = function() {}; - var Drawing2D = function() {}; - var Drawing3D = function() {}; - var DrawingPre = function() {}; - Drawing2D.prototype = new DrawingShared; - Drawing2D.prototype.constructor = Drawing2D; - Drawing3D.prototype = new DrawingShared; - Drawing3D.prototype.constructor = Drawing3D; - DrawingPre.prototype = new DrawingShared; - DrawingPre.prototype.constructor = DrawingPre; - DrawingShared.prototype.a3DOnlyFunction = nop; - var charMap = {}; - var Char = p.Character = function(chr) { - if (typeof chr === "string" && chr.length === 1) this.code = chr.charCodeAt(0); - else if (typeof chr === "number") this.code = chr; - else if (chr instanceof Char) this.code = chr; - else this.code = NaN; - return charMap[this.code] === undef ? charMap[this.code] = this : charMap[this.code] - }; - Char.prototype.toString = function() { - return String.fromCharCode(this.code) - }; - Char.prototype.valueOf = function() { - return this.code - }; - var PShape = p.PShape = function(family) { - this.family = family || 0; - this.visible = true; - this.style = true; - this.children = []; - this.nameTable = []; - this.params = []; - this.name = ""; - this.image = null; - this.matrix = null; - this.kind = null; - this.close = null; - this.width = null; - this.height = null; - this.parent = null - }; - PShape.prototype = { - isVisible: function() { - return this.visible - }, - setVisible: function(visible) { - this.visible = visible - }, - disableStyle: function() { - this.style = false; - for (var i = 0, j = this.children.length; i < j; i++) this.children[i].disableStyle() - }, - enableStyle: function() { - this.style = true; - for (var i = 0, j = this.children.length; i < j; i++) this.children[i].enableStyle() - }, - getFamily: function() { - return this.family - }, - getWidth: function() { - return this.width - }, - getHeight: function() { - return this.height - }, - setName: function(name) { - this.name = name - }, - getName: function() { - return this.name - }, - draw: function(renderContext) { - renderContext = renderContext || p; - if (this.visible) { - this.pre(renderContext); - this.drawImpl(renderContext); - this.post(renderContext) - } - }, - drawImpl: function(renderContext) { - if (this.family === 0) this.drawGroup(renderContext); - else if (this.family === 1) this.drawPrimitive(renderContext); - else if (this.family === 3) this.drawGeometry(renderContext); - else if (this.family === 21) this.drawPath(renderContext) - }, - drawPath: function(renderContext) { - var i, j; - if (this.vertices.length === 0) return; - renderContext.beginShape(); - if (this.vertexCodes.length === 0) if (this.vertices[0].length === 2) for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i][0], this.vertices[i][1]); - else for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i][0], this.vertices[i][1], this.vertices[i][2]); - else { - var index = 0; - if (this.vertices[0].length === 2) for (i = 0, j = this.vertexCodes.length; i < j; i++) if (this.vertexCodes[i] === 0) { - renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index]["moveTo"]); - renderContext.breakShape = false; - index++ - } else if (this.vertexCodes[i] === 1) { - renderContext.bezierVertex(this.vertices[index + 0][0], this.vertices[index + 0][1], this.vertices[index + 1][0], this.vertices[index + 1][1], this.vertices[index + 2][0], this.vertices[index + 2][1]); - index += 3 - } else if (this.vertexCodes[i] === 2) { - renderContext.curveVertex(this.vertices[index][0], this.vertices[index][1]); - index++ - } else { - if (this.vertexCodes[i] === 3) renderContext.breakShape = true - } else for (i = 0, j = this.vertexCodes.length; i < j; i++) if (this.vertexCodes[i] === 0) { - renderContext.vertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index][2]); - if (this.vertices[index]["moveTo"] === true) vertArray[vertArray.length - 1]["moveTo"] = true; - else if (this.vertices[index]["moveTo"] === false) vertArray[vertArray.length - 1]["moveTo"] = false; - renderContext.breakShape = false - } else if (this.vertexCodes[i] === 1) { - renderContext.bezierVertex(this.vertices[index + 0][0], this.vertices[index + 0][1], this.vertices[index + 0][2], this.vertices[index + 1][0], this.vertices[index + 1][1], this.vertices[index + 1][2], this.vertices[index + 2][0], this.vertices[index + 2][1], this.vertices[index + 2][2]); - index += 3 - } else if (this.vertexCodes[i] === 2) { - renderContext.curveVertex(this.vertices[index][0], this.vertices[index][1], this.vertices[index][2]); - index++ - } else if (this.vertexCodes[i] === 3) renderContext.breakShape = true - } - renderContext.endShape(this.close ? 2 : 1) - }, - drawGeometry: function(renderContext) { - var i, j; - renderContext.beginShape(this.kind); - if (this.style) for (i = 0, j = this.vertices.length; i < j; i++) renderContext.vertex(this.vertices[i]); - else for (i = 0, j = this.vertices.length; i < j; i++) { - var vert = this.vertices[i]; - if (vert[2] === 0) renderContext.vertex(vert[0], vert[1]); - else renderContext.vertex(vert[0], vert[1], vert[2]) - } - renderContext.endShape() - }, - drawGroup: function(renderContext) { - for (var i = 0, j = this.children.length; i < j; i++) this.children[i].draw(renderContext) - }, - drawPrimitive: function(renderContext) { - if (this.kind === 2) renderContext.point(this.params[0], this.params[1]); - else if (this.kind === 4) if (this.params.length === 4) renderContext.line(this.params[0], this.params[1], this.params[2], this.params[3]); - else renderContext.line(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); - else if (this.kind === 8) renderContext.triangle(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); - else if (this.kind === 16) renderContext.quad(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5], this.params[6], this.params[7]); - else if (this.kind === 30) if (this.image !== null) { - var imMode = imageModeConvert; - renderContext.imageMode(0); - renderContext.image(this.image, this.params[0], this.params[1], this.params[2], this.params[3]); - imageModeConvert = imMode - } else { - var rcMode = curRectMode; - renderContext.rectMode(0); - renderContext.rect(this.params[0], this.params[1], this.params[2], this.params[3]); - curRectMode = rcMode - } else if (this.kind === 31) { - var elMode = curEllipseMode; - renderContext.ellipseMode(0); - renderContext.ellipse(this.params[0], this.params[1], this.params[2], this.params[3]); - curEllipseMode = elMode - } else if (this.kind === 32) { - var eMode = curEllipseMode; - renderContext.ellipseMode(0); - renderContext.arc(this.params[0], this.params[1], this.params[2], this.params[3], this.params[4], this.params[5]); - curEllipseMode = eMode - } else if (this.kind === 41) if (this.params.length === 1) renderContext.box(this.params[0]); - else renderContext.box(this.params[0], this.params[1], this.params[2]); - else if (this.kind === 40) renderContext.sphere(this.params[0]) - }, - pre: function(renderContext) { - if (this.matrix) { - renderContext.pushMatrix(); - renderContext.transform(this.matrix) - } - if (this.style) { - renderContext.pushStyle(); - this.styles(renderContext) - } - }, - post: function(renderContext) { - if (this.matrix) renderContext.popMatrix(); - if (this.style) renderContext.popStyle() - }, - styles: function(renderContext) { - if (this.stroke) { - renderContext.stroke(this.strokeColor); - renderContext.strokeWeight(this.strokeWeight); - renderContext.strokeCap(this.strokeCap); - renderContext.strokeJoin(this.strokeJoin) - } else renderContext.noStroke(); - if (this.fill) renderContext.fill(this.fillColor); - else renderContext.noFill() - }, - getChild: function(child) { - var i, j; - if (typeof child === "number") return this.children[child]; - var found; - if (child === "" || this.name === child) return this; - if (this.nameTable.length > 0) { - for (i = 0, j = this.nameTable.length; i < j || found; i++) if (this.nameTable[i].getName === child) { - found = this.nameTable[i]; - break - } - if (found) return found - } - for (i = 0, j = this.children.length; i < j; i++) { - found = this.children[i].getChild(child); - if (found) return found - } - return null - }, - getChildCount: function() { - return this.children.length - }, - addChild: function(child) { - this.children.push(child); - child.parent = this; - if (child.getName() !== null) this.addName(child.getName(), child) - }, - addName: function(name, shape) { - if (this.parent !== null) this.parent.addName(name, shape); - else this.nameTable.push([name, shape]) - }, - translate: function() { - if (arguments.length === 2) { - this.checkMatrix(2); - this.matrix.translate(arguments[0], arguments[1]) - } else { - this.checkMatrix(3); - this.matrix.translate(arguments[0], arguments[1], 0) - } - }, - checkMatrix: function(dimensions) { - if (this.matrix === null) if (dimensions === 2) this.matrix = new p.PMatrix2D; - else this.matrix = new p.PMatrix3D; - else if (dimensions === 3 && this.matrix instanceof p.PMatrix2D) this.matrix = new p.PMatrix3D - }, - rotateX: function(angle) { - this.rotate(angle, 1, 0, 0) - }, - rotateY: function(angle) { - this.rotate(angle, 0, 1, 0) - }, - rotateZ: function(angle) { - this.rotate(angle, 0, 0, 1) - }, - rotate: function() { - if (arguments.length === 1) { - this.checkMatrix(2); - this.matrix.rotate(arguments[0]) - } else { - this.checkMatrix(3); - this.matrix.rotate(arguments[0], arguments[1], arguments[2], arguments[3]) - } - }, - scale: function() { - if (arguments.length === 2) { - this.checkMatrix(2); - this.matrix.scale(arguments[0], arguments[1]) - } else if (arguments.length === 3) { - this.checkMatrix(2); - this.matrix.scale(arguments[0], arguments[1], arguments[2]) - } else { - this.checkMatrix(2); - this.matrix.scale(arguments[0]) - } - }, - resetMatrix: function() { - this.checkMatrix(2); - this.matrix.reset() - }, - applyMatrix: function(matrix) { - if (arguments.length === 1) this.applyMatrix(matrix.elements[0], matrix.elements[1], 0, matrix.elements[2], matrix.elements[3], matrix.elements[4], 0, matrix.elements[5], 0, 0, 1, 0, 0, 0, 0, 1); - else if (arguments.length === 6) { - this.checkMatrix(2); - this.matrix.apply(arguments[0], arguments[1], arguments[2], 0, arguments[3], arguments[4], arguments[5], 0, 0, 0, 1, 0, 0, 0, 0, 1) - } else if (arguments.length === 16) { - this.checkMatrix(3); - this.matrix.apply(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11], arguments[12], arguments[13], arguments[14], arguments[15]) - } - } - }; - var PShapeSVG = p.PShapeSVG = function() { - p.PShape.call(this); - if (arguments.length === 1) { - this.element = arguments[0]; - this.vertexCodes = []; - this.vertices = []; - this.opacity = 1; - this.stroke = false; - this.strokeColor = 4278190080; - this.strokeWeight = 1; - this.strokeCap = 'butt'; - this.strokeJoin = 'miter'; - this.strokeGradient = null; - this.strokeGradientPaint = null; - this.strokeName = null; - this.strokeOpacity = 1; - this.fill = true; - this.fillColor = 4278190080; - this.fillGradient = null; - this.fillGradientPaint = null; - this.fillName = null; - this.fillOpacity = 1; - if (this.element.getName() !== "svg") throw "root is not , it's <" + this.element.getName() + ">"; - } else if (arguments.length === 2) if (typeof arguments[1] === "string") { - if (arguments[1].indexOf(".svg") > -1) { - this.element = new p.XMLElement(p, arguments[1]); - this.vertexCodes = []; - this.vertices = []; - this.opacity = 1; - this.stroke = false; - this.strokeColor = 4278190080; - this.strokeWeight = 1; - this.strokeCap = 'butt'; - this.strokeJoin = 'miter'; - this.strokeGradient = ""; - this.strokeGradientPaint = ""; - this.strokeName = ""; - this.strokeOpacity = 1; - this.fill = true; - this.fillColor = 4278190080; - this.fillGradient = null; - this.fillGradientPaint = null; - this.fillOpacity = 1 - } - } else if (arguments[0]) { - this.element = arguments[1]; - this.vertexCodes = arguments[0].vertexCodes.slice(); - this.vertices = arguments[0].vertices.slice(); - this.stroke = arguments[0].stroke; - this.strokeColor = arguments[0].strokeColor; - this.strokeWeight = arguments[0].strokeWeight; - this.strokeCap = arguments[0].strokeCap; - this.strokeJoin = arguments[0].strokeJoin; - this.strokeGradient = arguments[0].strokeGradient; - this.strokeGradientPaint = arguments[0].strokeGradientPaint; - this.strokeName = arguments[0].strokeName; - this.fill = arguments[0].fill; - this.fillColor = arguments[0].fillColor; - this.fillGradient = arguments[0].fillGradient; - this.fillGradientPaint = arguments[0].fillGradientPaint; - this.fillName = arguments[0].fillName; - this.strokeOpacity = arguments[0].strokeOpacity; - this.fillOpacity = arguments[0].fillOpacity; - this.opacity = arguments[0].opacity - } - this.name = this.element.getStringAttribute("id"); - var displayStr = this.element.getStringAttribute("display", "inline"); - this.visible = displayStr !== "none"; - var str = this.element.getAttribute("transform"); - if (str) this.matrix = this.parseMatrix(str); - var viewBoxStr = this.element.getStringAttribute("viewBox"); - if (viewBoxStr !== null) { - var viewBox = viewBoxStr.split(" "); - this.width = viewBox[2]; - this.height = viewBox[3] - } - var unitWidth = this.element.getStringAttribute("width"); - var unitHeight = this.element.getStringAttribute("height"); - if (unitWidth !== null) { - this.width = this.parseUnitSize(unitWidth); - this.height = this.parseUnitSize(unitHeight) - } else if (this.width === 0 || this.height === 0) { - this.width = 1; - this.height = 1; - throw "The width and/or height is not " + "readable in the tag of this file."; - } - this.parseColors(this.element); - this.parseChildren(this.element) - }; - PShapeSVG.prototype = new PShape; - PShapeSVG.prototype.parseMatrix = function() { - function getCoords(s) { - var m = []; - s.replace(/\((.*?)\)/, function() { - return function(all, params) { - m = params.replace(/,+/g, " ").split(/\s+/) - } - }()); - return m - } - return function(str) { - this.checkMatrix(2); - var pieces = []; - str.replace(/\s*(\w+)\((.*?)\)/g, function(all) { - pieces.push(p.trim(all)) - }); - if (pieces.length === 0) return null; - for (var i = 0, j = pieces.length; i < j; i++) { - var m = getCoords(pieces[i]); - if (pieces[i].indexOf("matrix") !== -1) this.matrix.set(m[0], m[2], m[4], m[1], m[3], m[5]); - else if (pieces[i].indexOf("translate") !== -1) { - var tx = m[0]; - var ty = m.length === 2 ? m[1] : 0; - this.matrix.translate(tx, ty) - } else if (pieces[i].indexOf("scale") !== -1) { - var sx = m[0]; - var sy = m.length === 2 ? m[1] : m[0]; - this.matrix.scale(sx, sy) - } else if (pieces[i].indexOf("rotate") !== -1) { - var angle = m[0]; - if (m.length === 1) this.matrix.rotate(p.radians(angle)); - else if (m.length === 3) { - this.matrix.translate(m[1], m[2]); - this.matrix.rotate(p.radians(m[0])); - this.matrix.translate(-m[1], -m[2]) - } - } else if (pieces[i].indexOf("skewX") !== -1) this.matrix.skewX(parseFloat(m[0])); - else if (pieces[i].indexOf("skewY") !== -1) this.matrix.skewY(m[0]); - else if (pieces[i].indexOf("shearX") !== -1) this.matrix.shearX(m[0]); - else if (pieces[i].indexOf("shearY") !== -1) this.matrix.shearY(m[0]) - } - return this.matrix - } - }(); - PShapeSVG.prototype.parseChildren = function(element) { - var newelement = element.getChildren(); - var children = new p.PShape; - for (var i = 0, j = newelement.length; i < j; i++) { - var kid = this.parseChild(newelement[i]); - if (kid) children.addChild(kid) - } - this.children.push(children) - }; - PShapeSVG.prototype.getName = function() { - return this.name - }; - PShapeSVG.prototype.parseChild = function(elem) { - var name = elem.getName(); - var shape; - if (name === "g") shape = new PShapeSVG(this, elem); - else if (name === "defs") shape = new PShapeSVG(this, elem); - else if (name === "line") { - shape = new PShapeSVG(this, elem); - shape.parseLine() - } else if (name === "circle") { - shape = new PShapeSVG(this, elem); - shape.parseEllipse(true) - } else if (name === "ellipse") { - shape = new PShapeSVG(this, elem); - shape.parseEllipse(false) - } else if (name === "rect") { - shape = new PShapeSVG(this, elem); - shape.parseRect() - } else if (name === "polygon") { - shape = new PShapeSVG(this, elem); - shape.parsePoly(true) - } else if (name === "polyline") { - shape = new PShapeSVG(this, elem); - shape.parsePoly(false) - } else if (name === "path") { - shape = new PShapeSVG(this, elem); - shape.parsePath() - } else if (name === "radialGradient") unimplemented("PShapeSVG.prototype.parseChild, name = radialGradient"); - else if (name === "linearGradient") unimplemented("PShapeSVG.prototype.parseChild, name = linearGradient"); - else if (name === "text") unimplemented("PShapeSVG.prototype.parseChild, name = text"); - else if (name === "filter") unimplemented("PShapeSVG.prototype.parseChild, name = filter"); - else if (name === "mask") unimplemented("PShapeSVG.prototype.parseChild, name = mask"); - else nop(); - return shape - }; - PShapeSVG.prototype.parsePath = function() { - this.family = 21; - this.kind = 0; - var pathDataChars = []; - var c; - var pathData = p.trim(this.element.getStringAttribute("d").replace(/[\s,]+/g, " ")); - if (pathData === null) return; - pathData = p.__toCharArray(pathData); - var cx = 0, - cy = 0, - ctrlX = 0, - ctrlY = 0, - ctrlX1 = 0, - ctrlX2 = 0, - ctrlY1 = 0, - ctrlY2 = 0, - endX = 0, - endY = 0, - ppx = 0, - ppy = 0, - px = 0, - py = 0, - i = 0, - valOf = 0; - var str = ""; - var tmpArray = []; - var flag = false; - var lastInstruction; - var command; - var j, k; - while (i < pathData.length) { - valOf = pathData[i].valueOf(); - if (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 122) { - j = i; - i++; - if (i < pathData.length) { - tmpArray = []; - valOf = pathData[i].valueOf(); - while (! (valOf >= 65 && valOf <= 90 || valOf >= 97 && valOf <= 100 || valOf >= 102 && valOf <= 122) && flag === false) { - if (valOf === 32) { - if (str !== "") { - tmpArray.push(parseFloat(str)); - str = "" - } - i++ - } else if (valOf === 45) if (pathData[i - 1].valueOf() === 101) { - str += pathData[i].toString(); - i++ - } else { - if (str !== "") tmpArray.push(parseFloat(str)); - str = pathData[i].toString(); - i++ - } else { - str += pathData[i].toString(); - i++ - } - if (i === pathData.length) flag = true; - else valOf = pathData[i].valueOf() - } - } - if (str !== "") { - tmpArray.push(parseFloat(str)); - str = "" - } - command = pathData[j]; - valOf = command.valueOf(); - if (valOf === 77) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - cx = tmpArray[0]; - cy = tmpArray[1]; - this.parsePathMoveto(cx, cy); - if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { - cx = tmpArray[j]; - cy = tmpArray[j + 1]; - this.parsePathLineto(cx, cy) - } - } - } else if (valOf === 109) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) { - cx += tmpArray[0]; - cy += tmpArray[1]; - this.parsePathMoveto(cx, cy); - if (tmpArray.length > 2) for (j = 2, k = tmpArray.length; j < k; j += 2) { - cx += tmpArray[j]; - cy += tmpArray[j + 1]; - this.parsePathLineto(cx, cy) - } - } - } else if (valOf === 76) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { - cx = tmpArray[j]; - cy = tmpArray[j + 1]; - this.parsePathLineto(cx, cy) - } - } else if (valOf === 108) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { - cx += tmpArray[j]; - cy += tmpArray[j + 1]; - this.parsePathLineto(cx, cy) - } - } else if (valOf === 72) for (j = 0, k = tmpArray.length; j < k; j++) { - cx = tmpArray[j]; - this.parsePathLineto(cx, cy) - } else if (valOf === 104) for (j = 0, k = tmpArray.length; j < k; j++) { - cx += tmpArray[j]; - this.parsePathLineto(cx, cy) - } else if (valOf === 86) for (j = 0, k = tmpArray.length; j < k; j++) { - cy = tmpArray[j]; - this.parsePathLineto(cx, cy) - } else if (valOf === 118) for (j = 0, k = tmpArray.length; j < k; j++) { - cy += tmpArray[j]; - this.parsePathLineto(cx, cy) - } else if (valOf === 67) { - if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { - ctrlX1 = tmpArray[j]; - ctrlY1 = tmpArray[j + 1]; - ctrlX2 = tmpArray[j + 2]; - ctrlY2 = tmpArray[j + 3]; - endX = tmpArray[j + 4]; - endY = tmpArray[j + 5]; - this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 99) { - if (tmpArray.length >= 6 && tmpArray.length % 6 === 0) for (j = 0, k = tmpArray.length; j < k; j += 6) { - ctrlX1 = cx + tmpArray[j]; - ctrlY1 = cy + tmpArray[j + 1]; - ctrlX2 = cx + tmpArray[j + 2]; - ctrlY2 = cy + tmpArray[j + 3]; - endX = cx + tmpArray[j + 4]; - endY = cy + tmpArray[j + 5]; - this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 83) { - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { - if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLowerCase() === "s") { - ppx = this.vertices[this.vertices.length - 2][0]; - ppy = this.vertices[this.vertices.length - 2][1]; - px = this.vertices[this.vertices.length - 1][0]; - py = this.vertices[this.vertices.length - 1][1]; - ctrlX1 = px + (px - ppx); - ctrlY1 = py + (py - ppy) - } else { - ctrlX1 = this.vertices[this.vertices.length - 1][0]; - ctrlY1 = this.vertices[this.vertices.length - 1][1] - } - ctrlX2 = tmpArray[j]; - ctrlY2 = tmpArray[j + 1]; - endX = tmpArray[j + 2]; - endY = tmpArray[j + 3]; - this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 115) { - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { - if (lastInstruction.toLowerCase() === "c" || lastInstruction.toLowerCase() === "s") { - ppx = this.vertices[this.vertices.length - 2][0]; - ppy = this.vertices[this.vertices.length - 2][1]; - px = this.vertices[this.vertices.length - 1][0]; - py = this.vertices[this.vertices.length - 1][1]; - ctrlX1 = px + (px - ppx); - ctrlY1 = py + (py - ppy) - } else { - ctrlX1 = this.vertices[this.vertices.length - 1][0]; - ctrlY1 = this.vertices[this.vertices.length - 1][1] - } - ctrlX2 = cx + tmpArray[j]; - ctrlY2 = cy + tmpArray[j + 1]; - endX = cx + tmpArray[j + 2]; - endY = cy + tmpArray[j + 3]; - this.parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 81) { - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { - ctrlX = tmpArray[j]; - ctrlY = tmpArray[j + 1]; - endX = tmpArray[j + 2]; - endY = tmpArray[j + 3]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 113) { - if (tmpArray.length >= 4 && tmpArray.length % 4 === 0) for (j = 0, k = tmpArray.length; j < k; j += 4) { - ctrlX = cx + tmpArray[j]; - ctrlY = cy + tmpArray[j + 1]; - endX = cx + tmpArray[j + 2]; - endY = cy + tmpArray[j + 3]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 84) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { - if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLowerCase() === "t") { - ppx = this.vertices[this.vertices.length - 2][0]; - ppy = this.vertices[this.vertices.length - 2][1]; - px = this.vertices[this.vertices.length - 1][0]; - py = this.vertices[this.vertices.length - 1][1]; - ctrlX = px + (px - ppx); - ctrlY = py + (py - ppy) - } else { - ctrlX = cx; - ctrlY = cy - } - endX = tmpArray[j]; - endY = tmpArray[j + 1]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 116) { - if (tmpArray.length >= 2 && tmpArray.length % 2 === 0) for (j = 0, k = tmpArray.length; j < k; j += 2) { - if (lastInstruction.toLowerCase() === "q" || lastInstruction.toLowerCase() === "t") { - ppx = this.vertices[this.vertices.length - 2][0]; - ppy = this.vertices[this.vertices.length - 2][1]; - px = this.vertices[this.vertices.length - 1][0]; - py = this.vertices[this.vertices.length - 1][1]; - ctrlX = px + (px - ppx); - ctrlY = py + (py - ppy) - } else { - ctrlX = cx; - ctrlY = cy - } - endX = cx + tmpArray[j]; - endY = cy + tmpArray[j + 1]; - this.parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY); - cx = endX; - cy = endY - } - } else if (valOf === 90 || valOf === 122) this.close = true; - lastInstruction = command.toString() - } else i++ - } - }; - PShapeSVG.prototype.parsePathQuadto = function(x1, y1, cx, cy, x2, y2) { - if (this.vertices.length > 0) { - this.parsePathCode(1); - this.parsePathVertex(x1 + (cx - x1) * 2 / 3, y1 + (cy - y1) * 2 / 3); - this.parsePathVertex(x2 + (cx - x2) * 2 / 3, y2 + (cy - y2) * 2 / 3); - this.parsePathVertex(x2, y2) - } else throw "Path must start with M/m"; - }; - PShapeSVG.prototype.parsePathCurveto = function(x1, y1, x2, y2, x3, y3) { - if (this.vertices.length > 0) { - this.parsePathCode(1); - this.parsePathVertex(x1, y1); - this.parsePathVertex(x2, y2); - this.parsePathVertex(x3, y3) - } else throw "Path must start with M/m"; - }; - PShapeSVG.prototype.parsePathLineto = function(px, py) { - if (this.vertices.length > 0) { - this.parsePathCode(0); - this.parsePathVertex(px, py); - this.vertices[this.vertices.length - 1]["moveTo"] = false - } else throw "Path must start with M/m"; - }; - PShapeSVG.prototype.parsePathMoveto = function(px, py) { - if (this.vertices.length > 0) this.parsePathCode(3); - this.parsePathCode(0); - this.parsePathVertex(px, py); - this.vertices[this.vertices.length - 1]["moveTo"] = true - }; - PShapeSVG.prototype.parsePathVertex = function(x, y) { - var verts = []; - verts[0] = x; - verts[1] = y; - this.vertices.push(verts) - }; - PShapeSVG.prototype.parsePathCode = function(what) { - this.vertexCodes.push(what) - }; - PShapeSVG.prototype.parsePoly = function(val) { - this.family = 21; - this.close = val; - var pointsAttr = p.trim(this.element.getStringAttribute("points").replace(/[,\s]+/g, " ")); - if (pointsAttr !== null) { - var pointsBuffer = pointsAttr.split(" "); - if (pointsBuffer.length % 2 === 0) for (var i = 0, j = pointsBuffer.length; i < j; i++) { - var verts = []; - verts[0] = pointsBuffer[i]; - verts[1] = pointsBuffer[++i]; - this.vertices.push(verts) - } else throw "Error parsing polygon points: odd number of coordinates provided"; - } - }; - PShapeSVG.prototype.parseRect = function() { - this.kind = 30; - this.family = 1; - this.params = []; - this.params[0] = this.element.getFloatAttribute("x"); - this.params[1] = this.element.getFloatAttribute("y"); - this.params[2] = this.element.getFloatAttribute("width"); - this.params[3] = this.element.getFloatAttribute("height"); - if (this.params[2] < 0 || this.params[3] < 0) throw "svg error: negative width or height found while parsing "; - }; - PShapeSVG.prototype.parseEllipse = function(val) { - this.kind = 31; - this.family = 1; - this.params = []; - this.params[0] = this.element.getFloatAttribute("cx") | 0; - this.params[1] = this.element.getFloatAttribute("cy") | 0; - var rx, ry; - if (val) { - rx = ry = this.element.getFloatAttribute("r"); - if (rx < 0) throw "svg error: negative radius found while parsing "; - } else { - rx = this.element.getFloatAttribute("rx"); - ry = this.element.getFloatAttribute("ry"); - if (rx < 0 || ry < 0) throw "svg error: negative x-axis radius or y-axis radius found while parsing "; - } - this.params[0] -= rx; - this.params[1] -= ry; - this.params[2] = rx * 2; - this.params[3] = ry * 2 - }; - PShapeSVG.prototype.parseLine = function() { - this.kind = 4; - this.family = 1; - this.params = []; - this.params[0] = this.element.getFloatAttribute("x1"); - this.params[1] = this.element.getFloatAttribute("y1"); - this.params[2] = this.element.getFloatAttribute("x2"); - this.params[3] = this.element.getFloatAttribute("y2") - }; - PShapeSVG.prototype.parseColors = function(element) { - if (element.hasAttribute("opacity")) this.setOpacity(element.getAttribute("opacity")); - if (element.hasAttribute("stroke")) this.setStroke(element.getAttribute("stroke")); - if (element.hasAttribute("stroke-width")) this.setStrokeWeight(element.getAttribute("stroke-width")); - if (element.hasAttribute("stroke-linejoin")) this.setStrokeJoin(element.getAttribute("stroke-linejoin")); - if (element.hasAttribute("stroke-linecap")) this.setStrokeCap(element.getStringAttribute("stroke-linecap")); - if (element.hasAttribute("fill")) this.setFill(element.getStringAttribute("fill")); - if (element.hasAttribute("style")) { - var styleText = element.getStringAttribute("style"); - var styleTokens = styleText.toString().split(";"); - for (var i = 0, j = styleTokens.length; i < j; i++) { - var tokens = p.trim(styleTokens[i].split(":")); - if (tokens[0] === "fill") this.setFill(tokens[1]); - else if (tokens[0] === "fill-opacity") this.setFillOpacity(tokens[1]); - else if (tokens[0] === "stroke") this.setStroke(tokens[1]); - else if (tokens[0] === "stroke-width") this.setStrokeWeight(tokens[1]); - else if (tokens[0] === "stroke-linecap") this.setStrokeCap(tokens[1]); - else if (tokens[0] === "stroke-linejoin") this.setStrokeJoin(tokens[1]); - else if (tokens[0] === "stroke-opacity") this.setStrokeOpacity(tokens[1]); - else if (tokens[0] === "opacity") this.setOpacity(tokens[1]) - } - } - }; - PShapeSVG.prototype.setFillOpacity = function(opacityText) { - this.fillOpacity = parseFloat(opacityText); - this.fillColor = this.fillOpacity * 255 << 24 | this.fillColor & 16777215 - }; - PShapeSVG.prototype.setFill = function(fillText) { - var opacityMask = this.fillColor & 4278190080; - if (fillText === "none") this.fill = false; - else if (fillText.indexOf("#") === 0) { - this.fill = true; - if (fillText.length === 4) fillText = fillText.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); - this.fillColor = opacityMask | parseInt(fillText.substring(1), 16) & 16777215 - } else if (fillText.indexOf("rgb") === 0) { - this.fill = true; - this.fillColor = opacityMask | this.parseRGB(fillText) - } else if (fillText.indexOf("url(#") === 0) this.fillName = fillText.substring(5, fillText.length - 1); - else if (colors[fillText]) { - this.fill = true; - this.fillColor = opacityMask | parseInt(colors[fillText].substring(1), 16) & 16777215 - } - }; - PShapeSVG.prototype.setOpacity = function(opacity) { - this.strokeColor = parseFloat(opacity) * 255 << 24 | this.strokeColor & 16777215; - this.fillColor = parseFloat(opacity) * 255 << 24 | this.fillColor & 16777215 - }; - PShapeSVG.prototype.setStroke = function(strokeText) { - var opacityMask = this.strokeColor & 4278190080; - if (strokeText === "none") this.stroke = false; - else if (strokeText.charAt(0) === "#") { - this.stroke = true; - if (strokeText.length === 4) strokeText = strokeText.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); - this.strokeColor = opacityMask | parseInt(strokeText.substring(1), 16) & 16777215 - } else if (strokeText.indexOf("rgb") === 0) { - this.stroke = true; - this.strokeColor = opacityMask | this.parseRGB(strokeText) - } else if (strokeText.indexOf("url(#") === 0) this.strokeName = strokeText.substring(5, strokeText.length - 1); - else if (colors[strokeText]) { - this.stroke = true; - this.strokeColor = opacityMask | parseInt(colors[strokeText].substring(1), 16) & 16777215 - } - }; - PShapeSVG.prototype.setStrokeWeight = function(weight) { - this.strokeWeight = this.parseUnitSize(weight) - }; - PShapeSVG.prototype.setStrokeJoin = function(linejoin) { - if (linejoin === "miter") this.strokeJoin = 'miter'; - else if (linejoin === "round") this.strokeJoin = 'round'; - else if (linejoin === "bevel") this.strokeJoin = 'bevel' - }; - PShapeSVG.prototype.setStrokeCap = function(linecap) { - if (linecap === "butt") this.strokeCap = 'butt'; - else if (linecap === "round") this.strokeCap = 'round'; - else if (linecap === "square") this.strokeCap = 'square' - }; - PShapeSVG.prototype.setStrokeOpacity = function(opacityText) { - this.strokeOpacity = parseFloat(opacityText); - this.strokeColor = this.strokeOpacity * 255 << 24 | this.strokeColor & 16777215 - }; - PShapeSVG.prototype.parseRGB = function(color) { - var sub = color.substring(color.indexOf("(") + 1, color.indexOf(")")); - var values = sub.split(", "); - return values[0] << 16 | values[1] << 8 | values[2] - }; - PShapeSVG.prototype.parseUnitSize = function(text) { - var len = text.length - 2; - if (len < 0) return text; - if (text.indexOf("pt") === len) return parseFloat(text.substring(0, len)) * 1.25; - if (text.indexOf("pc") === len) return parseFloat(text.substring(0, len)) * 15; - if (text.indexOf("mm") === len) return parseFloat(text.substring(0, len)) * 3.543307; - if (text.indexOf("cm") === len) return parseFloat(text.substring(0, len)) * 35.43307; - if (text.indexOf("in") === len) return parseFloat(text.substring(0, len)) * 90; - if (text.indexOf("px") === len) return parseFloat(text.substring(0, len)); - return parseFloat(text) - }; - p.shape = function(shape, x, y, width, height) { - if (arguments.length >= 1 && arguments[0] !== null) if (shape.isVisible()) { - p.pushMatrix(); - if (curShapeMode === 3) if (arguments.length === 5) { - p.translate(x - width / 2, y - height / 2); - p.scale(width / shape.getWidth(), height / shape.getHeight()) - } else if (arguments.length === 3) p.translate(x - shape.getWidth() / 2, -shape.getHeight() / 2); - else p.translate(-shape.getWidth() / 2, -shape.getHeight() / 2); - else if (curShapeMode === 0) if (arguments.length === 5) { - p.translate(x, y); - p.scale(width / shape.getWidth(), height / shape.getHeight()) - } else { - if (arguments.length === 3) p.translate(x, y) - } else if (curShapeMode === 1) if (arguments.length === 5) { - width -= x; - height -= y; - p.translate(x, y); - p.scale(width / shape.getWidth(), height / shape.getHeight()) - } else if (arguments.length === 3) p.translate(x, y); - shape.draw(p); - if (arguments.length === 1 && curShapeMode === 3 || arguments.length > 1) p.popMatrix() - } - }; - p.shapeMode = function(mode) { - curShapeMode = mode - }; - p.loadShape = function(filename) { - if (arguments.length === 1) if (filename.indexOf(".svg") > -1) return new PShapeSVG(null, filename); - return null - }; - var XMLAttribute = function(fname, n, nameSpace, v, t) { - this.fullName = fname || ""; - this.name = n || ""; - this.namespace = nameSpace || ""; - this.value = v; - this.type = t - }; - XMLAttribute.prototype = { - getName: function() { - return this.name - }, - getFullName: function() { - return this.fullName - }, - getNamespace: function() { - return this.namespace - }, - getValue: function() { - return this.value - }, - getType: function() { - return this.type - }, - setValue: function(newval) { - this.value = newval - } - }; - var XMLElement = p.XMLElement = function(selector, uri, sysid, line) { - this.attributes = []; - this.children = []; - this.fullName = null; - this.name = null; - this.namespace = ""; - this.content = null; - this.parent = null; - this.lineNr = ""; - this.systemID = ""; - this.type = "ELEMENT"; - if (selector) if (typeof selector === "string") if (uri === undef && selector.indexOf("<") > -1) this.parse(selector); - else { - this.fullName = selector; - this.namespace = uri; - this.systemId = sysid; - this.lineNr = line - } else this.parse(uri) - }; - XMLElement.prototype = { - parse: function(textstring) { - var xmlDoc; - try { - var extension = textstring.substring(textstring.length - 4); - if (extension === ".xml" || extension === ".svg") textstring = ajax(textstring); - xmlDoc = (new DOMParser).parseFromString(textstring, "text/xml"); - var elements = xmlDoc.documentElement; - if (elements) this.parseChildrenRecursive(null, elements); - else throw "Error loading document"; - return this - } catch(e) { - throw e; - } - }, - parseChildrenRecursive: function(parent, elementpath) { - var xmlelement, xmlattribute, tmpattrib, l, m, child; - if (!parent) { - this.fullName = elementpath.localName; - this.name = elementpath.nodeName; - xmlelement = this - } else { - xmlelement = new XMLElement(elementpath.nodeName); - xmlelement.parent = parent - } - if (elementpath.nodeType === 3 && elementpath.textContent !== "") return this.createPCDataElement(elementpath.textContent); - if (elementpath.nodeType === 4) return this.createCDataElement(elementpath.textContent); - if (elementpath.attributes) for (l = 0, m = elementpath.attributes.length; l < m; l++) { - tmpattrib = elementpath.attributes[l]; - xmlattribute = new XMLAttribute(tmpattrib.getname, tmpattrib.nodeName, tmpattrib.namespaceURI, tmpattrib.nodeValue, tmpattrib.nodeType); - xmlelement.attributes.push(xmlattribute) - } - if (elementpath.childNodes) for (l = 0, m = elementpath.childNodes.length; l < m; l++) { - var node = elementpath.childNodes[l]; - child = xmlelement.parseChildrenRecursive(xmlelement, node); - if (child !== null) xmlelement.children.push(child) - } - return xmlelement - }, - createElement: function(fullname, namespaceuri, sysid, line) { - if (sysid === undef) return new XMLElement(fullname, namespaceuri); - return new XMLElement(fullname, namespaceuri, sysid, line) - }, - createPCDataElement: function(content, isCDATA) { - if (content.replace(/^\s+$/g, "") === "") return null; - var pcdata = new XMLElement; - pcdata.type = "TEXT"; - pcdata.content = content; - return pcdata - }, - createCDataElement: function(content) { - var cdata = this.createPCDataElement(content); - if (cdata === null) return null; - cdata.type = "CDATA"; - var htmlentities = { - "<": "<", - ">": ">", - "'": "'", - '"': """ - }, - entity; - for (entity in htmlentities) if (!Object.hasOwnProperty(htmlentities, entity)) content = content.replace(new RegExp(entity, "g"), htmlentities[entity]); - cdata.cdata = content; - return cdata - }, - hasAttribute: function() { - if (arguments.length === 1) return this.getAttribute(arguments[0]) !== null; - if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]) !== null - }, - equals: function(other) { - if (! (other instanceof XMLElement)) return false; - var i, j; - if (this.fullName !== other.fullName) return false; - if (this.attributes.length !== other.getAttributeCount()) return false; - if (this.attributes.length !== other.attributes.length) return false; - var attr_name, attr_ns, attr_value, attr_type, attr_other; - for (i = 0, j = this.attributes.length; i < j; i++) { - attr_name = this.attributes[i].getName(); - attr_ns = this.attributes[i].getNamespace(); - attr_other = other.findAttribute(attr_name, attr_ns); - if (attr_other === null) return false; - if (this.attributes[i].getValue() !== attr_other.getValue()) return false; - if (this.attributes[i].getType() !== attr_other.getType()) return false - } - if (this.children.length !== other.getChildCount()) return false; - if (this.children.length > 0) { - var child1, child2; - for (i = 0, j = this.children.length; i < j; i++) { - child1 = this.getChild(i); - child2 = other.getChild(i); - if (!child1.equals(child2)) return false - } - return true - } - return this.content === other.content - }, - getContent: function() { - if (this.type === "TEXT" || this.type === "CDATA") return this.content; - var children = this.children; - if (children.length === 1 && (children[0].type === "TEXT" || children[0].type === "CDATA")) return children[0].content; - return null - }, - getAttribute: function() { - var attribute; - if (arguments.length === 2) { - attribute = this.findAttribute(arguments[0]); - if (attribute) return attribute.getValue(); - return arguments[1] - } else if (arguments.length === 1) { - attribute = this.findAttribute(arguments[0]); - if (attribute) return attribute.getValue(); - return null - } else if (arguments.length === 3) { - attribute = this.findAttribute(arguments[0], arguments[1]); - if (attribute) return attribute.getValue(); - return arguments[2] - } - }, - getStringAttribute: function() { - if (arguments.length === 1) return this.getAttribute(arguments[0]); - if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); - return this.getAttribute(arguments[0], arguments[1], arguments[2]) - }, - getString: function(attributeName) { - return this.getStringAttribute(attributeName) - }, - getFloatAttribute: function() { - if (arguments.length === 1) return parseFloat(this.getAttribute(arguments[0], 0)); - if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); - return this.getAttribute(arguments[0], arguments[1], arguments[2]) - }, - getFloat: function(attributeName) { - return this.getFloatAttribute(attributeName) - }, - getIntAttribute: function() { - if (arguments.length === 1) return this.getAttribute(arguments[0], 0); - if (arguments.length === 2) return this.getAttribute(arguments[0], arguments[1]); - return this.getAttribute(arguments[0], arguments[1], arguments[2]) - }, - getInt: function(attributeName) { - return this.getIntAttribute(attributeName) - }, - hasChildren: function() { - return this.children.length > 0 - }, - addChild: function(child) { - if (child !== null) { - child.parent = this; - this.children.push(child) - } - }, - insertChild: function(child, index) { - if (child) { - if (child.getLocalName() === null && !this.hasChildren()) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild.getLocalName() === null) { - lastChild.setContent(lastChild.getContent() + child.getContent()); - return - } - } - child.parent = this; - this.children.splice(index, 0, child) - } - }, - getChild: function(selector) { - if (typeof selector === "number") return this.children[selector]; - if (selector.indexOf("/") !== -1) return this.getChildRecursive(selector.split("/"), 0); - var kid, kidName; - for (var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === selector) return kid - } - return null - }, - getChildren: function() { - if (arguments.length === 1) { - if (typeof arguments[0] === "number") return this.getChild(arguments[0]); - if (arguments[0].indexOf("/") !== -1) return this.getChildrenRecursive(arguments[0].split("/"), 0); - var matches = []; - var kid, kidName; - for (var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === arguments[0]) matches.push(kid) - } - return matches - } - return this.children - }, - getChildCount: function() { - return this.children.length - }, - getChildRecursive: function(items, offset) { - if (offset === items.length) return this; - var kid, kidName, matchName = items[offset]; - for (var i = 0, j = this.getChildCount(); i < j; i++) { - kid = this.getChild(i); - kidName = kid.getName(); - if (kidName !== null && kidName === matchName) return kid.getChildRecursive(items, offset + 1) - } - return null - }, - getChildrenRecursive: function(items, offset) { - if (offset === items.length - 1) return this.getChildren(items[offset]); - var matches = this.getChildren(items[offset]); - var kidMatches = []; - for (var i = 0; i < matches.length; i++) kidMatches = kidMatches.concat(matches[i].getChildrenRecursive(items, offset + 1)); - return kidMatches - }, - isLeaf: function() { - return !this.hasChildren() - }, - listChildren: function() { - var arr = []; - for (var i = 0, j = this.children.length; i < j; i++) arr.push(this.getChild(i).getName()); - return arr - }, - removeAttribute: function(name, namespace) { - this.namespace = namespace || ""; - for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) { - this.attributes.splice(i, 1); - break - } - }, - removeChild: function(child) { - if (child) for (var i = 0, j = this.children.length; i < j; i++) if (this.children[i].equals(child)) { - this.children.splice(i, 1); - break - } - }, - removeChildAtIndex: function(index) { - if (this.children.length > index) this.children.splice(index, 1) - }, - findAttribute: function(name, namespace) { - this.namespace = namespace || ""; - for (var i = 0, j = this.attributes.length; i < j; i++) if (this.attributes[i].getName() === name && this.attributes[i].getNamespace() === this.namespace) return this.attributes[i]; - return null - }, - setAttribute: function() { - var attr; - if (arguments.length === 3) { - var index = arguments[0].indexOf(":"); - var name = arguments[0].substring(index + 1); - attr = this.findAttribute(name, arguments[1]); - if (attr) attr.setValue(arguments[2]); - else { - attr = new XMLAttribute(arguments[0], name, arguments[1], arguments[2], "CDATA"); - this.attributes.push(attr) - } - } else { - attr = this.findAttribute(arguments[0]); - if (attr) attr.setValue(arguments[1]); - else { - attr = new XMLAttribute(arguments[0], arguments[0], null, arguments[1], "CDATA"); - this.attributes.push(attr) - } - } - }, - setString: function(attribute, value) { - this.setAttribute(attribute, value) - }, - setInt: function(attribute, value) { - this.setAttribute(attribute, value) - }, - setFloat: function(attribute, value) { - this.setAttribute(attribute, value) - }, - setContent: function(content) { - if (this.children.length > 0) Processing.debug("Tried to set content for XMLElement with children"); - this.content = content - }, - setName: function() { - if (arguments.length === 1) { - this.name = arguments[0]; - this.fullName = arguments[0]; - this.namespace = null - } else { - var index = arguments[0].indexOf(":"); - if (arguments[1] === null || index < 0) this.name = arguments[0]; - else this.name = arguments[0].substring(index + 1); - this.fullName = arguments[0]; - this.namespace = arguments[1] - } - }, - getName: function() { - return this.fullName - }, - getLocalName: function() { - return this.name - }, - getAttributeCount: function() { - return this.attributes.length - }, - toString: function() { - if (this.type === "TEXT") return this.content; - if (this.type === "CDATA") return this.cdata; - var tagstring = this.fullName; - var xmlstring = "<" + tagstring; - var a, c; - for (a = 0; a < this.attributes.length; a++) { - var attr = this.attributes[a]; - xmlstring += " " + attr.getName() + "=" + '"' + attr.getValue() + '"' - } - if (this.children.length === 0) if (this.content === "") xmlstring += "/>"; - else xmlstring += ">" + this.content + ""; - else { - xmlstring += ">"; - for (c = 0; c < this.children.length; c++) xmlstring += this.children[c].toString(); - xmlstring += "" - } - return xmlstring - } - }; - XMLElement.parse = function(xmlstring) { - var element = new XMLElement; - element.parse(xmlstring); - return element - }; - var XML = p.XML = p.XMLElement; - p.loadXML = function(uri) { - return new XML(p, uri) - }; - var printMatrixHelper = function(elements) { - var big = 0; - for (var i = 0; i < elements.length; i++) if (i !== 0) big = Math.max(big, Math.abs(elements[i])); - else big = Math.abs(elements[i]); - var digits = (big + "").indexOf("."); - if (digits === 0) digits = 1; - else if (digits === -1) digits = (big + "").length; - return digits - }; - var PMatrix2D = p.PMatrix2D = function() { - if (arguments.length === 0) this.reset(); - else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this.set(arguments[0].array()); - else if (arguments.length === 6) this.set(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]) - }; - PMatrix2D.prototype = { - set: function() { - if (arguments.length === 6) { - var a = arguments; - this.set([a[0], a[1], a[2], a[3], a[4], a[5]]) - } else if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) this.elements = arguments[0].array(); - else if (arguments.length === 1 && arguments[0] instanceof Array) this.elements = arguments[0].slice() - }, - get: function() { - var outgoing = new PMatrix2D; - outgoing.set(this.elements); - return outgoing - }, - reset: function() { - this.set([1, 0, 0, 0, 1, 0]) - }, - array: function array() { - return this.elements.slice() - }, - translate: function(tx, ty) { - this.elements[2] = tx * this.elements[0] + ty * this.elements[1] + this.elements[2]; - this.elements[5] = tx * this.elements[3] + ty * this.elements[4] + this.elements[5] - }, - invTranslate: function(tx, ty) { - this.translate(-tx, -ty) - }, - transpose: function() {}, - mult: function(source, target) { - var x, y; - if (source instanceof - PVector) { - x = source.x; - y = source.y; - if (!target) target = new PVector - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - if (!target) target = [] - } - if (target instanceof Array) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target[1] = this.elements[3] * x + this.elements[4] * y + this.elements[5] - } else if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2]; - target.y = this.elements[3] * x + this.elements[4] * y + this.elements[5]; - target.z = 0 - } - return target - }, - multX: function(x, y) { - return x * this.elements[0] + y * this.elements[1] + this.elements[2] - }, - multY: function(x, y) { - return x * this.elements[3] + y * this.elements[4] + this.elements[5] - }, - skewX: function(angle) { - this.apply(1, 0, 1, angle, 0, 0) - }, - skewY: function(angle) { - this.apply(1, 0, 1, 0, angle, 0) - }, - shearX: function(angle) { - this.apply(1, 0, 1, Math.tan(angle), 0, 0) - }, - shearY: function(angle) { - this.apply(1, 0, 1, 0, Math.tan(angle), 0) - }, - determinant: function() { - return this.elements[0] * this.elements[4] - this.elements[1] * this.elements[3] - }, - invert: function() { - var d = this.determinant(); - if (Math.abs(d) > -2147483648) { - var old00 = this.elements[0]; - var old01 = this.elements[1]; - var old02 = this.elements[2]; - var old10 = this.elements[3]; - var old11 = this.elements[4]; - var old12 = this.elements[5]; - this.elements[0] = old11 / d; - this.elements[3] = -old10 / d; - this.elements[1] = -old01 / d; - this.elements[4] = old00 / d; - this.elements[2] = (old01 * old12 - old11 * old02) / d; - this.elements[5] = (old10 * old02 - old00 * old12) / d; - return true - } - return false - }, - scale: function(sx, sy) { - if (sx && !sy) sy = sx; - if (sx && sy) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[3] *= sx; - this.elements[4] *= sy - } - }, - invScale: function(sx, sy) { - if (sx && !sy) sy = sx; - this.scale(1 / sx, 1 / sy) - }, - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array(); - else if (arguments.length === 6) source = Array.prototype.slice.call(arguments); - else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; - var result = [0, 0, this.elements[2], 0, 0, this.elements[5]]; - var e = 0; - for (var row = 0; row < 2; row++) for (var col = 0; col < 3; col++, e++) result[e] += this.elements[row * 3 + 0] * source[col + 0] + this.elements[row * 3 + 1] * source[col + 3]; - this.elements = result.slice() - }, - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix2D) source = arguments[0].array(); - else if (arguments.length === 6) source = Array.prototype.slice.call(arguments); - else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; - var result = [0, 0, source[2], 0, 0, source[5]]; - result[2] = source[2] + this.elements[2] * source[0] + this.elements[5] * source[1]; - result[5] = source[5] + this.elements[2] * source[3] + this.elements[5] * source[4]; - result[0] = this.elements[0] * source[0] + this.elements[3] * source[1]; - result[3] = this.elements[0] * source[3] + this.elements[3] * source[4]; - result[1] = this.elements[1] * source[0] + this.elements[4] * source[1]; - result[4] = this.elements[1] * source[3] + this.elements[4] * source[4]; - this.elements = result.slice() - }, - rotate: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - var temp1 = this.elements[0]; - var temp2 = this.elements[1]; - this.elements[0] = c * temp1 + s * temp2; - this.elements[1] = -s * temp1 + c * temp2; - temp1 = this.elements[3]; - temp2 = this.elements[4]; - this.elements[3] = c * temp1 + s * temp2; - this.elements[4] = -s * temp1 + c * temp2 - }, - rotateZ: function(angle) { - this.rotate(angle) - }, - invRotateZ: function(angle) { - this.rotateZ(angle - Math.PI) - }, - print: function() { - var digits = printMatrixHelper(this.elements); - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + "\n" + p.nfs(this.elements[3], digits, 4) + " " + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + "\n\n"; - p.println(output) - } - }; - var PMatrix3D = p.PMatrix3D = function() { - this.reset() - }; - PMatrix3D.prototype = { - set: function() { - if (arguments.length === 16) this.elements = Array.prototype.slice.call(arguments); - else if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) this.elements = arguments[0].array(); - else if (arguments.length === 1 && arguments[0] instanceof Array) this.elements = arguments[0].slice() - }, - get: function() { - var outgoing = new PMatrix3D; - outgoing.set(this.elements); - return outgoing - }, - reset: function() { - this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] - }, - array: function array() { - return this.elements.slice() - }, - translate: function(tx, ty, tz) { - if (tz === undef) tz = 0; - this.elements[3] += tx * this.elements[0] + ty * this.elements[1] + tz * this.elements[2]; - this.elements[7] += tx * this.elements[4] + ty * this.elements[5] + tz * this.elements[6]; - this.elements[11] += tx * this.elements[8] + ty * this.elements[9] + tz * this.elements[10]; - this.elements[15] += tx * this.elements[12] + ty * this.elements[13] + tz * this.elements[14] - }, - transpose: function() { - var temp = this.elements[4]; - this.elements[4] = this.elements[1]; - this.elements[1] = temp; - temp = this.elements[8]; - this.elements[8] = this.elements[2]; - this.elements[2] = temp; - temp = this.elements[6]; - this.elements[6] = this.elements[9]; - this.elements[9] = temp; - temp = this.elements[3]; - this.elements[3] = this.elements[12]; - this.elements[12] = temp; - temp = this.elements[7]; - this.elements[7] = this.elements[13]; - this.elements[13] = temp; - temp = this.elements[11]; - this.elements[11] = this.elements[14]; - this.elements[14] = temp - }, - mult: function(source, target) { - var x, y, z, w; - if (source instanceof - PVector) { - x = source.x; - y = source.y; - z = source.z; - w = 1; - if (!target) target = new PVector - } else if (source instanceof Array) { - x = source[0]; - y = source[1]; - z = source[2]; - w = source[3] || 1; - if (!target || target.length !== 3 && target.length !== 4) target = [0, 0, 0] - } - if (target instanceof Array) if (target.length === 3) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] - } else if (target.length === 4) { - target[0] = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w; - target[1] = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w; - target[2] = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w; - target[3] = this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w - } - if (target instanceof PVector) { - target.x = this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - target.y = this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - target.z = this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] - } - return target - }, - preApply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); - else if (arguments.length === 16) source = Array.prototype.slice.call(arguments); - else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; - var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[col + 0] * source[row * 4 + 0] + this.elements[col + 4] * source[row * 4 + 1] + this.elements[col + 8] * source[row * 4 + 2] + this.elements[col + 12] * source[row * 4 + 3]; - this.elements = result.slice() - }, - apply: function() { - var source; - if (arguments.length === 1 && arguments[0] instanceof PMatrix3D) source = arguments[0].array(); - else if (arguments.length === 16) source = Array.prototype.slice.call(arguments); - else if (arguments.length === 1 && arguments[0] instanceof Array) source = arguments[0]; - var result = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - var e = 0; - for (var row = 0; row < 4; row++) for (var col = 0; col < 4; col++, e++) result[e] += this.elements[row * 4 + 0] * source[col + 0] + this.elements[row * 4 + 1] * source[col + 4] + this.elements[row * 4 + 2] * source[col + 8] + this.elements[row * 4 + 3] * source[col + 12]; - this.elements = result.slice() - }, - rotate: function(angle, v0, v1, v2) { - if (!v1) this.rotateZ(angle); - else { - var c = p.cos(angle); - var s = p.sin(angle); - var t = 1 - c; - this.apply(t * v0 * v0 + c, t * v0 * v1 - s * v2, t * v0 * v2 + s * v1, 0, t * v0 * v1 + s * v2, t * v1 * v1 + c, t * v1 * v2 - s * v0, 0, t * v0 * v2 - s * v1, t * v1 * v2 + s * v0, t * v2 * v2 + c, 0, 0, 0, 0, 1) - } - }, - invApply: function() { - if (inverseCopy === undef) inverseCopy = new PMatrix3D; - var a = arguments; - inverseCopy.set(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - if (!inverseCopy.invert()) return false; - this.preApply(inverseCopy); - return true - }, - rotateX: function(angle) { - var c = p.cos(angle); - var s = p.sin(angle); - this.apply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) - }, - rotateY: function(angle) { - var c = p.cos(angle); - var s = p.sin(angle); - this.apply([c, - 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) - }, - rotateZ: function(angle) { - var c = Math.cos(angle); - var s = Math.sin(angle); - this.apply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) - }, - scale: function(sx, sy, sz) { - if (sx && !sy && !sz) sy = sz = sx; - else if (sx && sy && !sz) sz = 1; - if (sx && sy && sz) { - this.elements[0] *= sx; - this.elements[1] *= sy; - this.elements[2] *= sz; - this.elements[4] *= sx; - this.elements[5] *= sy; - this.elements[6] *= sz; - this.elements[8] *= sx; - this.elements[9] *= sy; - this.elements[10] *= sz; - this.elements[12] *= sx; - this.elements[13] *= sy; - this.elements[14] *= sz - } - }, - skewX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) - }, - skewY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) - }, - shearX: function(angle) { - var t = Math.tan(angle); - this.apply(1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) - }, - shearY: function(angle) { - var t = Math.tan(angle); - this.apply(1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) - }, - multX: function(x, y, z, w) { - if (!z) return this.elements[0] * x + this.elements[1] * y + this.elements[3]; - if (!w) return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3]; - return this.elements[0] * x + this.elements[1] * y + this.elements[2] * z + this.elements[3] * w - }, - multY: function(x, y, z, w) { - if (!z) return this.elements[4] * x + this.elements[5] * y + this.elements[7]; - if (!w) return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7]; - return this.elements[4] * x + this.elements[5] * y + this.elements[6] * z + this.elements[7] * w - }, - multZ: function(x, y, z, w) { - if (!w) return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11]; - return this.elements[8] * x + this.elements[9] * y + this.elements[10] * z + this.elements[11] * w - }, - multW: function(x, y, z, w) { - if (!w) return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15]; - return this.elements[12] * x + this.elements[13] * y + this.elements[14] * z + this.elements[15] * w - }, - invert: function() { - var fA0 = this.elements[0] * this.elements[5] - this.elements[1] * this.elements[4]; - var fA1 = this.elements[0] * this.elements[6] - this.elements[2] * this.elements[4]; - var fA2 = this.elements[0] * this.elements[7] - this.elements[3] * this.elements[4]; - var fA3 = this.elements[1] * this.elements[6] - this.elements[2] * this.elements[5]; - var fA4 = this.elements[1] * this.elements[7] - this.elements[3] * this.elements[5]; - var fA5 = this.elements[2] * this.elements[7] - this.elements[3] * this.elements[6]; - var fB0 = this.elements[8] * this.elements[13] - this.elements[9] * this.elements[12]; - var fB1 = this.elements[8] * this.elements[14] - this.elements[10] * this.elements[12]; - var fB2 = this.elements[8] * this.elements[15] - this.elements[11] * this.elements[12]; - var fB3 = this.elements[9] * this.elements[14] - this.elements[10] * this.elements[13]; - var fB4 = this.elements[9] * this.elements[15] - this.elements[11] * this.elements[13]; - var fB5 = this.elements[10] * this.elements[15] - this.elements[11] * this.elements[14]; - var fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; - if (Math.abs(fDet) <= 1.0E-9) return false; - var kInv = []; - kInv[0] = +this.elements[5] * fB5 - this.elements[6] * fB4 + this.elements[7] * fB3; - kInv[4] = -this.elements[4] * fB5 + this.elements[6] * fB2 - this.elements[7] * fB1; - kInv[8] = +this.elements[4] * fB4 - this.elements[5] * fB2 + this.elements[7] * fB0; - kInv[12] = -this.elements[4] * fB3 + this.elements[5] * fB1 - this.elements[6] * fB0; - kInv[1] = -this.elements[1] * fB5 + this.elements[2] * fB4 - this.elements[3] * fB3; - kInv[5] = +this.elements[0] * fB5 - this.elements[2] * fB2 + this.elements[3] * fB1; - kInv[9] = -this.elements[0] * fB4 + this.elements[1] * fB2 - this.elements[3] * fB0; - kInv[13] = +this.elements[0] * fB3 - this.elements[1] * fB1 + this.elements[2] * fB0; - kInv[2] = +this.elements[13] * fA5 - this.elements[14] * fA4 + this.elements[15] * fA3; - kInv[6] = -this.elements[12] * fA5 + this.elements[14] * fA2 - this.elements[15] * fA1; - kInv[10] = +this.elements[12] * fA4 - this.elements[13] * fA2 + this.elements[15] * fA0; - kInv[14] = -this.elements[12] * fA3 + this.elements[13] * fA1 - this.elements[14] * fA0; - kInv[3] = -this.elements[9] * fA5 + this.elements[10] * fA4 - this.elements[11] * fA3; - kInv[7] = +this.elements[8] * fA5 - this.elements[10] * fA2 + this.elements[11] * fA1; - kInv[11] = -this.elements[8] * fA4 + this.elements[9] * fA2 - this.elements[11] * fA0; - kInv[15] = +this.elements[8] * fA3 - this.elements[9] * fA1 + this.elements[10] * fA0; - var fInvDet = 1 / fDet; - kInv[0] *= fInvDet; - kInv[1] *= fInvDet; - kInv[2] *= fInvDet; - kInv[3] *= fInvDet; - kInv[4] *= fInvDet; - kInv[5] *= fInvDet; - kInv[6] *= fInvDet; - kInv[7] *= fInvDet; - kInv[8] *= fInvDet; - kInv[9] *= fInvDet; - kInv[10] *= fInvDet; - kInv[11] *= fInvDet; - kInv[12] *= fInvDet; - kInv[13] *= fInvDet; - kInv[14] *= fInvDet; - kInv[15] *= fInvDet; - this.elements = kInv.slice(); - return true - }, - toString: function() { - var str = ""; - for (var i = 0; i < 15; i++) str += this.elements[i] + ", "; - str += this.elements[15]; - return str - }, - print: function() { - var digits = printMatrixHelper(this.elements); - var output = "" + p.nfs(this.elements[0], digits, 4) + " " + p.nfs(this.elements[1], digits, 4) + " " + p.nfs(this.elements[2], digits, 4) + " " + p.nfs(this.elements[3], digits, 4) + "\n" + p.nfs(this.elements[4], digits, 4) + " " + p.nfs(this.elements[5], digits, 4) + " " + p.nfs(this.elements[6], digits, 4) + " " + p.nfs(this.elements[7], digits, 4) + "\n" + p.nfs(this.elements[8], digits, 4) + " " + p.nfs(this.elements[9], digits, 4) + " " + p.nfs(this.elements[10], digits, 4) + " " + p.nfs(this.elements[11], digits, 4) + "\n" + p.nfs(this.elements[12], digits, 4) + " " + p.nfs(this.elements[13], digits, 4) + " " + p.nfs(this.elements[14], digits, 4) + " " + p.nfs(this.elements[15], digits, 4) + "\n\n"; - p.println(output) - }, - invTranslate: function(tx, ty, tz) { - this.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1) - }, - invRotateX: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1]) - }, - invRotateY: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1]) - }, - invRotateZ: function(angle) { - var c = Math.cos(-angle); - var s = Math.sin(-angle); - this.preApply([c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) - }, - invScale: function(x, y, z) { - this.preApply([1 / x, 0, 0, 0, 0, 1 / y, 0, 0, 0, 0, 1 / z, 0, 0, 0, 0, 1]) - } - }; - var PMatrixStack = p.PMatrixStack = function() { - this.matrixStack = [] - }; - PMatrixStack.prototype.load = function() { - var tmpMatrix = drawing.$newPMatrix(); - if (arguments.length === 1) tmpMatrix.set(arguments[0]); - else tmpMatrix.set(arguments); - this.matrixStack.push(tmpMatrix) - }; - Drawing2D.prototype.$newPMatrix = function() { - return new PMatrix2D - }; - Drawing3D.prototype.$newPMatrix = function() { - return new PMatrix3D - }; - PMatrixStack.prototype.push = function() { - this.matrixStack.push(this.peek()) - }; - PMatrixStack.prototype.pop = function() { - return this.matrixStack.pop() - }; - PMatrixStack.prototype.peek = function() { - var tmpMatrix = drawing.$newPMatrix(); - tmpMatrix.set(this.matrixStack[this.matrixStack.length - 1]); - return tmpMatrix - }; - PMatrixStack.prototype.mult = function(matrix) { - this.matrixStack[this.matrixStack.length - 1].apply(matrix) - }; - p.split = function(str, delim) { - return str.split(delim) - }; - p.splitTokens = function(str, tokens) { - if (tokens === undef) return str.split(/\s+/g); - var chars = tokens.split(/()/g), - buffer = "", - len = str.length, - i, c, tokenized = []; - for (i = 0; i < len; i++) { - c = str[i]; - if (chars.indexOf(c) > -1) { - if (buffer !== "") tokenized.push(buffer); - buffer = "" - } else buffer += c - } - if (buffer !== "") tokenized.push(buffer); - return tokenized - }; - p.append = function(array, element) { - array[array.length] = element; - return array - }; - p.concat = function(array1, array2) { - return array1.concat(array2) - }; - p.sort = function(array, numElem) { - var ret = []; - if (array.length > 0) { - var elemsToCopy = numElem > 0 ? numElem : array.length; - for (var i = 0; i < elemsToCopy; i++) ret.push(array[i]); - if (typeof array[0] === "string") ret.sort(); - else ret.sort(function(a, b) { - return a - b - }); - if (numElem > 0) for (var j = ret.length; j < array.length; j++) ret.push(array[j]) - } - return ret - }; - p.splice = function(array, value, index) { - if (value.length === 0) return array; - if (value instanceof Array) for (var i = 0, j = index; i < value.length; j++, i++) array.splice(j, 0, value[i]); - else array.splice(index, 0, value); - return array - }; - p.subset = function(array, offset, length) { - var end = length !== undef ? offset + length : array.length; - return array.slice(offset, end) - }; - p.join = function(array, seperator) { - return array.join(seperator) - }; - p.shorten = function(ary) { - var newary = []; - var len = ary.length; - for (var i = 0; i < len; i++) newary[i] = ary[i]; - newary.pop(); - return newary - }; - p.expand = function(ary, targetSize) { - var temp = ary.slice(0), - newSize = targetSize || ary.length * 2; - temp.length = newSize; - return temp - }; - p.arrayCopy = function() { - var src, srcPos = 0, - dest, destPos = 0, - length; - if (arguments.length === 2) { - src = arguments[0]; - dest = arguments[1]; - length = src.length - } else if (arguments.length === 3) { - src = arguments[0]; - dest = arguments[1]; - length = arguments[2] - } else if (arguments.length === 5) { - src = arguments[0]; - srcPos = arguments[1]; - dest = arguments[2]; - destPos = arguments[3]; - length = arguments[4] - } - for (var i = srcPos, j = destPos; i < length + srcPos; i++, j++) if (dest[j] !== undef) dest[j] = src[i]; - else throw "array index out of bounds exception"; - }; - p.reverse = function(array) { - return array.reverse() - }; - p.mix = function(a, b, f) { - return a + ((b - a) * f >> 8) - }; - p.peg = function(n) { - return n < 0 ? 0 : n > 255 ? 255 : n - }; - p.modes = function() { - var ALPHA_MASK = 4278190080, - RED_MASK = 16711680, - GREEN_MASK = 65280, - BLUE_MASK = 255, - min = Math.min, - max = Math.max; - - function applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) { - var a = min(((c1 & 4278190080) >>> 24) + f, 255) << 24; - var r = ar + ((cr - ar) * f >> 8); - r = (r < 0 ? 0 : r > 255 ? 255 : r) << 16; - var g = ag + ((cg - ag) * f >> 8); - g = (g < 0 ? 0 : g > 255 ? 255 : g) << 8; - var b = ab + ((cb - ab) * f >> 8); - b = b < 0 ? 0 : b > 255 ? 255 : b; - return a | r | g | b - } - return { - replace: function(c1, c2) { - return c2 - }, - blend: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = c1 & RED_MASK, - ag = c1 & GREEN_MASK, - ab = c1 & BLUE_MASK, - br = c2 & RED_MASK, - bg = c2 & GREEN_MASK, - bb = c2 & BLUE_MASK; - return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab) * f >> 8) & BLUE_MASK - }, - add: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | min((c1 & RED_MASK) + ((c2 & RED_MASK) >> 8) * f, RED_MASK) & RED_MASK | min((c1 & GREEN_MASK) + ((c2 & GREEN_MASK) >> 8) * f, GREEN_MASK) & GREEN_MASK | min((c1 & BLUE_MASK) + ((c2 & BLUE_MASK) * f >> 8), BLUE_MASK) - }, - subtract: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max((c1 & RED_MASK) - ((c2 & RED_MASK) >> 8) * f, GREEN_MASK) & RED_MASK | max((c1 & GREEN_MASK) - ((c2 & GREEN_MASK) >> 8) * f, BLUE_MASK) & GREEN_MASK | max((c1 & BLUE_MASK) - ((c2 & BLUE_MASK) * f >> 8), 0) - }, - lightest: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24; - return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | max(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f) & RED_MASK | max(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f) & GREEN_MASK | max(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8) - }, - darkest: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = c1 & RED_MASK, - ag = c1 & GREEN_MASK, - ab = c1 & BLUE_MASK, - br = min(c1 & RED_MASK, ((c2 & RED_MASK) >> 8) * f), - bg = min(c1 & GREEN_MASK, ((c2 & GREEN_MASK) >> 8) * f), - bb = min(c1 & BLUE_MASK, (c2 & BLUE_MASK) * f >> 8); - return min(((c1 & ALPHA_MASK) >>> 24) + f, 255) << 24 | ar + ((br - ar) * f >> 8) & RED_MASK | ag + ((bg - ag) * f >> 8) & GREEN_MASK | ab + ((bb - ab) * f >> 8) & BLUE_MASK - }, - difference: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = ar > br ? ar - br : br - ar, - cg = ag > bg ? ag - bg : bg - ag, - cb = ab > bb ? ab - bb : bb - ab; - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - exclusion: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = ar + br - (ar * br >> 7), - cg = ag + bg - (ag * bg >> 7), - cb = ab + bb - (ab * bb >> 7); - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - multiply: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = ar * br >> 8, - cg = ag * bg >> 8, - cb = ab * bb >> 8; - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - screen: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = 255 - ((255 - ar) * (255 - br) >> 8), - cg = 255 - ((255 - ag) * (255 - bg) >> 8), - cb = 255 - ((255 - ab) * (255 - bb) >> 8); - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - hard_light: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = br < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), - cg = bg < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), - cb = bb < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - soft_light: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = (ar * br >> 7) + (ar * ar >> 8) - (ar * ar * br >> 15), - cg = (ag * bg >> 7) + (ag * ag >> 8) - (ag * ag * bg >> 15), - cb = (ab * bb >> 7) + (ab * ab >> 8) - (ab * ab * bb >> 15); - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - overlay: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK, - cr = ar < 128 ? ar * br >> 7 : 255 - ((255 - ar) * (255 - br) >> 7), - cg = ag < 128 ? ag * bg >> 7 : 255 - ((255 - ag) * (255 - bg) >> 7), - cb = ab < 128 ? ab * bb >> 7 : 255 - ((255 - ab) * (255 - bb) >> 7); - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - dodge: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK; - var cr = 255; - if (br !== 255) { - cr = (ar << 8) / (255 - br); - cr = cr < 0 ? 0 : cr > 255 ? 255 : cr - } - var cg = 255; - if (bg !== 255) { - cg = (ag << 8) / (255 - bg); - cg = cg < 0 ? 0 : cg > 255 ? 255 : cg - } - var cb = 255; - if (bb !== 255) { - cb = (ab << 8) / (255 - bb); - cb = cb < 0 ? 0 : cb > 255 ? 255 : cb - } - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - }, - burn: function(c1, c2) { - var f = (c2 & ALPHA_MASK) >>> 24, - ar = (c1 & RED_MASK) >> 16, - ag = (c1 & GREEN_MASK) >> 8, - ab = c1 & BLUE_MASK, - br = (c2 & RED_MASK) >> 16, - bg = (c2 & GREEN_MASK) >> 8, - bb = c2 & BLUE_MASK; - var cr = 0; - if (br !== 0) { - cr = (255 - ar << 8) / br; - cr = 255 - (cr < 0 ? 0 : cr > 255 ? 255 : cr) - } - var cg = 0; - if (bg !== 0) { - cg = (255 - ag << 8) / bg; - cg = 255 - (cg < 0 ? 0 : cg > 255 ? 255 : cg) - } - var cb = 0; - if (bb !== 0) { - cb = (255 - ab << 8) / bb; - cb = 255 - (cb < 0 ? 0 : cb > 255 ? 255 : cb) - } - return applyMode(c1, f, ar, ag, ab, br, bg, bb, cr, cg, cb) - } - } - }(); - - function color$4(aValue1, aValue2, aValue3, aValue4) { - var r, g, b, a; - if (curColorMode === 3) { - var rgb = p.color.toRGB(aValue1, aValue2, aValue3); - r = rgb[0]; - g = rgb[1]; - b = rgb[2] - } else { - r = Math.round(255 * (aValue1 / colorModeX)); - g = Math.round(255 * (aValue2 / colorModeY)); - b = Math.round(255 * (aValue3 / colorModeZ)) - } - a = Math.round(255 * (aValue4 / colorModeA)); - r = r < 0 ? 0 : r; - g = g < 0 ? 0 : g; - b = b < 0 ? 0 : b; - a = a < 0 ? 0 : a; - r = r > 255 ? 255 : r; - g = g > 255 ? 255 : g; - b = b > 255 ? 255 : b; - a = a > 255 ? 255 : a; - return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 - } - function color$2(aValue1, aValue2) { - var a; - if (aValue1 & 4278190080) { - a = Math.round(255 * (aValue2 / colorModeA)); - a = a > 255 ? 255 : a; - a = a < 0 ? 0 : a; - return aValue1 - (aValue1 & 4278190080) + (a << 24 & 4278190080) - } - if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, aValue2); - if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colorModeZ, aValue2) - } - function color$1(aValue1) { - if (aValue1 <= colorModeX && aValue1 >= 0) { - if (curColorMode === 1) return color$4(aValue1, aValue1, aValue1, colorModeA); - if (curColorMode === 3) return color$4(0, 0, aValue1 / colorModeX * colorModeZ, colorModeA) - } - if (aValue1) { - if (aValue1 > 2147483647) aValue1 -= 4294967296; - return aValue1 - } - } - p.color = function(aValue1, aValue2, aValue3, aValue4) { - if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef && aValue4 !== undef) return color$4(aValue1, aValue2, aValue3, aValue4); - if (aValue1 !== undef && aValue2 !== undef && aValue3 !== undef) return color$4(aValue1, aValue2, aValue3, colorModeA); - if (aValue1 !== undef && aValue2 !== undef) return color$2(aValue1, aValue2); - if (typeof aValue1 === "number") return color$1(aValue1); - return color$4(colorModeX, colorModeY, colorModeZ, colorModeA) - }; - p.color.toString = function(colorInt) { - return "rgba(" + ((colorInt >> 16) & 255) + "," + ((colorInt >> 8) & 255) + "," + (colorInt & 255) + "," + ((colorInt >> 24) & 255) / 255 + ")" - }; - p.color.toInt = function(r, g, b, a) { - return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 - }; - p.color.toArray = function(colorInt) { - return [(colorInt >> 16) & 255, (colorInt >> 8) & 255, colorInt & 255, (colorInt >> 24) & 255] - }; - p.color.toGLArray = function(colorInt) { - return [((colorInt & 16711680) >>> 16) / 255, ((colorInt >> 8) & 255) / 255, (colorInt & 255) / 255, ((colorInt >> 24) & 255) / 255] - }; - p.color.toRGB = function(h, s, b) { - h = h > colorModeX ? colorModeX : h; - s = s > colorModeY ? colorModeY : s; - b = b > colorModeZ ? colorModeZ : b; - h = h / colorModeX * 360; - s = s / colorModeY * 100; - b = b / colorModeZ * 100; - var br = Math.round(b / 100 * 255); - if (s === 0) return [br, br, br]; - var hue = h % 360; - var f = hue % 60; - var p = Math.round(b * (100 - s) / 1E4 * 255); - var q = Math.round(b * (6E3 - s * f) / 6E5 * 255); - var t = Math.round(b * (6E3 - s * (60 - f)) / 6E5 * 255); - switch (Math.floor(hue / 60)) { - case 0: - return [br, t, p]; - case 1: - return [q, br, p]; - case 2: - return [p, br, t]; - case 3: - return [p, q, br]; - case 4: - return [t, p, br]; - case 5: - return [br, p, q] - } - }; - - function colorToHSB(colorInt) { - var red, green, blue; - red = ((colorInt >> 16) & 255) / 255; - green = ((colorInt >> 8) & 255) / 255; - blue = (colorInt & 255) / 255; - var max = p.max(p.max(red, green), blue), - min = p.min(p.min(red, green), blue), - hue, saturation; - if (min === max) return [0, 0, max * colorModeZ]; - saturation = (max - min) / max; - if (red === max) hue = (green - blue) / (max - min); - else if (green === max) hue = 2 + (blue - red) / (max - min); - else hue = 4 + (red - green) / (max - min); - hue /= 6; - if (hue < 0) hue += 1; - else if (hue > 1) hue -= 1; - return [hue * colorModeX, saturation * colorModeY, max * colorModeZ] - } - p.brightness = function(colInt) { - return colorToHSB(colInt)[2] - }; - p.saturation = function(colInt) { - return colorToHSB(colInt)[1] - }; - p.hue = function(colInt) { - return colorToHSB(colInt)[0] - }; - p.red = function(aColor) { - return ((aColor >> 16) & 255) / 255 * colorModeX - }; - p.green = function(aColor) { - return ((aColor & 65280) >>> 8) / 255 * colorModeY - }; - p.blue = function(aColor) { - return (aColor & 255) / 255 * colorModeZ - }; - p.alpha = function(aColor) { - return ((aColor >> 24) & 255) / 255 * colorModeA - }; - p.lerpColor = function(c1, c2, amt) { - var r, g, b, a, r1, g1, b1, a1, r2, g2, b2, a2; - var hsb1, hsb2, rgb, h, s; - var colorBits1 = p.color(c1); - var colorBits2 = p.color(c2); - if (curColorMode === 3) { - hsb1 = colorToHSB(colorBits1); - a1 = ((colorBits1 >> 24) & 255) / colorModeA; - hsb2 = colorToHSB(colorBits2); - a2 = ((colorBits2 & 4278190080) >>> 24) / colorModeA; - h = p.lerp(hsb1[0], hsb2[0], amt); - s = p.lerp(hsb1[1], hsb2[1], amt); - b = p.lerp(hsb1[2], hsb2[2], amt); - rgb = p.color.toRGB(h, s, b); - a = p.lerp(a1, a2, amt) * colorModeA; - return a << 24 & 4278190080 | (rgb[0] & 255) << 16 | (rgb[1] & 255) << 8 | rgb[2] & 255 - } - r1 = (colorBits1 >> 16) & 255; - g1 = (colorBits1 >> 8) & 255; - b1 = colorBits1 & 255; - a1 = ((colorBits1 >> 24) & 255) / colorModeA; - r2 = (colorBits2 & 16711680) >>> 16; - g2 = (colorBits2 >> 8) & 255; - b2 = colorBits2 & 255; - a2 = ((colorBits2 >> 24) & 255) / colorModeA; - r = p.lerp(r1, r2, amt) | 0; - g = p.lerp(g1, g2, amt) | 0; - b = p.lerp(b1, b2, amt) | 0; - a = p.lerp(a1, a2, amt) * colorModeA; - return a << 24 & 4278190080 | r << 16 & 16711680 | g << 8 & 65280 | b & 255 - }; - p.colorMode = function() { - curColorMode = arguments[0]; - if (arguments.length > 1) { - colorModeX = arguments[1]; - colorModeY = arguments[2] || arguments[1]; - colorModeZ = arguments[3] || arguments[1]; - colorModeA = arguments[4] || arguments[1] - } - }; - p.blendColor = function(c1, c2, mode) { - if (mode === 0) return p.modes.replace(c1, c2); - else if (mode === 1) return p.modes.blend(c1, c2); - else if (mode === 2) return p.modes.add(c1, c2); - else if (mode === 4) return p.modes.subtract(c1, c2); - else if (mode === 8) return p.modes.lightest(c1, c2); - else if (mode === 16) return p.modes.darkest(c1, c2); - else if (mode === 32) return p.modes.difference(c1, c2); - else if (mode === 64) return p.modes.exclusion(c1, c2); - else if (mode === 128) return p.modes.multiply(c1, c2); - else if (mode === 256) return p.modes.screen(c1, c2); - else if (mode === 1024) return p.modes.hard_light(c1, c2); - else if (mode === 2048) return p.modes.soft_light(c1, c2); - else if (mode === 512) return p.modes.overlay(c1, c2); - else if (mode === 4096) return p.modes.dodge(c1, c2); - else if (mode === 8192) return p.modes.burn(c1, c2) - }; - - function saveContext() { - curContext.save() - } - function restoreContext() { - curContext.restore(); - isStrokeDirty = true; - isFillDirty = true - } - p.printMatrix = function() { - modelView.print() - }; - Drawing2D.prototype.translate = function(x, y) { - modelView.translate(x, y); - modelViewInv.invTranslate(x, y); - curContext.translate(x, y) - }; - Drawing3D.prototype.translate = function(x, y, z) { - modelView.translate(x, y, z); - modelViewInv.invTranslate(x, y, z) - }; - Drawing2D.prototype.scale = function(x, y) { - modelView.scale(x, y); - modelViewInv.invScale(x, y); - curContext.scale(x, y || x) - }; - Drawing3D.prototype.scale = function(x, y, z) { - modelView.scale(x, y, z); - modelViewInv.invScale(x, y, z) - }; - Drawing2D.prototype.transform = function(pmatrix) { - var e = pmatrix.array(); - curContext.transform(e[0], e[3], e[1], e[4], e[2], e[5]) - }; - Drawing3D.prototype.transformm = function(pmatrix3d) { - throw "p.transform is currently not supported in 3D mode"; - }; - Drawing2D.prototype.pushMatrix = function() { - userMatrixStack.load(modelView); - userReverseMatrixStack.load(modelViewInv); - saveContext() - }; - Drawing3D.prototype.pushMatrix = function() { - userMatrixStack.load(modelView); - userReverseMatrixStack.load(modelViewInv) - }; - Drawing2D.prototype.popMatrix = function() { - modelView.set(userMatrixStack.pop()); - modelViewInv.set(userReverseMatrixStack.pop()); - restoreContext() - }; - Drawing3D.prototype.popMatrix = function() { - modelView.set(userMatrixStack.pop()); - modelViewInv.set(userReverseMatrixStack.pop()) - }; - Drawing2D.prototype.resetMatrix = function() { - modelView.reset(); - modelViewInv.reset(); - curContext.setTransform(1, 0, 0, 1, 0, 0) - }; - Drawing3D.prototype.resetMatrix = function() { - modelView.reset(); - modelViewInv.reset() - }; - DrawingShared.prototype.applyMatrix = function() { - var a = arguments; - modelView.apply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); - modelViewInv.invApply(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]) - }; - Drawing2D.prototype.applyMatrix = function() { - var a = arguments; - for (var cnt = a.length; cnt < 16; cnt++) a[cnt] = 0; - a[10] = a[15] = 1; - DrawingShared.prototype.applyMatrix.apply(this, a) - }; - p.rotateX = function(angleInRadians) { - modelView.rotateX(angleInRadians); - modelViewInv.invRotateX(angleInRadians) - }; - Drawing2D.prototype.rotateZ = function() { - throw "rotateZ() is not supported in 2D mode. Use rotate(float) instead."; - }; - Drawing3D.prototype.rotateZ = function(angleInRadians) { - modelView.rotateZ(angleInRadians); - modelViewInv.invRotateZ(angleInRadians) - }; - p.rotateY = function(angleInRadians) { - modelView.rotateY(angleInRadians); - modelViewInv.invRotateY(angleInRadians) - }; - Drawing2D.prototype.rotate = function(angleInRadians) { - modelView.rotateZ(angleInRadians); - modelViewInv.invRotateZ(angleInRadians); - curContext.rotate(angleInRadians) - }; - Drawing3D.prototype.rotate = function(angleInRadians) { - p.rotateZ(angleInRadians) - }; - Drawing2D.prototype.shearX = function(angleInRadians) { - modelView.shearX(angleInRadians); - curContext.transform(1, 0, angleInRadians, 1, 0, 0) - }; - Drawing3D.prototype.shearX = function(angleInRadians) { - modelView.shearX(angleInRadians) - }; - Drawing2D.prototype.shearY = function(angleInRadians) { - modelView.shearY(angleInRadians); - curContext.transform(1, angleInRadians, 0, 1, 0, 0) - }; - Drawing3D.prototype.shearY = function(angleInRadians) { - modelView.shearY(angleInRadians) - }; - p.pushStyle = function() { - saveContext(); - p.pushMatrix(); - var newState = { - "doFill": doFill, - "currentFillColor": currentFillColor, - "doStroke": doStroke, - "currentStrokeColor": currentStrokeColor, - "curTint": curTint, - "curRectMode": curRectMode, - "curColorMode": curColorMode, - "colorModeX": colorModeX, - "colorModeZ": colorModeZ, - "colorModeY": colorModeY, - "colorModeA": colorModeA, - "curTextFont": curTextFont, - "horizontalTextAlignment": horizontalTextAlignment, - "verticalTextAlignment": verticalTextAlignment, - "textMode": textMode, - "curFontName": curFontName, - "curTextSize": curTextSize, - "curTextAscent": curTextAscent, - "curTextDescent": curTextDescent, - "curTextLeading": curTextLeading - }; - styleArray.push(newState) - }; - p.popStyle = function() { - var oldState = styleArray.pop(); - if (oldState) { - restoreContext(); - p.popMatrix(); - doFill = oldState.doFill; - currentFillColor = oldState.currentFillColor; - doStroke = oldState.doStroke; - currentStrokeColor = oldState.currentStrokeColor; - curTint = oldState.curTint; - curRectMode = oldState.curRectMode; - curColorMode = oldState.curColorMode; - colorModeX = oldState.colorModeX; - colorModeZ = oldState.colorModeZ; - colorModeY = oldState.colorModeY; - colorModeA = oldState.colorModeA; - curTextFont = oldState.curTextFont; - curFontName = oldState.curFontName; - curTextSize = oldState.curTextSize; - horizontalTextAlignment = oldState.horizontalTextAlignment; - verticalTextAlignment = oldState.verticalTextAlignment; - textMode = oldState.textMode; - curTextAscent = oldState.curTextAscent; - curTextDescent = oldState.curTextDescent; - curTextLeading = oldState.curTextLeading - } else throw "Too many popStyle() without enough pushStyle()"; - }; - p.year = function() { - return (new Date).getFullYear() - }; - p.month = function() { - return (new Date).getMonth() + 1 - }; - p.day = function() { - return (new Date).getDate() - }; - p.hour = function() { - return (new Date).getHours() - }; - p.minute = function() { - return (new Date).getMinutes() - }; - p.second = function() { - return (new Date).getSeconds() - }; - p.millis = function() { - return Date.now() - start - }; - - function redrawHelper() { - var sec = (Date.now() - timeSinceLastFPS) / 1E3; - framesSinceLastFPS++; - var fps = framesSinceLastFPS / sec; - if (sec > 0.5) { - timeSinceLastFPS = Date.now(); - framesSinceLastFPS = 0; - p.__frameRate = fps - } - p.frameCount++ - } - Drawing2D.prototype.redraw = function() { - redrawHelper(); - curContext.lineWidth = lineWidth; - var pmouseXLastEvent = p.pmouseX, - pmouseYLastEvent = p.pmouseY; - p.pmouseX = pmouseXLastFrame; - p.pmouseY = pmouseYLastFrame; - saveContext(); - p.draw(); - restoreContext(); - pmouseXLastFrame = p.mouseX; - pmouseYLastFrame = p.mouseY; - p.pmouseX = pmouseXLastEvent; - p.pmouseY = pmouseYLastEvent - }; - Drawing3D.prototype.redraw = function() { - redrawHelper(); - var pmouseXLastEvent = p.pmouseX, - pmouseYLastEvent = p.pmouseY; - p.pmouseX = pmouseXLastFrame; - p.pmouseY = pmouseYLastFrame; - curContext.clear(curContext.DEPTH_BUFFER_BIT); - curContextCache = { - attributes: {}, - locations: {} - }; - p.noLights(); - p.lightFalloff(1, 0, 0); - p.shininess(1); - p.ambient(255, 255, 255); - p.specular(0, 0, 0); - p.emissive(0, 0, 0); - p.camera(); - p.draw(); - pmouseXLastFrame = p.mouseX; - pmouseYLastFrame = p.mouseY; - p.pmouseX = pmouseXLastEvent; - p.pmouseY = pmouseYLastEvent - }; - p.noLoop = function() { - doLoop = false; - loopStarted = false; - clearInterval(looping); - curSketch.onPause() - }; - p.loop = function() { - if (loopStarted) return; - timeSinceLastFPS = Date.now(); - framesSinceLastFPS = 0; - looping = window.setInterval(function() { - try { - curSketch.onFrameStart(); - p.redraw(); - curSketch.onFrameEnd() - } catch(e_loop) { - window.clearInterval(looping); - throw e_loop; - } - }, - curMsPerFrame); - doLoop = true; - loopStarted = true; - curSketch.onLoop() - }; - p.frameRate = function(aRate) { - curFrameRate = aRate; - curMsPerFrame = 1E3 / curFrameRate; - if (doLoop) { - p.noLoop(); - p.loop() - } - }; - var eventHandlers = []; - - function attachEventHandler(elem, type, fn) { - if (elem.addEventListener) elem.addEventListener(type, fn, false); - else elem.attachEvent("on" + type, fn); - eventHandlers.push({ - elem: elem, - type: type, - fn: fn - }) - } - function detachEventHandler(eventHandler) { - var elem = eventHandler.elem, - type = eventHandler.type, - fn = eventHandler.fn; - if (elem.removeEventListener) elem.removeEventListener(type, fn, false); - else if (elem.detachEvent) elem.detachEvent("on" + type, fn) - } - p.exit = function() { - window.clearInterval(looping); - removeInstance(p.externals.canvas.id); - delete curElement.onmousedown; - for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if (Processing.lib[lib].hasOwnProperty("detach")) Processing.lib[lib].detach(p); - var i = eventHandlers.length; - while (i--) detachEventHandler(eventHandlers[i]); - curSketch.onExit() - }; - p.cursor = function() { - if (arguments.length > 1 || arguments.length === 1 && arguments[0] instanceof p.PImage) { - var image = arguments[0], - x, y; - if (arguments.length >= 3) { - x = arguments[1]; - y = arguments[2]; - if (x < 0 || y < 0 || y >= image.height || x >= image.width) throw "x and y must be non-negative and less than the dimensions of the image"; - } else { - x = image.width >>> 1; - y = image.height >>> 1 - } - var imageDataURL = image.toDataURL(); - var style = 'url("' + imageDataURL + '") ' + x + " " + y + ", default"; - curCursor = curElement.style.cursor = style - } else if (arguments.length === 1) { - var mode = arguments[0]; - curCursor = curElement.style.cursor = mode - } else curCursor = curElement.style.cursor = oldCursor - }; - p.noCursor = function() { - curCursor = curElement.style.cursor = PConstants.NOCURSOR - }; - p.link = function(href, target) { - if (target !== undef) window.open(href, target); - else window.location = href - }; - p.beginDraw = nop; - p.endDraw = nop; - Drawing2D.prototype.toImageData = function(x, y, w, h) { - x = x !== undef ? x : 0; - y = y !== undef ? y : 0; - w = w !== undef ? w : p.width; - h = h !== undef ? h : p.height; - return curContext.getImageData(x, y, w, h) - }; - Drawing3D.prototype.toImageData = function(x, y, w, h) { - x = x !== undef ? x : 0; - y = y !== undef ? y : 0; - w = w !== undef ? w : p.width; - h = h !== undef ? h : p.height; - var c = document.createElement("canvas"), - ctx = c.getContext("2d"), - obj = ctx.createImageData(w, h), - uBuff = new Uint8Array(w * h * 4); - curContext.readPixels(x, y, w, h, curContext.RGBA, curContext.UNSIGNED_BYTE, uBuff); - for (var i = 0, ul = uBuff.length, obj_data = obj.data; i < ul; i++) obj_data[i] = uBuff[(h - 1 - Math.floor(i / 4 / w)) * w * 4 + i % (w * 4)]; - return obj - }; - p.status = function(text) { - window.status = text - }; - p.binary = function(num, numBits) { - var bit; - if (numBits > 0) bit = numBits; - else if (num instanceof Char) { - bit = 16; - num |= 0 - } else { - bit = 32; - while (bit > 1 && !(num >>> bit - 1 & 1)) bit-- - } - var result = ""; - while (bit > 0) result += num >>> --bit & 1 ? "1" : "0"; - return result - }; - p.unbinary = function(binaryString) { - var i = binaryString.length - 1, - mask = 1, - result = 0; - while (i >= 0) { - var ch = binaryString[i--]; - if (ch !== "0" && ch !== "1") throw "the value passed into unbinary was not an 8 bit binary number"; - if (ch === "1") result += mask; - mask <<= 1 - } - return result - }; - - function nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) { - var sign = value < 0 ? minus : plus; - var autoDetectDecimals = rightDigits === 0; - var rightDigitsOfDefault = rightDigits === undef || rightDigits < 0 ? 0 : rightDigits; - var absValue = Math.abs(value); - if (autoDetectDecimals) { - rightDigitsOfDefault = 1; - absValue *= 10; - while (Math.abs(Math.round(absValue) - absValue) > 1.0E-6 && rightDigitsOfDefault < 7) { - ++rightDigitsOfDefault; - absValue *= 10 - } - } else if (rightDigitsOfDefault !== 0) absValue *= Math.pow(10, rightDigitsOfDefault); - var number, doubled = absValue * 2; - if (Math.floor(absValue) === absValue) number = absValue; - else if (Math.floor(doubled) === doubled) { - var floored = Math.floor(absValue); - number = floored + floored % 2 - } else number = Math.round(absValue); - var buffer = ""; - var totalDigits = leftDigits + rightDigitsOfDefault; - while (totalDigits > 0 || number > 0) { - totalDigits--; - buffer = "" + number % 10 + buffer; - number = Math.floor(number / 10) - } - if (group !== undef) { - var i = buffer.length - 3 - rightDigitsOfDefault; - while (i > 0) { - buffer = buffer.substring(0, i) + group + buffer.substring(i); - i -= 3 - } - } - if (rightDigitsOfDefault > 0) return sign + buffer.substring(0, buffer.length - rightDigitsOfDefault) + "." + buffer.substring(buffer.length - rightDigitsOfDefault, buffer.length); - return sign + buffer - } - function nfCore(value, plus, minus, leftDigits, rightDigits, group) { - if (value instanceof Array) { - var arr = []; - for (var i = 0, len = value.length; i < len; i++) arr.push(nfCoreScalar(value[i], plus, minus, leftDigits, rightDigits, group)); - return arr - } - return nfCoreScalar(value, plus, minus, leftDigits, rightDigits, group) - } - p.nf = function(value, leftDigits, rightDigits) { - return nfCore(value, "", "-", leftDigits, rightDigits) - }; - p.nfs = function(value, leftDigits, rightDigits) { - return nfCore(value, " ", "-", leftDigits, rightDigits) - }; - p.nfp = function(value, leftDigits, rightDigits) { - return nfCore(value, "+", "-", leftDigits, rightDigits) - }; - p.nfc = function(value, leftDigits, rightDigits) { - return nfCore(value, "", "-", leftDigits, rightDigits, ",") - }; - var decimalToHex = function(d, padding) { - padding = padding === undef || padding === null ? padding = 8 : padding; - if (d < 0) d = 4294967295 + d + 1; - var hex = Number(d).toString(16).toUpperCase(); - while (hex.length < padding) hex = "0" + hex; - if (hex.length >= padding) hex = hex.substring(hex.length - padding, hex.length); - return hex - }; - p.hex = function(value, len) { - if (arguments.length === 1) if (value instanceof Char) len = 4; - else len = 8; - return decimalToHex(value, len) - }; - - function unhexScalar(hex) { - var value = parseInt("0x" + hex, 16); - if (value > 2147483647) value -= 4294967296; - return value - } - p.unhex = function(hex) { - if (hex instanceof Array) { - var arr = []; - for (var i = 0; i < hex.length; i++) arr.push(unhexScalar(hex[i])); - return arr - } - return unhexScalar(hex) - }; - p.loadStrings = function(filename) { - if (localStorage[filename]) return localStorage[filename].split("\n"); - var filecontent = ajax(filename); - if (typeof filecontent !== "string" || filecontent === "") return []; - filecontent = filecontent.replace(/(\r\n?)/g, "\n").replace(/\n$/, ""); - return filecontent.split("\n") - }; - p.saveStrings = function(filename, strings) { - localStorage[filename] = strings.join("\n") - }; - p.loadBytes = function(url) { - var string = ajax(url); - var ret = []; - for (var i = 0; i < string.length; i++) ret.push(string.charCodeAt(i)); - return ret - }; - - function removeFirstArgument(args) { - return Array.prototype.slice.call(args, 1) - } - p.matchAll = function(aString, aRegExp) { - var results = [], - latest; - var regexp = new RegExp(aRegExp, "g"); - while ((latest = regexp.exec(aString)) !== null) { - results.push(latest); - if (latest[0].length === 0)++regexp.lastIndex - } - return results.length > 0 ? results : null - }; - p.__contains = function(subject, subStr) { - if (typeof subject !== "string") return subject.contains.apply(subject, removeFirstArgument(arguments)); - return subject !== null && subStr !== null && typeof subStr === "string" && subject.indexOf(subStr) > -1 - }; - p.__replaceAll = function(subject, regex, replacement) { - if (typeof subject !== "string") return subject.replaceAll.apply(subject, removeFirstArgument(arguments)); - return subject.replace(new RegExp(regex, "g"), replacement) - }; - p.__replaceFirst = function(subject, regex, replacement) { - if (typeof subject !== "string") return subject.replaceFirst.apply(subject, removeFirstArgument(arguments)); - return subject.replace(new RegExp(regex, ""), replacement) - }; - p.__replace = function(subject, what, replacement) { - if (typeof subject !== "string") return subject.replace.apply(subject, removeFirstArgument(arguments)); - if (what instanceof RegExp) return subject.replace(what, replacement); - if (typeof what !== "string") what = what.toString(); - if (what === "") return subject; - var i = subject.indexOf(what); - if (i < 0) return subject; - var j = 0, - result = ""; - do { - result += subject.substring(j, i) + replacement; - j = i + what.length - } while ((i = subject.indexOf(what, j)) >= 0); - return result + subject.substring(j) - }; - p.__equals = function(subject, other) { - if (subject.equals instanceof - Function) return subject.equals.apply(subject, removeFirstArgument(arguments)); - return subject.valueOf() === other.valueOf() - }; - p.__equalsIgnoreCase = function(subject, other) { - if (typeof subject !== "string") return subject.equalsIgnoreCase.apply(subject, removeFirstArgument(arguments)); - return subject.toLowerCase() === other.toLowerCase() - }; - p.__toCharArray = function(subject) { - if (typeof subject !== "string") return subject.toCharArray.apply(subject, removeFirstArgument(arguments)); - var chars = []; - for (var i = 0, len = subject.length; i < len; ++i) chars[i] = new Char(subject.charAt(i)); - return chars - }; - p.__split = function(subject, regex, limit) { - if (typeof subject !== "string") return subject.split.apply(subject, removeFirstArgument(arguments)); - var pattern = new RegExp(regex); - if (limit === undef || limit < 1) return subject.split(pattern); - var result = [], - currSubject = subject, - pos; - while ((pos = currSubject.search(pattern)) !== -1 && result.length < limit - 1) { - var match = pattern.exec(currSubject).toString(); - result.push(currSubject.substring(0, pos)); - currSubject = currSubject.substring(pos + match.length) - } - if (pos !== -1 || currSubject !== "") result.push(currSubject); - return result - }; - p.__codePointAt = function(subject, idx) { - var code = subject.charCodeAt(idx), - hi, low; - if (55296 <= code && code <= 56319) { - hi = code; - low = subject.charCodeAt(idx + 1); - return (hi - 55296) * 1024 + (low - 56320) + 65536 - } - return code - }; - p.match = function(str, regexp) { - return str.match(regexp) - }; - p.__matches = function(str, regexp) { - return (new RegExp(regexp)).test(str) - }; - p.__startsWith = function(subject, prefix, toffset) { - if (typeof subject !== "string") return subject.startsWith.apply(subject, removeFirstArgument(arguments)); - toffset = toffset || 0; - if (toffset < 0 || toffset > subject.length) return false; - return prefix === "" || prefix === subject ? true : subject.indexOf(prefix) === toffset - }; - p.__endsWith = function(subject, suffix) { - if (typeof subject !== "string") return subject.endsWith.apply(subject, removeFirstArgument(arguments)); - var suffixLen = suffix ? suffix.length : 0; - return suffix === "" || suffix === subject ? true : subject.indexOf(suffix) === subject.length - suffixLen - }; - p.__hashCode = function(subject) { - if (subject.hashCode instanceof - Function) return subject.hashCode.apply(subject, removeFirstArgument(arguments)); - return virtHashCode(subject) - }; - p.__printStackTrace = function(subject) { - p.println("Exception: " + subject.toString()) - }; - var logBuffer = []; - p.println = function(message) { - var bufferLen = logBuffer.length; - if (bufferLen) { - Processing.logger.log(logBuffer.join("")); - logBuffer.length = 0 - } - if (arguments.length === 0 && bufferLen === 0) Processing.logger.log(""); - else if (arguments.length !== 0) Processing.logger.log(message) - }; - p.print = function(message) { - logBuffer.push(message) - }; - p.str = function(val) { - if (val instanceof Array) { - var arr = []; - for (var i = 0; i < val.length; i++) arr.push(val[i].toString() + ""); - return arr - } - return val.toString() + "" - }; - p.trim = function(str) { - if (str instanceof Array) { - var arr = []; - for (var i = 0; i < str.length; i++) arr.push(str[i].replace(/^\s*/, "").replace(/\s*$/, "").replace(/\r*$/, "")); - return arr - } - return str.replace(/^\s*/, "").replace(/\s*$/, "").replace(/\r*$/, "") - }; - - function booleanScalar(val) { - if (typeof val === "number") return val !== 0; - if (typeof val === "boolean") return val; - if (typeof val === "string") return val.toLowerCase() === "true"; - if (val instanceof Char) return val.code === 49 || val.code === 84 || val.code === 116 - } - p.parseBoolean = function(val) { - if (val instanceof Array) { - var ret = []; - for (var i = 0; i < val.length; i++) ret.push(booleanScalar(val[i])); - return ret - } - return booleanScalar(val) - }; - p.parseByte = function(what) { - if (what instanceof Array) { - var bytes = []; - for (var i = 0; i < what.length; i++) bytes.push(0 - (what[i] & 128) | what[i] & 127); - return bytes - } - return 0 - (what & 128) | what & 127 - }; - p.parseChar = function(key) { - if (typeof key === "number") return new Char(String.fromCharCode(key & 65535)); - if (key instanceof Array) { - var ret = []; - for (var i = 0; i < key.length; i++) ret.push(new Char(String.fromCharCode(key[i] & 65535))); - return ret - } - throw "char() may receive only one argument of type int, byte, int[], or byte[]."; - }; - - function floatScalar(val) { - if (typeof val === "number") return val; - if (typeof val === "boolean") return val ? 1 : 0; - if (typeof val === "string") return parseFloat(val); - if (val instanceof Char) return val.code - } - p.parseFloat = function(val) { - if (val instanceof - Array) { - var ret = []; - for (var i = 0; i < val.length; i++) ret.push(floatScalar(val[i])); - return ret - } - return floatScalar(val) - }; - - function intScalar(val, radix) { - if (typeof val === "number") return val & 4294967295; - if (typeof val === "boolean") return val ? 1 : 0; - if (typeof val === "string") { - var number = parseInt(val, radix || 10); - return number & 4294967295 - } - if (val instanceof Char) return val.code - } - p.parseInt = function(val, radix) { - if (val instanceof Array) { - var ret = []; - for (var i = 0; i < val.length; i++) if (typeof val[i] === "string" && !/^\s*[+\-]?\d+\s*$/.test(val[i])) ret.push(0); - else ret.push(intScalar(val[i], radix)); - return ret - } - return intScalar(val, radix) - }; - p.__int_cast = function(val) { - return 0 | val - }; - p.__instanceof = function(obj, type) { - if (typeof type !== "function") throw "Function is expected as type argument for instanceof operator"; - if (typeof obj === "string") return type === Object || type === String; - if (obj instanceof type) return true; - if (typeof obj !== "object" || obj === null) return false; - var objType = obj.constructor; - if (type.$isInterface) { - var interfaces = []; - while (objType) { - if (objType.$interfaces) interfaces = interfaces.concat(objType.$interfaces); - objType = objType.$base - } - while (interfaces.length > 0) { - var i = interfaces.shift(); - if (i === type) return true; - if (i.$interfaces) interfaces = interfaces.concat(i.$interfaces) - } - return false - } - while (objType.hasOwnProperty("$base")) { - objType = objType.$base; - if (objType === type) return true - } - return false - }; - p.abs = Math.abs; - p.ceil = Math.ceil; - p.constrain = function(aNumber, aMin, aMax) { - return aNumber > aMax ? aMax : aNumber < aMin ? aMin : aNumber - }; - p.dist = function() { - var dx, dy, dz; - if (arguments.length === 4) { - dx = arguments[0] - arguments[2]; - dy = arguments[1] - arguments[3]; - return Math.sqrt(dx * dx + dy * dy) - } - if (arguments.length === 6) { - dx = arguments[0] - arguments[3]; - dy = arguments[1] - arguments[4]; - dz = arguments[2] - arguments[5]; - return Math.sqrt(dx * dx + dy * dy + dz * dz) - } - }; - p.exp = Math.exp; - p.floor = Math.floor; - p.lerp = function(value1, value2, amt) { - return (value2 - value1) * amt + value1 - }; - p.log = Math.log; - p.mag = function(a, b, c) { - if (c) return Math.sqrt(a * a + b * b + c * c); - return Math.sqrt(a * a + b * b) - }; - p.map = function(value, istart, istop, ostart, ostop) { - return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)) - }; - p.max = function() { - if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments[1] : arguments[0]; - var numbers = arguments.length === 1 ? arguments[0] : arguments; - if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; - var max = numbers[0], - count = numbers.length; - for (var i = 1; i < count; ++i) if (max < numbers[i]) max = numbers[i]; - return max - }; - p.min = function() { - if (arguments.length === 2) return arguments[0] < arguments[1] ? arguments[0] : arguments[1]; - var numbers = arguments.length === 1 ? arguments[0] : arguments; - if (! ("length" in numbers && numbers.length > 0)) throw "Non-empty array is expected"; - var min = numbers[0], - count = numbers.length; - for (var i = 1; i < count; ++i) if (min > numbers[i]) min = numbers[i]; - return min - }; - p.norm = function(aNumber, low, high) { - return (aNumber - low) / (high - low) - }; - p.pow = Math.pow; - p.round = Math.round; - p.sq = function(aNumber) { - return aNumber * aNumber - }; - p.sqrt = Math.sqrt; - p.acos = Math.acos; - p.asin = Math.asin; - p.atan = Math.atan; - p.atan2 = Math.atan2; - p.cos = Math.cos; - p.degrees = function(aAngle) { - return aAngle * 180 / Math.PI - }; - p.radians = function(aAngle) { - return aAngle / 180 * Math.PI - }; - p.sin = Math.sin; - p.tan = Math.tan; - var currentRandom = Math.random; - p.random = function() { - if (arguments.length === 0) return currentRandom(); - if (arguments.length === 1) return currentRandom() * arguments[0]; - var aMin = arguments[0], - aMax = arguments[1]; - return currentRandom() * (aMax - aMin) + aMin - }; - - function Marsaglia(i1, i2) { - var z = i1 || 362436069, - w = i2 || 521288629; - var nextInt = function() { - z = 36969 * (z & 65535) + (z >>> 16) & 4294967295; - w = 18E3 * (w & 65535) + (w >>> 16) & 4294967295; - return ((z & 65535) << 16 | w & 65535) & 4294967295 - }; - this.nextDouble = function() { - var i = nextInt() / 4294967296; - return i < 0 ? 1 + i : i - }; - this.nextInt = nextInt - } - Marsaglia.createRandomized = function() { - var now = new Date; - return new Marsaglia(now / 6E4 & 4294967295, now & 4294967295) - }; - p.randomSeed = function(seed) { - currentRandom = (new Marsaglia(seed)).nextDouble - }; - p.Random = function(seed) { - var haveNextNextGaussian = false, - nextNextGaussian, random; - this.nextGaussian = function() { - if (haveNextNextGaussian) { - haveNextNextGaussian = false; - return nextNextGaussian - } - var v1, v2, s; - do { - v1 = 2 * random() - 1; - v2 = 2 * random() - 1; - s = v1 * v1 + v2 * v2 - } while (s >= 1 || s === 0); - var multiplier = Math.sqrt(-2 * Math.log(s) / s); - nextNextGaussian = v2 * multiplier; - haveNextNextGaussian = true; - return v1 * multiplier - }; - random = seed === undef ? Math.random : (new Marsaglia(seed)).nextDouble - }; - - function PerlinNoise(seed) { - var rnd = seed !== undef ? new Marsaglia(seed) : Marsaglia.createRandomized(); - var i, j; - var perm = new Uint8Array(512); - for (i = 0; i < 256; ++i) perm[i] = i; - for (i = 0; i < 256; ++i) { - var t = perm[j = rnd.nextInt() & 255]; - perm[j] = perm[i]; - perm[i] = t - } - for (i = 0; i < 256; ++i) perm[i + 256] = perm[i]; - - function grad3d(i, x, y, z) { - var h = i & 15; - var u = h < 8 ? x : y, - v = h < 4 ? y : h === 12 || h === 14 ? x : z; - return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v) - } - function grad2d(i, x, y) { - var v = (i & 1) === 0 ? x : y; - return (i & 2) === 0 ? -v : v - } - function grad1d(i, x) { - return (i & 1) === 0 ? -x : x - } - function lerp(t, a, b) { - return a + t * (b - a) - } - this.noise3d = function(x, y, z) { - var X = Math.floor(x) & 255, - Y = Math.floor(y) & 255, - Z = Math.floor(z) & 255; - x -= Math.floor(x); - y -= Math.floor(y); - z -= Math.floor(z); - var fx = (3 - 2 * x) * x * x, - fy = (3 - 2 * y) * y * y, - fz = (3 - 2 * z) * z * z; - var p0 = perm[X] + Y, - p00 = perm[p0] + Z, - p01 = perm[p0 + 1] + Z, - p1 = perm[X + 1] + Y, - p10 = perm[p1] + Z, - p11 = perm[p1 + 1] + Z; - return lerp(fz, lerp(fy, lerp(fx, grad3d(perm[p00], x, y, z), grad3d(perm[p10], x - 1, y, z)), lerp(fx, grad3d(perm[p01], x, y - 1, z), grad3d(perm[p11], x - 1, y - 1, z))), lerp(fy, lerp(fx, grad3d(perm[p00 + 1], x, y, z - 1), grad3d(perm[p10 + 1], x - 1, y, z - 1)), lerp(fx, grad3d(perm[p01 + 1], x, y - 1, z - 1), grad3d(perm[p11 + 1], x - 1, y - 1, z - 1)))) - }; - this.noise2d = function(x, y) { - var X = Math.floor(x) & 255, - Y = Math.floor(y) & 255; - x -= Math.floor(x); - y -= Math.floor(y); - var fx = (3 - 2 * x) * x * x, - fy = (3 - 2 * y) * y * y; - var p0 = perm[X] + Y, - p1 = perm[X + 1] + Y; - return lerp(fy, lerp(fx, grad2d(perm[p0], x, y), grad2d(perm[p1], x - 1, y)), lerp(fx, grad2d(perm[p0 + 1], x, y - 1), grad2d(perm[p1 + 1], x - 1, y - 1))) - }; - this.noise1d = function(x) { - var X = Math.floor(x) & 255; - x -= Math.floor(x); - var fx = (3 - 2 * x) * x * x; - return lerp(fx, grad1d(perm[X], x), grad1d(perm[X + 1], x - 1)) - } - } - var noiseProfile = { - generator: undef, - octaves: 4, - fallout: 0.5, - seed: undef - }; - p.noise = function(x, y, z) { - if (noiseProfile.generator === undef) noiseProfile.generator = new PerlinNoise(noiseProfile.seed); - var generator = noiseProfile.generator; - var effect = 1, - k = 1, - sum = 0; - for (var i = 0; i < noiseProfile.octaves; ++i) { - effect *= noiseProfile.fallout; - switch (arguments.length) { - case 1: - sum += effect * (1 + generator.noise1d(k * x)) / 2; - break; - case 2: - sum += effect * (1 + generator.noise2d(k * x, k * y)) / 2; - break; - case 3: - sum += effect * (1 + generator.noise3d(k * x, k * y, k * z)) / 2; - break - } - k *= 2 - } - return sum - }; - p.noiseDetail = function(octaves, fallout) { - noiseProfile.octaves = octaves; - if (fallout !== undef) noiseProfile.fallout = fallout - }; - p.noiseSeed = function(seed) { - noiseProfile.seed = seed; - noiseProfile.generator = undef - }; - DrawingShared.prototype.size = function(aWidth, aHeight, aMode) { - if (doStroke) p.stroke(0); - if (doFill) p.fill(255); - var savedProperties = { - fillStyle: curContext.fillStyle, - strokeStyle: curContext.strokeStyle, - lineCap: curContext.lineCap, - lineJoin: curContext.lineJoin - }; - if (curElement.style.length > 0) { - curElement.style.removeProperty("width"); - curElement.style.removeProperty("height") - } - curElement.width = p.width = aWidth || 100; - curElement.height = p.height = aHeight || 100; - for (var prop in savedProperties) if (savedProperties.hasOwnProperty(prop)) curContext[prop] = savedProperties[prop]; - p.textFont(curTextFont); - p.background(); - maxPixelsCached = Math.max(1E3, aWidth * aHeight * 0.05); - p.externals.context = curContext; - for (var i = 0; i < 720; i++) { - sinLUT[i] = p.sin(i * (Math.PI / 180) * 0.5); - cosLUT[i] = p.cos(i * (Math.PI / 180) * 0.5) - } - }; - Drawing2D.prototype.size = function(aWidth, aHeight, aMode) { - if (curContext === undef) { - curContext = curElement.getContext("2d"); - userMatrixStack = new PMatrixStack; - userReverseMatrixStack = new PMatrixStack; - modelView = new PMatrix2D; - modelViewInv = new PMatrix2D - } - DrawingShared.prototype.size.apply(this, arguments) - }; - Drawing3D.prototype.size = function() { - var size3DCalled = false; - return function size(aWidth, aHeight, aMode) { - if (size3DCalled) throw "Multiple calls to size() for 3D renders are not allowed."; - size3DCalled = true; - - function getGLContext(canvas) { - var ctxNames = ["experimental-webgl", "webgl", "webkit-3d"], - gl; - for (var i = 0, l = ctxNames.length; i < l; i++) { - gl = canvas.getContext(ctxNames[i], { - antialias: false, - preserveDrawingBuffer: true - }); - if (gl) break - } - return gl - } - try { - curElement.width = p.width = aWidth || 100; - curElement.height = p.height = aHeight || 100; - curContext = getGLContext(curElement); - canTex = curContext.createTexture(); - textTex = curContext.createTexture() - } catch(e_size) { - Processing.debug(e_size) - } - if (!curContext) throw "WebGL context is not supported on this browser."; - curContext.viewport(0, 0, curElement.width, curElement.height); - curContext.enable(curContext.DEPTH_TEST); - curContext.enable(curContext.BLEND); - curContext.blendFunc(curContext.SRC_ALPHA, curContext.ONE_MINUS_SRC_ALPHA); - programObject2D = createProgramObject(curContext, vertexShaderSrc2D, fragmentShaderSrc2D); - programObjectUnlitShape = createProgramObject(curContext, vertexShaderSrcUnlitShape, fragmentShaderSrcUnlitShape); - p.strokeWeight(1); - programObject3D = createProgramObject(curContext, vertexShaderSrc3D, fragmentShaderSrc3D); - curContext.useProgram(programObject3D); - uniformi("usingTexture3d", programObject3D, "usingTexture", usingTexture); - p.lightFalloff(1, 0, 0); - p.shininess(1); - p.ambient(255, 255, 255); - p.specular(0, 0, 0); - p.emissive(0, 0, 0); - boxBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxVerts, curContext.STATIC_DRAW); - boxNormBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxNormBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxNorms, curContext.STATIC_DRAW); - boxOutlineBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, boxOutlineBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, boxOutlineVerts, curContext.STATIC_DRAW); - rectBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, rectBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, rectVerts, curContext.STATIC_DRAW); - rectNormBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, rectNormBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, rectNorms, curContext.STATIC_DRAW); - sphereBuffer = curContext.createBuffer(); - lineBuffer = curContext.createBuffer(); - fillBuffer = curContext.createBuffer(); - fillColorBuffer = curContext.createBuffer(); - strokeColorBuffer = curContext.createBuffer(); - shapeTexVBO = curContext.createBuffer(); - pointBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, pointBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 0]), curContext.STATIC_DRAW); - textBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, textBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0]), curContext.STATIC_DRAW); - textureBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ARRAY_BUFFER, textureBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), curContext.STATIC_DRAW); - indexBuffer = curContext.createBuffer(); - curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); - curContext.bufferData(curContext.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 2, 3, 0]), curContext.STATIC_DRAW); - cam = new PMatrix3D; - cameraInv = new PMatrix3D; - modelView = new PMatrix3D; - modelViewInv = new PMatrix3D; - projection = new PMatrix3D; - p.camera(); - p.perspective(); - userMatrixStack = new PMatrixStack; - userReverseMatrixStack = new PMatrixStack; - curveBasisMatrix = new PMatrix3D; - curveToBezierMatrix = new PMatrix3D; - curveDrawMatrix = new PMatrix3D; - bezierDrawMatrix = new PMatrix3D; - bezierBasisInverse = new PMatrix3D; - bezierBasisMatrix = new PMatrix3D; - bezierBasisMatrix.set(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0); - DrawingShared.prototype.size.apply(this, arguments) - } - }(); - Drawing2D.prototype.ambientLight = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.ambientLight = function(r, g, b, x, y, z) { - if (lightCount === 8) throw "can only create " + 8 + " lights"; - var pos = new PVector(x, y, z); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.mult(pos, pos); - var col = color$4(r, g, b, 0); - var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; - curContext.useProgram(programObject3D); - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 0); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) - }; - Drawing2D.prototype.directionalLight = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.directionalLight = function(r, g, b, nx, ny, nz) { - if (lightCount === 8) throw "can only create " + 8 + " lights"; - curContext.useProgram(programObject3D); - var mvm = new PMatrix3D; - mvm.scale(1, -1, 1); - mvm.apply(modelView.array()); - mvm = mvm.array(); - var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz]; - var col = color$4(r, g, b, 0); - var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", dir); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 1); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) - }; - Drawing2D.prototype.lightFalloff = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.lightFalloff = function(constant, linear, quadratic) { - curContext.useProgram(programObject3D); - uniformf("uFalloff3d", programObject3D, "uFalloff", [constant, linear, quadratic]) - }; - Drawing2D.prototype.lightSpecular = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.lightSpecular = function(r, g, b) { - var col = color$4(r, g, b, 0); - var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; - curContext.useProgram(programObject3D); - uniformf("uSpecular3d", programObject3D, "uSpecular", normalizedCol) - }; - p.lights = function() { - p.ambientLight(128, 128, 128); - p.directionalLight(128, 128, 128, 0, 0, -1); - p.lightFalloff(1, 0, 0); - p.lightSpecular(0, 0, 0) - }; - Drawing2D.prototype.pointLight = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.pointLight = function(r, g, b, x, y, z) { - if (lightCount === 8) throw "can only create " + 8 + " lights"; - var pos = new PVector(x, y, z); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.mult(pos, pos); - var col = color$4(r, g, b, 0); - var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; - curContext.useProgram(programObject3D); - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 2); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) - }; - Drawing2D.prototype.noLights = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.noLights = function() { - lightCount = 0; - curContext.useProgram(programObject3D); - uniformi("uLightCount3d", programObject3D, "uLightCount", lightCount) - }; - Drawing2D.prototype.spotLight = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.spotLight = function(r, g, b, x, y, z, nx, ny, nz, angle, concentration) { - if (lightCount === 8) throw "can only create " + 8 + " lights"; - curContext.useProgram(programObject3D); - var pos = new PVector(x, y, z); - var mvm = new PMatrix3D; - mvm.scale(1, -1, 1); - mvm.apply(modelView.array()); - mvm.mult(pos, pos); - mvm = mvm.array(); - var dir = [mvm[0] * nx + mvm[4] * ny + mvm[8] * nz, mvm[1] * - nx + mvm[5] * ny + mvm[9] * nz, mvm[2] * nx + mvm[6] * ny + mvm[10] * nz]; - var col = color$4(r, g, b, 0); - var normalizedCol = [((col >> 16) & 255) / 255, ((col >> 8) & 255) / 255, (col & 255) / 255]; - uniformf("uLights.color.3d." + lightCount, programObject3D, "uLights" + lightCount + ".color", normalizedCol); - uniformf("uLights.position.3d." + lightCount, programObject3D, "uLights" + lightCount + ".position", pos.array()); - uniformf("uLights.direction.3d." + lightCount, programObject3D, "uLights" + lightCount + ".direction", dir); - uniformf("uLights.concentration.3d." + lightCount, programObject3D, "uLights" + lightCount + ".concentration", concentration); - uniformf("uLights.angle.3d." + lightCount, programObject3D, "uLights" + lightCount + ".angle", angle); - uniformi("uLights.type.3d." + lightCount, programObject3D, "uLights" + lightCount + ".type", 3); - uniformi("uLightCount3d", programObject3D, "uLightCount", ++lightCount) - }; - Drawing2D.prototype.beginCamera = function() { - throw "beginCamera() is not available in 2D mode"; - }; - Drawing3D.prototype.beginCamera = function() { - if (manipulatingCamera) throw "You cannot call beginCamera() again before calling endCamera()"; - manipulatingCamera = true; - modelView = cameraInv; - modelViewInv = cam - }; - Drawing2D.prototype.endCamera = function() { - throw "endCamera() is not available in 2D mode"; - }; - Drawing3D.prototype.endCamera = function() { - if (!manipulatingCamera) throw "You cannot call endCamera() before calling beginCamera()"; - modelView.set(cam); - modelViewInv.set(cameraInv); - manipulatingCamera = false - }; - p.camera = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { - if (eyeX === undef) { - cameraX = p.width / 2; - cameraY = p.height / 2; - cameraZ = cameraY / Math.tan(cameraFOV / 2); - eyeX = cameraX; - eyeY = cameraY; - eyeZ = cameraZ; - centerX = cameraX; - centerY = cameraY; - centerZ = 0; - upX = 0; - upY = 1; - upZ = 0 - } - var z = new PVector(eyeX - centerX, eyeY - centerY, eyeZ - centerZ); - var y = new PVector(upX, upY, upZ); - z.normalize(); - var x = PVector.cross(y, z); - y = PVector.cross(z, x); - x.normalize(); - y.normalize(); - var xX = x.x, - xY = x.y, - xZ = x.z; - var yX = y.x, - yY = y.y, - yZ = y.z; - var zX = z.x, - zY = z.y, - zZ = z.z; - cam.set(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); - cam.translate(-eyeX, -eyeY, -eyeZ); - cameraInv.reset(); - cameraInv.invApply(xX, xY, xZ, 0, yX, yY, yZ, 0, zX, zY, zZ, 0, 0, 0, 0, 1); - cameraInv.translate(eyeX, eyeY, eyeZ); - modelView.set(cam); - modelViewInv.set(cameraInv) - }; - p.perspective = function(fov, aspect, near, far) { - if (arguments.length === 0) { - cameraY = curElement.height / 2; - cameraZ = cameraY / Math.tan(cameraFOV / 2); - cameraNear = cameraZ / 10; - cameraFar = cameraZ * 10; - cameraAspect = p.width / p.height; - fov = cameraFOV; - aspect = cameraAspect; - near = cameraNear; - far = cameraFar - } - var yMax, yMin, xMax, xMin; - yMax = near * Math.tan(fov / 2); - yMin = -yMax; - xMax = yMax * aspect; - xMin = yMin * aspect; - p.frustum(xMin, xMax, yMin, yMax, near, far) - }; - Drawing2D.prototype.frustum = function() { - throw "Processing.js: frustum() is not supported in 2D mode"; - }; - Drawing3D.prototype.frustum = function(left, right, bottom, top, near, far) { - frustumMode = true; - projection = new PMatrix3D; - projection.set(2 * near / (right - left), 0, (right + left) / (right - left), 0, 0, 2 * near / (top - bottom), (top + bottom) / (top - bottom), 0, 0, 0, -(far + near) / (far - near), -(2 * far * near) / (far - near), 0, 0, -1, 0); - var proj = new PMatrix3D; - proj.set(projection); - proj.transpose(); - curContext.useProgram(programObject2D); - uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); - curContext.useProgram(programObject3D); - uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()) - }; - p.ortho = function(left, right, bottom, top, near, far) { - if (arguments.length === 0) { - left = 0; - right = p.width; - bottom = 0; - top = p.height; - near = -10; - far = 10 - } - var x = 2 / (right - left); - var y = 2 / (top - bottom); - var z = -2 / (far - near); - var tx = -(right + left) / (right - left); - var ty = -(top + bottom) / (top - bottom); - var tz = -(far + near) / (far - near); - projection = new PMatrix3D; - projection.set(x, 0, 0, tx, 0, y, 0, ty, 0, 0, z, tz, 0, 0, 0, 1); - var proj = new PMatrix3D; - proj.set(projection); - proj.transpose(); - curContext.useProgram(programObject2D); - uniformMatrix("projection2d", programObject2D, "uProjection", false, proj.array()); - curContext.useProgram(programObject3D); - uniformMatrix("projection3d", programObject3D, "uProjection", false, proj.array()); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uProjectionUS", programObjectUnlitShape, "uProjection", false, proj.array()); - frustumMode = false - }; - p.printProjection = function() { - projection.print() - }; - p.printCamera = function() { - cam.print() - }; - Drawing2D.prototype.box = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.box = function(w, h, d) { - if (!h || !d) h = d = w; - var model = new PMatrix3D; - model.scale(w, h, d); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - if (doFill) { - curContext.useProgram(programObject3D); - uniformMatrix("model3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("view3d", programObject3D, "uView", false, view.array()); - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("color3d", programObject3D, "uColor", fillStyle); - if (lightCount > 0) { - var v = new PMatrix3D; - v.set(view); - var m = new PMatrix3D; - m.set(model); - v.mult(m); - var normalMatrix = new PMatrix3D; - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, boxNormBuffer) - } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); - vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, boxBuffer); - disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); - disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); - curContext.drawArrays(curContext.TRIANGLES, 0, boxVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL) - } - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - vertexAttribPointer("vertex2d", programObject2D, "aVertex", 3, boxOutlineBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.LINES, 0, boxOutlineVerts.length / 3) - } - }; - var initSphere = function() { - var i; - sphereVerts = []; - for (i = 0; i < sphereDetailU; i++) { - sphereVerts.push(0); - sphereVerts.push(-1); - sphereVerts.push(0); - sphereVerts.push(sphereX[i]); - sphereVerts.push(sphereY[i]); - sphereVerts.push(sphereZ[i]) - } - sphereVerts.push(0); - sphereVerts.push(-1); - sphereVerts.push(0); - sphereVerts.push(sphereX[0]); - sphereVerts.push(sphereY[0]); - sphereVerts.push(sphereZ[0]); - var v1, v11, v2; - var voff = 0; - for (i = 2; i < sphereDetailV; i++) { - v1 = v11 = voff; - voff += sphereDetailU; - v2 = voff; - for (var j = 0; j < sphereDetailU; j++) { - sphereVerts.push(sphereX[v1]); - sphereVerts.push(sphereY[v1]); - sphereVerts.push(sphereZ[v1++]); - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2++]) - } - v1 = v11; - v2 = voff; - sphereVerts.push(sphereX[v1]); - sphereVerts.push(sphereY[v1]); - sphereVerts.push(sphereZ[v1]); - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2]) - } - for (i = 0; i < sphereDetailU; i++) { - v2 = voff + i; - sphereVerts.push(sphereX[v2]); - sphereVerts.push(sphereY[v2]); - sphereVerts.push(sphereZ[v2]); - sphereVerts.push(0); - sphereVerts.push(1); - sphereVerts.push(0) - } - sphereVerts.push(sphereX[voff]); - sphereVerts.push(sphereY[voff]); - sphereVerts.push(sphereZ[voff]); - sphereVerts.push(0); - sphereVerts.push(1); - sphereVerts.push(0); - curContext.bindBuffer(curContext.ARRAY_BUFFER, sphereBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(sphereVerts), curContext.STATIC_DRAW) - }; - p.sphereDetail = function(ures, vres) { - var i; - if (arguments.length === 1) ures = vres = arguments[0]; - if (ures < 3) ures = 3; - if (vres < 2) vres = 2; - if (ures === sphereDetailU && vres === sphereDetailV) return; - var delta = 720 / ures; - var cx = new Float32Array(ures); - var cz = new Float32Array(ures); - for (i = 0; i < ures; i++) { - cx[i] = cosLUT[i * delta % 720 | 0]; - cz[i] = sinLUT[i * delta % 720 | 0] - } - var vertCount = ures * (vres - 1) + 2; - var currVert = 0; - sphereX = new Float32Array(vertCount); - sphereY = new Float32Array(vertCount); - sphereZ = new Float32Array(vertCount); - var angle_step = 720 * 0.5 / vres; - var angle = angle_step; - for (i = 1; i < vres; i++) { - var curradius = sinLUT[angle % 720 | 0]; - var currY = -cosLUT[angle % 720 | 0]; - for (var j = 0; j < ures; j++) { - sphereX[currVert] = cx[j] * curradius; - sphereY[currVert] = currY; - sphereZ[currVert++] = cz[j] * curradius - } - angle += angle_step - } - sphereDetailU = ures; - sphereDetailV = vres; - initSphere() - }; - Drawing2D.prototype.sphere = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.sphere = function() { - var sRad = arguments[0]; - if (sphereDetailU < 3 || sphereDetailV < 2) p.sphereDetail(30); - var model = new PMatrix3D; - model.scale(sRad, sRad, sRad); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - if (doFill) { - if (lightCount > 0) { - var v = new PMatrix3D; - v.set(view); - var m = new PMatrix3D; - m.set(model); - v.mult(m); - var normalMatrix = new PMatrix3D; - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, sphereBuffer) - } else disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); - curContext.useProgram(programObject3D); - disableVertexAttribPointer("aTexture3d", programObject3D, "aTexture"); - uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); - vertexAttribPointer("aVertex3d", programObject3D, "aVertex", 3, sphereBuffer); - disableVertexAttribPointer("aColor3d", programObject3D, "aColor"); - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("uColor3d", programObject3D, "uColor", fillStyle); - curContext.drawArrays(curContext.TRIANGLE_STRIP, 0, sphereVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL) - } - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, sphereBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); - curContext.drawArrays(curContext.LINE_STRIP, 0, sphereVerts.length / 3) - } - }; - p.modelX = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - return ow !== 0 ? ox / ow : ox - }; - p.modelY = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - return ow !== 0 ? oy / ow : oy - }; - p.modelZ = function(x, y, z) { - var mv = modelView.array(); - var ci = cameraInv.array(); - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var oz = ci[8] * ax + ci[9] * ay + ci[10] * az + ci[11] * aw; - var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw; - return ow !== 0 ? oz / ow : oz - }; - Drawing2D.prototype.ambient = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.ambient = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialAmbient3d", programObject3D, "uMaterialAmbient", p.color.toGLArray(col).slice(0, 3)) - }; - Drawing2D.prototype.emissive = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.emissive = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialEmissive3d", programObject3D, "uMaterialEmissive", p.color.toGLArray(col).slice(0, 3)) - }; - Drawing2D.prototype.shininess = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.shininess = function(shine) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - uniformf("uShininess3d", programObject3D, "uShininess", shine) - }; - Drawing2D.prototype.specular = DrawingShared.prototype.a3DOnlyFunction; - Drawing3D.prototype.specular = function(v1, v2, v3) { - curContext.useProgram(programObject3D); - uniformi("uUsingMat3d", programObject3D, "uUsingMat", true); - var col = p.color(v1, v2, v3); - uniformf("uMaterialSpecular3d", programObject3D, "uMaterialSpecular", p.color.toGLArray(col).slice(0, 3)) - }; - p.screenX = function(x, y, z) { - var mv = modelView.array(); - if (mv.length === 16) { - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var pj = projection.array(); - var ox = pj[0] * ax + pj[1] * ay + pj[2] * az + pj[3] * aw; - var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; - if (ow !== 0) ox /= ow; - return p.width * (1 + ox) / 2 - } - return modelView.multX(x, y) - }; - p.screenY = function screenY(x, y, z) { - var mv = modelView.array(); - if (mv.length === 16) { - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var pj = projection.array(); - var oy = pj[4] * ax + pj[5] * ay + pj[6] * az + pj[7] * aw; - var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; - if (ow !== 0) oy /= ow; - return p.height * (1 + oy) / 2 - } - return modelView.multY(x, y) - }; - p.screenZ = function screenZ(x, y, z) { - var mv = modelView.array(); - if (mv.length !== 16) return 0; - var pj = projection.array(); - var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3]; - var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7]; - var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11]; - var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15]; - var oz = pj[8] * ax + pj[9] * ay + pj[10] * az + pj[11] * aw; - var ow = pj[12] * ax + pj[13] * ay + pj[14] * az + pj[15] * aw; - if (ow !== 0) oz /= ow; - return (oz + 1) / 2 - }; - DrawingShared.prototype.fill = function() { - var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]); - if (color === currentFillColor && doFill) return; - doFill = true; - currentFillColor = color - }; - Drawing2D.prototype.fill = function() { - DrawingShared.prototype.fill.apply(this, arguments); - isFillDirty = true - }; - Drawing3D.prototype.fill = function() { - DrawingShared.prototype.fill.apply(this, arguments); - fillStyle = p.color.toGLArray(currentFillColor) - }; - - function executeContextFill() { - if (doFill) { - if (isFillDirty) { - curContext.fillStyle = p.color.toString(currentFillColor); - isFillDirty = false - } - curContext.fill() - } - } - p.noFill = function() { - doFill = false - }; - DrawingShared.prototype.stroke = function() { - var color = p.color(arguments[0], arguments[1], arguments[2], arguments[3]); - if (color === currentStrokeColor && doStroke) return; - doStroke = true; - currentStrokeColor = color - }; - Drawing2D.prototype.stroke = function() { - DrawingShared.prototype.stroke.apply(this, arguments); - isStrokeDirty = true - }; - Drawing3D.prototype.stroke = function() { - DrawingShared.prototype.stroke.apply(this, arguments); - strokeStyle = p.color.toGLArray(currentStrokeColor) - }; - - function executeContextStroke() { - if (doStroke) { - if (isStrokeDirty) { - curContext.strokeStyle = p.color.toString(currentStrokeColor); - isStrokeDirty = false - } - curContext.stroke() - } - } - p.noStroke = function() { - doStroke = false - }; - DrawingShared.prototype.strokeWeight = function(w) { - lineWidth = w - }; - Drawing2D.prototype.strokeWeight = function(w) { - DrawingShared.prototype.strokeWeight.apply(this, arguments); - curContext.lineWidth = w - }; - Drawing3D.prototype.strokeWeight = function(w) { - DrawingShared.prototype.strokeWeight.apply(this, arguments); - curContext.useProgram(programObject2D); - uniformf("pointSize2d", programObject2D, "uPointSize", w); - curContext.useProgram(programObjectUnlitShape); - uniformf("pointSizeUnlitShape", programObjectUnlitShape, "uPointSize", w); - curContext.lineWidth(w) - }; - p.strokeCap = function(value) { - drawing.$ensureContext().lineCap = value - }; - p.strokeJoin = function(value) { - drawing.$ensureContext().lineJoin = value - }; - Drawing2D.prototype.smooth = function() { - renderSmooth = true; - var style = curElement.style; - style.setProperty("image-rendering", "optimizeQuality", "important"); - style.setProperty("-ms-interpolation-mode", "bicubic", "important"); - if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozImageSmoothingEnabled = true - }; - Drawing3D.prototype.smooth = function() { - renderSmooth = true - }; - Drawing2D.prototype.noSmooth = function() { - renderSmooth = false; - var style = curElement.style; - style.setProperty("image-rendering", "optimizeSpeed", "important"); - style.setProperty("image-rendering", "-moz-crisp-edges", "important"); - style.setProperty("image-rendering", "-webkit-optimize-contrast", "important"); - style.setProperty("image-rendering", "optimize-contrast", "important"); - style.setProperty("-ms-interpolation-mode", "nearest-neighbor", "important"); - if (curContext.hasOwnProperty("mozImageSmoothingEnabled")) curContext.mozImageSmoothingEnabled = false - }; - Drawing3D.prototype.noSmooth = function() { - renderSmooth = false - }; - Drawing2D.prototype.point = function(x, y) { - if (!doStroke) return; - x = Math.round(x); - y = Math.round(y); - curContext.fillStyle = p.color.toString(currentStrokeColor); - isFillDirty = true; - if (lineWidth > 1) { - curContext.beginPath(); - curContext.arc(x, y, lineWidth / 2, 0, 6.283185307179586, false); - curContext.fill() - } else curContext.fillRect(x, y, 1, 1) - }; - Drawing3D.prototype.point = function(x, y, z) { - var model = new PMatrix3D; - model.translate(x, y, z || 0); - model.transpose(); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - if (lineWidth > 0 && doStroke) { - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - uniformi("uSmooth2d", programObject2D, "uSmooth", renderSmooth); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, pointBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.POINTS, 0, 1) - } - }; - p.beginShape = function(type) { - curShape = type; - curvePoints = []; - vertArray = [] - }; - Drawing2D.prototype.vertex = function(x, y, moveTo) { - var vert = []; - if (firstVert) firstVert = false; - vert["isVert"] = true; - vert[0] = x; - vert[1] = y; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - vert[5] = currentFillColor; - vert[6] = currentStrokeColor; - vertArray.push(vert); - if (moveTo) vertArray[vertArray.length - 1]["moveTo"] = moveTo - }; - Drawing3D.prototype.vertex = function(x, y, z, u, v) { - var vert = []; - if (firstVert) firstVert = false; - vert["isVert"] = true; - if (v === undef && usingTexture) { - v = u; - u = z; - z = 0 - } - if (u !== undef && v !== undef) { - if (curTextureMode === 2) { - u /= curTexture.width; - v /= curTexture.height - } - u = u > 1 ? 1 : u; - u = u < 0 ? 0 : u; - v = v > 1 ? 1 : v; - v = v < 0 ? 0 : v - } - vert[0] = x; - vert[1] = y; - vert[2] = z || 0; - vert[3] = u || 0; - vert[4] = v || 0; - vert[5] = fillStyle[0]; - vert[6] = fillStyle[1]; - vert[7] = fillStyle[2]; - vert[8] = fillStyle[3]; - vert[9] = strokeStyle[0]; - vert[10] = strokeStyle[1]; - vert[11] = strokeStyle[2]; - vert[12] = strokeStyle[3]; - vert[13] = normalX; - vert[14] = normalY; - vert[15] = normalZ; - vertArray.push(vert) - }; - var point3D = function(vArray, cArray) { - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); - uniformi("uSmoothUS", programObjectUnlitShape, "uSmooth", renderSmooth); - vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, pointBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); - vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, fillColorBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); - curContext.drawArrays(curContext.POINTS, 0, vArray.length / 3) - }; - var line3D = function(vArray, mode, cArray) { - var ctxMode; - if (mode === "LINES") ctxMode = curContext.LINES; - else if (mode === "LINE_LOOP") ctxMode = curContext.LINE_LOOP; - else ctxMode = curContext.LINE_STRIP; - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - curContext.useProgram(programObjectUnlitShape); - uniformMatrix("uViewUS", programObjectUnlitShape, "uView", false, view.array()); - vertexAttribPointer("aVertexUS", programObjectUnlitShape, "aVertex", 3, lineBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); - vertexAttribPointer("aColorUS", programObjectUnlitShape, "aColor", 4, strokeColorBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); - curContext.drawArrays(ctxMode, 0, vArray.length / 3) - }; - var fill3D = function(vArray, mode, cArray, tArray) { - var ctxMode; - if (mode === "TRIANGLES") ctxMode = curContext.TRIANGLES; - else if (mode === "TRIANGLE_FAN") ctxMode = curContext.TRIANGLE_FAN; - else ctxMode = curContext.TRIANGLE_STRIP; - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - curContext.useProgram(programObject3D); - uniformMatrix("model3d", programObject3D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - uniformMatrix("view3d", programObject3D, "uView", false, view.array()); - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("color3d", programObject3D, "uColor", [-1, 0, 0, 0]); - vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, fillBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(vArray), curContext.STREAM_DRAW); - if (usingTexture && curTint !== null) curTint3d(cArray); - vertexAttribPointer("aColor3d", programObject3D, "aColor", 4, fillColorBuffer); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(cArray), curContext.STREAM_DRAW); - disableVertexAttribPointer("aNormal3d", programObject3D, "aNormal"); - if (usingTexture) { - uniformi("uUsingTexture3d", programObject3D, "uUsingTexture", usingTexture); - vertexAttribPointer("aTexture3d", programObject3D, "aTexture", 2, shapeTexVBO); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(tArray), curContext.STREAM_DRAW) - } - curContext.drawArrays(ctxMode, 0, vArray.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL) - }; - - function fillStrokeClose() { - executeContextFill(); - executeContextStroke(); - curContext.closePath() - } - Drawing2D.prototype.endShape = function(mode) { - if (vertArray.length === 0) return; - var closeShape = mode === 2; - if (closeShape) vertArray.push(vertArray[0]); - var lineVertArray = []; - var fillVertArray = []; - var colorVertArray = []; - var strokeVertArray = []; - var texVertArray = []; - var cachedVertArray; - firstVert = true; - var i, j, k; - var vertArrayLength = vertArray.length; - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - texVertArray.push(cachedVertArray[3]); - texVertArray.push(cachedVertArray[4]) - } - if (isCurve && (curShape === 20 || curShape === undef)) { - if (vertArrayLength > 3) { - var b = [], - s = 1 - curTightness; - curContext.beginPath(); - curContext.moveTo(vertArray[1][0], vertArray[1][1]); - for (i = 1; i + 2 < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - b[0] = [cachedVertArray[0], cachedVertArray[1]]; - b[1] = [cachedVertArray[0] + (s * vertArray[i + 1][0] - s * vertArray[i - 1][0]) / 6, cachedVertArray[1] + (s * vertArray[i + 1][1] - s * vertArray[i - 1][1]) / 6]; - b[2] = [vertArray[i + 1][0] + (s * vertArray[i][0] - s * vertArray[i + 2][0]) / 6, vertArray[i + 1][1] + (s * vertArray[i][1] - s * vertArray[i + 2][1]) / 6]; - b[3] = [vertArray[i + 1][0], vertArray[i + 1][1]]; - curContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]) - } - fillStrokeClose() - } - } else if (isBezier && (curShape === 20 || curShape === undef)) { - curContext.beginPath(); - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (vertArray[i]["isVert"]) if (vertArray[i]["moveTo"]) curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - else curContext.bezierCurveTo(vertArray[i][0], vertArray[i][1], vertArray[i][2], vertArray[i][3], vertArray[i][4], vertArray[i][5]) - } - fillStrokeClose() - } else if (curShape === 2) for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (doStroke) p.stroke(cachedVertArray[6]); - p.point(cachedVertArray[0], cachedVertArray[1]) - } else if (curShape === 4) for (i = 0; i + 1 < vertArrayLength; i += 2) { - cachedVertArray = vertArray[i]; - if (doStroke) p.stroke(vertArray[i + 1][6]); - p.line(cachedVertArray[0], cachedVertArray[1], vertArray[i + 1][0], vertArray[i + 1][1]) - } else if (curShape === 9) for (i = 0; i + 2 < vertArrayLength; i += 3) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); - curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - if (doFill) { - p.fill(vertArray[i + 2][5]); - executeContextFill() - } - if (doStroke) { - p.stroke(vertArray[i + 2][6]); - executeContextStroke() - } - curContext.closePath() - } else if (curShape === 10) for (i = 0; i + 1 < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(vertArray[i + 1][0], vertArray[i + 1][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - if (doStroke) p.stroke(vertArray[i + 1][6]); - if (doFill) p.fill(vertArray[i + 1][5]); - if (i + 2 < vertArrayLength) { - curContext.lineTo(vertArray[i + 2][0], vertArray[i + 2][1]); - if (doStroke) p.stroke(vertArray[i + 2][6]); - if (doFill) p.fill(vertArray[i + 2][5]) - } - fillStrokeClose() - } else if (curShape === 11) { - if (vertArrayLength > 2) { - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - curContext.lineTo(vertArray[1][0], vertArray[1][1]); - curContext.lineTo(vertArray[2][0], vertArray[2][1]); - if (doFill) { - p.fill(vertArray[2][5]); - executeContextFill() - } - if (doStroke) { - p.stroke(vertArray[2][6]); - executeContextStroke() - } - curContext.closePath(); - for (i = 3; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - curContext.lineTo(vertArray[i - 1][0], vertArray[i - 1][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - if (doFill) { - p.fill(cachedVertArray[5]); - executeContextFill() - } - if (doStroke) { - p.stroke(cachedVertArray[6]); - executeContextStroke() - } - curContext.closePath() - } - } - } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - for (j = 1; j < 4; j++) curContext.lineTo(vertArray[i + j][0], vertArray[i + j][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - if (doFill) { - p.fill(vertArray[i + 3][5]); - executeContextFill() - } - if (doStroke) { - p.stroke(vertArray[i + 3][6]); - executeContextStroke() - } - curContext.closePath() - } else if (curShape === 17) { - if (vertArrayLength > 3) for (i = 0; i + 1 < vertArrayLength; i += 2) { - cachedVertArray = vertArray[i]; - curContext.beginPath(); - if (i + 3 < vertArrayLength) { - curContext.moveTo(vertArray[i + 2][0], vertArray[i + 2][1]); - curContext.lineTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]); - curContext.lineTo(vertArray[i + 3][0], vertArray[i + 3][1]); - if (doFill) p.fill(vertArray[i + 3][5]); - if (doStroke) p.stroke(vertArray[i + 3][6]) - } else { - curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - curContext.lineTo(vertArray[i + 1][0], vertArray[i + 1][1]) - } - fillStrokeClose() - } - } else { - curContext.beginPath(); - curContext.moveTo(vertArray[0][0], vertArray[0][1]); - for (i = 1; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - if (cachedVertArray["isVert"]) if (cachedVertArray["moveTo"]) curContext.moveTo(cachedVertArray[0], cachedVertArray[1]); - else curContext.lineTo(cachedVertArray[0], cachedVertArray[1]) - } - fillStrokeClose() - } - isCurve = false; - isBezier = false; - curveVertArray = []; - curveVertCount = 0; - if (closeShape) vertArray.pop() - }; - Drawing3D.prototype.endShape = function(mode) { - if (vertArray.length === 0) return; - var closeShape = mode === 2; - var lineVertArray = []; - var fillVertArray = []; - var colorVertArray = []; - var strokeVertArray = []; - var texVertArray = []; - var cachedVertArray; - firstVert = true; - var i, j, k; - var vertArrayLength = vertArray.length; - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) fillVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - texVertArray.push(cachedVertArray[3]); - texVertArray.push(cachedVertArray[4]) - } - if (closeShape) { - fillVertArray.push(vertArray[0][0]); - fillVertArray.push(vertArray[0][1]); - fillVertArray.push(vertArray[0][2]); - for (i = 5; i < 9; i++) colorVertArray.push(vertArray[0][i]); - for (i = 9; i < 13; i++) strokeVertArray.push(vertArray[0][i]); - texVertArray.push(vertArray[0][3]); - texVertArray.push(vertArray[0][4]) - } - if (isCurve && (curShape === 20 || curShape === undef)) { - lineVertArray = fillVertArray; - if (doStroke) line3D(lineVertArray, null, strokeVertArray); - if (doFill) fill3D(fillVertArray, null, colorVertArray) - } else if (isBezier && (curShape === 20 || curShape === undef)) { - lineVertArray = fillVertArray; - lineVertArray.splice(lineVertArray.length - 3); - strokeVertArray.splice(strokeVertArray.length - 4); - if (doStroke) line3D(lineVertArray, null, strokeVertArray); - if (doFill) fill3D(fillVertArray, "TRIANGLES", colorVertArray) - } else { - if (curShape === 2) { - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) - } - point3D(lineVertArray, strokeVertArray) - } else if (curShape === 4) { - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 5; j < 9; j++) colorVertArray.push(cachedVertArray[j]) - } - line3D(lineVertArray, "LINES", strokeVertArray) - } else if (curShape === 9) { - if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i += 3) { - fillVertArray = []; - texVertArray = []; - lineVertArray = []; - colorVertArray = []; - strokeVertArray = []; - for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { - lineVertArray.push(vertArray[i + j][k]); - fillVertArray.push(vertArray[i + j][k]) - } - for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(vertArray[i + j][k]); - for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { - colorVertArray.push(vertArray[i + j][k]); - strokeVertArray.push(vertArray[i + j][k + 4]) - } - if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLES", colorVertArray, texVertArray) - } - } else if (curShape === 10) { - if (vertArrayLength > 2) for (i = 0; i + 2 < vertArrayLength; i++) { - lineVertArray = []; - fillVertArray = []; - strokeVertArray = []; - colorVertArray = []; - texVertArray = []; - for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { - lineVertArray.push(vertArray[i + j][k]); - fillVertArray.push(vertArray[i + j][k]) - } - for (j = 0; j < 3; j++) for (k = 3; k < 5; k++) texVertArray.push(vertArray[i + j][k]); - for (j = 0; j < 3; j++) for (k = 5; k < 9; k++) { - strokeVertArray.push(vertArray[i + j][k + 4]); - colorVertArray.push(vertArray[i + j][k]) - } - if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray); - if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray) - } - } else if (curShape === 11) { - if (vertArrayLength > 2) { - for (i = 0; i < 3; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < 3; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) - } - if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - for (i = 2; i + 1 < vertArrayLength; i++) { - lineVertArray = []; - strokeVertArray = []; - lineVertArray.push(vertArray[0][0]); - lineVertArray.push(vertArray[0][1]); - lineVertArray.push(vertArray[0][2]); - strokeVertArray.push(vertArray[0][9]); - strokeVertArray.push(vertArray[0][10]); - strokeVertArray.push(vertArray[0][11]); - strokeVertArray.push(vertArray[0][12]); - for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) lineVertArray.push(vertArray[i + j][k]); - for (j = 0; j < 2; j++) for (k = 9; k < 13; k++) strokeVertArray.push(vertArray[i + j][k]); - if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) - } - if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray) - } - } else if (curShape === 16) for (i = 0; i + 3 < vertArrayLength; i += 4) { - lineVertArray = []; - for (j = 0; j < 4; j++) { - cachedVertArray = vertArray[i + j]; - for (k = 0; k < 3; k++) lineVertArray.push(cachedVertArray[k]) - } - if (doStroke) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - if (doFill) { - fillVertArray = []; - colorVertArray = []; - texVertArray = []; - for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); - for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]); - for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 1][j]); - for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 1][j]); - for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 3][j]); - for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 3][j]); - for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i + 2][j]); - for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i + 2][j]); - if (usingTexture) { - texVertArray.push(vertArray[i + 0][3]); - texVertArray.push(vertArray[i + 0][4]); - texVertArray.push(vertArray[i + 1][3]); - texVertArray.push(vertArray[i + 1][4]); - texVertArray.push(vertArray[i + 3][3]); - texVertArray.push(vertArray[i + 3][4]); - texVertArray.push(vertArray[i + 2][3]); - texVertArray.push(vertArray[i + 2][4]) - } - fill3D(fillVertArray, "TRIANGLE_STRIP", colorVertArray, texVertArray) - } - } else if (curShape === 17) { - var tempArray = []; - if (vertArrayLength > 3) { - for (i = 0; i < 2; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]) - } - for (i = 0; i < 2; i++) { - cachedVertArray = vertArray[i]; - for (j = 9; j < 13; j++) strokeVertArray.push(cachedVertArray[j]) - } - line3D(lineVertArray, "LINE_STRIP", strokeVertArray); - if (vertArrayLength > 4 && vertArrayLength % 2 > 0) { - tempArray = fillVertArray.splice(fillVertArray.length - 3); - vertArray.pop() - } - for (i = 0; i + 3 < vertArrayLength; i += 2) { - lineVertArray = []; - strokeVertArray = []; - for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 1][j]); - for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 3][j]); - for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 2][j]); - for (j = 0; j < 3; j++) lineVertArray.push(vertArray[i + 0][j]); - for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 1][j]); - for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 3][j]); - for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 2][j]); - for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[i + 0][j]); - if (doStroke) line3D(lineVertArray, "LINE_STRIP", strokeVertArray) - } - if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_LIST", colorVertArray, texVertArray) - } - } else if (vertArrayLength === 1) { - for (j = 0; j < 3; j++) lineVertArray.push(vertArray[0][j]); - for (j = 9; j < 13; j++) strokeVertArray.push(vertArray[0][j]); - point3D(lineVertArray, strokeVertArray) - } else { - for (i = 0; i < vertArrayLength; i++) { - cachedVertArray = vertArray[i]; - for (j = 0; j < 3; j++) lineVertArray.push(cachedVertArray[j]); - for (j = 5; j < 9; j++) strokeVertArray.push(cachedVertArray[j]) - } - if (doStroke && closeShape) line3D(lineVertArray, "LINE_LOOP", strokeVertArray); - else if (doStroke && !closeShape) line3D(lineVertArray, "LINE_STRIP", strokeVertArray); - if (doFill || usingTexture) fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray, texVertArray) - } - usingTexture = false; - curContext.useProgram(programObject3D); - uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture) - } - isCurve = false; - isBezier = false; - curveVertArray = []; - curveVertCount = 0 - }; - var splineForward = function(segments, matrix) { - var f = 1 / segments; - var ff = f * f; - var fff = ff * f; - matrix.set(0, 0, 0, 1, fff, ff, f, 0, 6 * fff, 2 * ff, 0, 0, 6 * fff, 0, 0, 0) - }; - var curveInit = function() { - if (!curveDrawMatrix) { - curveBasisMatrix = new PMatrix3D; - curveDrawMatrix = new PMatrix3D; - curveInited = true - } - var s = curTightness; - curveBasisMatrix.set((s - 1) / 2, (s + 3) / 2, (-3 - s) / 2, (1 - s) / 2, 1 - s, (-5 - s) / 2, s + 2, (s - 1) / 2, (s - 1) / 2, 0, (1 - s) / 2, 0, 0, 1, 0, 0); - splineForward(curveDet, curveDrawMatrix); - if (!bezierBasisInverse) curveToBezierMatrix = new PMatrix3D; - curveToBezierMatrix.set(curveBasisMatrix); - curveToBezierMatrix.preApply(bezierBasisInverse); - curveDrawMatrix.apply(curveBasisMatrix) - }; - Drawing2D.prototype.bezierVertex = function() { - isBezier = true; - var vert = []; - if (firstVert) throw "vertex() must be used at least once before calling bezierVertex()"; - for (var i = 0; i < arguments.length; i++) vert[i] = arguments[i]; - vertArray.push(vert); - vertArray[vertArray.length - 1]["isVert"] = false - }; - Drawing3D.prototype.bezierVertex = function() { - isBezier = true; - var vert = []; - if (firstVert) throw "vertex() must be used at least once before calling bezierVertex()"; - if (arguments.length === 9) { - if (bezierDrawMatrix === undef) bezierDrawMatrix = new PMatrix3D; - var lastPoint = vertArray.length - 1; - splineForward(bezDetail, bezierDrawMatrix); - bezierDrawMatrix.apply(bezierBasisMatrix); - var draw = bezierDrawMatrix.array(); - var x1 = vertArray[lastPoint][0], - y1 = vertArray[lastPoint][1], - z1 = vertArray[lastPoint][2]; - var xplot1 = draw[4] * x1 + draw[5] * arguments[0] + draw[6] * arguments[3] + draw[7] * arguments[6]; - var xplot2 = draw[8] * x1 + draw[9] * arguments[0] + draw[10] * arguments[3] + draw[11] * arguments[6]; - var xplot3 = draw[12] * x1 + draw[13] * arguments[0] + draw[14] * arguments[3] + draw[15] * arguments[6]; - var yplot1 = draw[4] * y1 + draw[5] * arguments[1] + draw[6] * arguments[4] + draw[7] * arguments[7]; - var yplot2 = draw[8] * y1 + draw[9] * arguments[1] + draw[10] * arguments[4] + draw[11] * arguments[7]; - var yplot3 = draw[12] * y1 + draw[13] * arguments[1] + draw[14] * arguments[4] + draw[15] * arguments[7]; - var zplot1 = draw[4] * z1 + draw[5] * arguments[2] + draw[6] * arguments[5] + draw[7] * arguments[8]; - var zplot2 = draw[8] * z1 + draw[9] * arguments[2] + draw[10] * arguments[5] + draw[11] * arguments[8]; - var zplot3 = draw[12] * z1 + draw[13] * arguments[2] + draw[14] * arguments[5] + draw[15] * arguments[8]; - for (var j = 0; j < bezDetail; j++) { - x1 += xplot1; - xplot1 += xplot2; - xplot2 += xplot3; - y1 += yplot1; - yplot1 += yplot2; - yplot2 += yplot3; - z1 += zplot1; - zplot1 += zplot2; - zplot2 += zplot3; - p.vertex(x1, y1, z1) - } - p.vertex(arguments[6], arguments[7], arguments[8]) - } - }; - p.texture = function(pimage) { - var curContext = drawing.$ensureContext(); - if (pimage.__texture) curContext.bindTexture(curContext.TEXTURE_2D, pimage.__texture); - else if (pimage.localName === "canvas") { - curContext.bindTexture(curContext.TEXTURE_2D, canTex); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, pimage); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); - curContext.generateMipmap(curContext.TEXTURE_2D); - curTexture.width = pimage.width; - curTexture.height = pimage.height - } else { - var texture = curContext.createTexture(), - cvs = document.createElement("canvas"), - cvsTextureCtx = cvs.getContext("2d"), - pot; - if (pimage.width & pimage.width - 1 === 0) cvs.width = pimage.width; - else { - pot = 1; - while (pot < pimage.width) pot *= 2; - cvs.width = pot - } - if (pimage.height & pimage.height - 1 === 0) cvs.height = pimage.height; - else { - pot = 1; - while (pot < pimage.height) pot *= 2; - cvs.height = pot - } - cvsTextureCtx.drawImage(pimage.sourceImg, 0, 0, pimage.width, pimage.height, 0, 0, cvs.width, cvs.height); - curContext.bindTexture(curContext.TEXTURE_2D, texture); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR_MIPMAP_LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, cvs); - curContext.generateMipmap(curContext.TEXTURE_2D); - pimage.__texture = texture; - curTexture.width = pimage.width; - curTexture.height = pimage.height - } - usingTexture = true; - curContext.useProgram(programObject3D); - uniformi("usingTexture3d", programObject3D, "uUsingTexture", usingTexture) - }; - p.textureMode = function(mode) { - curTextureMode = mode - }; - var curveVertexSegment = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { - var x0 = x2; - var y0 = y2; - var z0 = z2; - var draw = curveDrawMatrix.array(); - var xplot1 = draw[4] * x1 + draw[5] * x2 + draw[6] * x3 + draw[7] * x4; - var xplot2 = draw[8] * x1 + draw[9] * x2 + draw[10] * x3 + draw[11] * x4; - var xplot3 = draw[12] * x1 + draw[13] * x2 + draw[14] * x3 + draw[15] * x4; - var yplot1 = draw[4] * y1 + draw[5] * y2 + draw[6] * y3 + draw[7] * y4; - var yplot2 = draw[8] * y1 + draw[9] * y2 + draw[10] * y3 + draw[11] * y4; - var yplot3 = draw[12] * y1 + draw[13] * y2 + draw[14] * y3 + draw[15] * y4; - var zplot1 = draw[4] * z1 + draw[5] * z2 + draw[6] * z3 + draw[7] * z4; - var zplot2 = draw[8] * z1 + draw[9] * z2 + draw[10] * z3 + draw[11] * z4; - var zplot3 = draw[12] * z1 + draw[13] * z2 + draw[14] * z3 + draw[15] * z4; - p.vertex(x0, y0, z0); - for (var j = 0; j < curveDet; j++) { - x0 += xplot1; - xplot1 += xplot2; - xplot2 += xplot3; - y0 += yplot1; - yplot1 += yplot2; - yplot2 += yplot3; - z0 += zplot1; - zplot1 += zplot2; - zplot2 += zplot3; - p.vertex(x0, y0, z0) - } - }; - Drawing2D.prototype.curveVertex = function(x, y) { - isCurve = true; - p.vertex(x, y) - }; - Drawing3D.prototype.curveVertex = function(x, y, z) { - isCurve = true; - if (!curveInited) curveInit(); - var vert = []; - vert[0] = x; - vert[1] = y; - vert[2] = z; - curveVertArray.push(vert); - curveVertCount++; - if (curveVertCount > 3) curveVertexSegment(curveVertArray[curveVertCount - 4][0], curveVertArray[curveVertCount - 4][1], curveVertArray[curveVertCount - 4][2], curveVertArray[curveVertCount - 3][0], curveVertArray[curveVertCount - 3][1], curveVertArray[curveVertCount - 3][2], curveVertArray[curveVertCount - 2][0], curveVertArray[curveVertCount - 2][1], curveVertArray[curveVertCount - 2][2], curveVertArray[curveVertCount - 1][0], curveVertArray[curveVertCount - 1][1], curveVertArray[curveVertCount - 1][2]) - }; - Drawing2D.prototype.curve = function(x1, y1, x2, y2, x3, y3, x4, y4) { - p.beginShape(); - p.curveVertex(x1, y1); - p.curveVertex(x2, y2); - p.curveVertex(x3, y3); - p.curveVertex(x4, y4); - p.endShape() - }; - Drawing3D.prototype.curve = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { - if (z4 !== undef) { - p.beginShape(); - p.curveVertex(x1, y1, z1); - p.curveVertex(x2, y2, z2); - p.curveVertex(x3, y3, z3); - p.curveVertex(x4, y4, z4); - p.endShape(); - return - } - p.beginShape(); - p.curveVertex(x1, y1); - p.curveVertex(z1, x2); - p.curveVertex(y2, z2); - p.curveVertex(x3, y3); - p.endShape() - }; - p.curveTightness = function(tightness) { - curTightness = tightness - }; - p.curveDetail = function(detail) { - curveDet = detail; - curveInit() - }; - p.rectMode = function(aRectMode) { - curRectMode = aRectMode - }; - p.imageMode = function(mode) { - switch (mode) { - case 0: - imageModeConvert = imageModeCorner; - break; - case 1: - imageModeConvert = imageModeCorners; - break; - case 3: - imageModeConvert = imageModeCenter; - break; - default: - throw "Invalid imageMode"; - } - }; - p.ellipseMode = function(aEllipseMode) { - curEllipseMode = aEllipseMode - }; - p.arc = function(x, y, width, height, start, stop) { - if (width <= 0 || stop < start) return; - if (curEllipseMode === 1) { - width = width - x; - height = height - y - } else if (curEllipseMode === 2) { - x = x - width; - y = y - height; - width = width * 2; - height = height * 2 - } else if (curEllipseMode === 3) { - x = x - width / 2; - y = y - height / 2 - } - while (start < 0) { - start += 6.283185307179586; - stop += 6.283185307179586 - } - if (stop - start > 6.283185307179586) { - start = 0; - stop = 6.283185307179586 - } - var hr = width / 2, - vr = height / 2, - centerX = x + hr, - centerY = y + vr, - startLUT = 0 | 0.5 + start * p.RAD_TO_DEG * 2, - stopLUT = 0 | 0.5 + stop * p.RAD_TO_DEG * 2, - i, j; - if (doFill) { - var savedStroke = doStroke; - doStroke = false; - p.beginShape(); - p.vertex(centerX, centerY); - for (i = startLUT; i <= stopLUT; i++) { - j = i % 720; - p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr) - } - p.endShape(2); - doStroke = savedStroke - } - if (doStroke) { - var savedFill = doFill; - doFill = false; - p.beginShape(); - for (i = startLUT; i <= stopLUT; i++) { - j = i % 720; - p.vertex(centerX + cosLUT[j] * hr, centerY + sinLUT[j] * vr) - } - p.endShape(); - doFill = savedFill - } - }; - Drawing2D.prototype.line = function(x1, y1, x2, y2) { - if (!doStroke) return; - x1 = Math.round(x1); - x2 = Math.round(x2); - y1 = Math.round(y1); - y2 = Math.round(y2); - if (x1 === x2 && y1 === y2) { - p.point(x1, y1); - return - } - var swap = undef, - lineCap = undef, - drawCrisp = true, - currentModelView = modelView.array(), - identityMatrix = [1, 0, 0, 0, 1, 0]; - for (var i = 0; i < 6 && drawCrisp; i++) drawCrisp = currentModelView[i] === identityMatrix[i]; - if (drawCrisp) { - if (x1 === x2) { - if (y1 > y2) { - swap = y1; - y1 = y2; - y2 = swap - } - y2++; - if (lineWidth % 2 === 1) curContext.translate(0.5, 0) - } else if (y1 === y2) { - if (x1 > x2) { - swap = x1; - x1 = x2; - x2 = swap - } - x2++; - if (lineWidth % 2 === 1) curContext.translate(0, 0.5) - } - if (lineWidth === 1) { - lineCap = curContext.lineCap; - curContext.lineCap = "butt" - } - } - curContext.beginPath(); - curContext.moveTo(x1 || 0, y1 || 0); - curContext.lineTo(x2 || 0, y2 || 0); - executeContextStroke(); - if (drawCrisp) { - if (x1 === x2 && lineWidth % 2 === 1) curContext.translate(-0.5, 0); - else if (y1 === y2 && lineWidth % 2 === 1) curContext.translate(0, -0.5); - if (lineWidth === 1) curContext.lineCap = lineCap - } - }; - Drawing3D.prototype.line = function(x1, y1, z1, x2, y2, z2) { - if (y2 === undef || z2 === undef) { - z2 = 0; - y2 = x2; - x2 = z1; - z1 = 0 - } - if (x1 === x2 && y1 === y2 && z1 === z2) { - p.point(x1, y1, z1); - return - } - var lineVerts = [x1, y1, z1, x2, y2, z2]; - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText", programObject2D, "uIsDrawingText", false); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, lineBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.bufferData(curContext.ARRAY_BUFFER, new Float32Array(lineVerts), curContext.STREAM_DRAW); - curContext.drawArrays(curContext.LINES, 0, 2) - } - }; - Drawing2D.prototype.bezier = function() { - if (arguments.length !== 8) throw "You must use 8 parameters for bezier() in 2D mode"; - p.beginShape(); - p.vertex(arguments[0], arguments[1]); - p.bezierVertex(arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); - p.endShape() - }; - Drawing3D.prototype.bezier = function() { - if (arguments.length !== 12) throw "You must use 12 parameters for bezier() in 3D mode"; - p.beginShape(); - p.vertex(arguments[0], arguments[1], arguments[2]); - p.bezierVertex(arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8], arguments[9], arguments[10], arguments[11]); - p.endShape() - }; - p.bezierDetail = function(detail) { - bezDetail = detail - }; - p.bezierPoint = function(a, b, c, d, t) { - return (1 - t) * (1 - t) * (1 - t) * a + 3 * (1 - t) * (1 - t) * t * b + 3 * (1 - t) * t * t * c + t * t * t * d - }; - p.bezierTangent = function(a, b, c, d, t) { - return 3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b) - }; - p.curvePoint = function(a, b, c, d, t) { - return 0.5 * (2 * b + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t * t + (-a + 3 * b - 3 * c + d) * t * t * t) - }; - p.curveTangent = function(a, b, c, d, t) { - return 0.5 * (-a + c + 2 * (2 * a - 5 * b + 4 * c - d) * t + 3 * (-a + 3 * b - 3 * c + d) * t * t) - }; - p.triangle = function(x1, y1, x2, y2, x3, y3) { - p.beginShape(9); - p.vertex(x1, y1, 0); - p.vertex(x2, y2, 0); - p.vertex(x3, y3, 0); - p.endShape() - }; - p.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { - p.beginShape(16); - p.vertex(x1, y1, 0); - p.vertex(x2, y2, 0); - p.vertex(x3, y3, 0); - p.vertex(x4, y4, 0); - p.endShape() - }; - var roundedRect$2d = function(x, y, width, height, tl, tr, br, bl) { - if (bl === undef) { - tr = tl; - br = tl; - bl = tl - } - var halfWidth = width / 2, - halfHeight = height / 2; - if (tl > halfWidth || tl > halfHeight) tl = Math.min(halfWidth, halfHeight); - if (tr > halfWidth || tr > halfHeight) tr = Math.min(halfWidth, halfHeight); - if (br > halfWidth || br > halfHeight) br = Math.min(halfWidth, halfHeight); - if (bl > halfWidth || bl > halfHeight) bl = Math.min(halfWidth, halfHeight); - if (!doFill || doStroke) curContext.translate(0.5, 0.5); - curContext.beginPath(); - curContext.moveTo(x + tl, y); - curContext.lineTo(x + width - tr, y); - curContext.quadraticCurveTo(x + width, y, x + width, y + tr); - curContext.lineTo(x + width, y + height - br); - curContext.quadraticCurveTo(x + width, y + height, x + width - br, y + height); - curContext.lineTo(x + bl, y + height); - curContext.quadraticCurveTo(x, y + height, x, y + height - bl); - curContext.lineTo(x, y + tl); - curContext.quadraticCurveTo(x, y, x + tl, y); - if (!doFill || doStroke) curContext.translate(-0.5, -0.5); - executeContextFill(); - executeContextStroke() - }; - Drawing2D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { - if (!width && !height) return; - if (curRectMode === 1) { - width -= x; - height -= y - } else if (curRectMode === 2) { - width *= 2; - height *= 2; - x -= width / 2; - y -= height / 2 - } else if (curRectMode === 3) { - x -= width / 2; - y -= height / 2 - } - x = Math.round(x); - y = Math.round(y); - width = Math.round(width); - height = Math.round(height); - if (tl !== undef) { - roundedRect$2d(x, y, width, height, tl, tr, br, bl); - return - } - if (doStroke && lineWidth % 2 === 1) curContext.translate(0.5, 0.5); - curContext.beginPath(); - curContext.rect(x, y, width, height); - executeContextFill(); - executeContextStroke(); - if (doStroke && lineWidth % 2 === 1) curContext.translate(-0.5, -0.5) - }; - Drawing3D.prototype.rect = function(x, y, width, height, tl, tr, br, bl) { - if (tl !== undef) throw "rect() with rounded corners is not supported in 3D mode"; - if (curRectMode === 1) { - width -= x; - height -= y - } else if (curRectMode === 2) { - width *= 2; - height *= 2; - x -= width / 2; - y -= height / 2 - } else if (curRectMode === 3) { - x -= width / 2; - y -= height / 2 - } - var model = new PMatrix3D; - model.translate(x, y, 0); - model.scale(width, height, 1); - model.transpose(); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - if (lineWidth > 0 && doStroke) { - curContext.useProgram(programObject2D); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", strokeStyle); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", false); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, rectBuffer); - disableVertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord"); - curContext.drawArrays(curContext.LINE_LOOP, 0, rectVerts.length / 3) - } - if (doFill) { - curContext.useProgram(programObject3D); - uniformMatrix("uModel3d", programObject3D, "uModel", false, model.array()); - uniformMatrix("uView3d", programObject3D, "uView", false, view.array()); - curContext.enable(curContext.POLYGON_OFFSET_FILL); - curContext.polygonOffset(1, 1); - uniformf("color3d", programObject3D, "uColor", fillStyle); - if (lightCount > 0) { - var v = new PMatrix3D; - v.set(view); - var m = new PMatrix3D; - m.set(model); - v.mult(m); - var normalMatrix = new PMatrix3D; - normalMatrix.set(v); - normalMatrix.invert(); - normalMatrix.transpose(); - uniformMatrix("uNormalTransform3d", programObject3D, "uNormalTransform", false, normalMatrix.array()); - vertexAttribPointer("aNormal3d", programObject3D, "aNormal", 3, rectNormBuffer) - } else disableVertexAttribPointer("normal3d", programObject3D, "aNormal"); - vertexAttribPointer("vertex3d", programObject3D, "aVertex", 3, rectBuffer); - curContext.drawArrays(curContext.TRIANGLE_FAN, 0, rectVerts.length / 3); - curContext.disable(curContext.POLYGON_OFFSET_FILL) - } - }; - Drawing2D.prototype.ellipse = function(x, y, width, height) { - x = x || 0; - y = y || 0; - if (width <= 0 && height <= 0) return; - if (curEllipseMode === 2) { - width *= 2; - height *= 2 - } else if (curEllipseMode === 1) { - width = width - x; - height = height - y; - x += width / 2; - y += height / 2 - } else if (curEllipseMode === 0) { - x += width / 2; - y += height / 2 - } - if (width === height) { - curContext.beginPath(); - curContext.arc(x, y, width / 2, 0, 6.283185307179586, false); - executeContextFill(); - executeContextStroke() - } else { - var w = width / 2, - h = height / 2, - C = 0.5522847498307933, - c_x = C * w, - c_y = C * h; - p.beginShape(); - p.vertex(x + w, y); - p.bezierVertex(x + w, y - c_y, x + c_x, y - h, x, y - h); - p.bezierVertex(x - c_x, y - h, x - w, y - c_y, x - w, y); - p.bezierVertex(x - w, y + c_y, x - c_x, y + h, x, y + h); - p.bezierVertex(x + c_x, y + h, x + w, y + c_y, x + w, y); - p.endShape() - } - }; - Drawing3D.prototype.ellipse = function(x, y, width, height) { - x = x || 0; - y = y || 0; - if (width <= 0 && height <= 0) return; - if (curEllipseMode === 2) { - width *= 2; - height *= 2 - } else if (curEllipseMode === 1) { - width = width - x; - height = height - y; - x += width / 2; - y += height / 2 - } else if (curEllipseMode === 0) { - x += width / 2; - y += height / 2 - } - var w = width / 2, - h = height / 2, - C = 0.5522847498307933, - c_x = C * w, - c_y = C * h; - p.beginShape(); - p.vertex(x + w, y); - p.bezierVertex(x + w, y - c_y, 0, x + c_x, y - h, 0, x, y - h, 0); - p.bezierVertex(x - c_x, y - h, 0, x - w, y - c_y, 0, x - w, y, 0); - p.bezierVertex(x - w, y + c_y, 0, x - c_x, y + h, 0, x, y + h, 0); - p.bezierVertex(x + c_x, y + h, 0, x + w, y + c_y, 0, x + w, y, 0); - p.endShape(); - if (doFill) { - var xAv = 0, - yAv = 0, - i, j; - for (i = 0; i < vertArray.length; i++) { - xAv += vertArray[i][0]; - yAv += vertArray[i][1] - } - xAv /= vertArray.length; - yAv /= vertArray.length; - var vert = [], - fillVertArray = [], - colorVertArray = []; - vert[0] = xAv; - vert[1] = yAv; - vert[2] = 0; - vert[3] = 0; - vert[4] = 0; - vert[5] = fillStyle[0]; - vert[6] = fillStyle[1]; - vert[7] = fillStyle[2]; - vert[8] = fillStyle[3]; - vert[9] = strokeStyle[0]; - vert[10] = strokeStyle[1]; - vert[11] = strokeStyle[2]; - vert[12] = strokeStyle[3]; - vert[13] = normalX; - vert[14] = normalY; - vert[15] = normalZ; - vertArray.unshift(vert); - for (i = 0; i < vertArray.length; i++) { - for (j = 0; j < 3; j++) fillVertArray.push(vertArray[i][j]); - for (j = 5; j < 9; j++) colorVertArray.push(vertArray[i][j]) - } - fill3D(fillVertArray, "TRIANGLE_FAN", colorVertArray) - } - }; - p.normal = function(nx, ny, nz) { - if (arguments.length !== 3 || !(typeof nx === "number" && typeof ny === "number" && typeof nz === "number")) throw "normal() requires three numeric arguments."; - normalX = nx; - normalY = ny; - normalZ = nz; - if (curShape !== 0) if (normalMode === 0) normalMode = 1; - else if (normalMode === 1) normalMode = 2 - }; - p.save = function(file, img) { - if (img !== undef) return window.open(img.toDataURL(), "_blank"); - return window.open(p.externals.canvas.toDataURL(), "_blank") - }; - var saveNumber = 0; - p.saveFrame = function(file) { - if (file === undef) file = "screen-####.png"; - var frameFilename = file.replace(/#+/, function(all) { - var s = "" + saveNumber++; - while (s.length < all.length) s = "0" + s; - return s - }); - p.save(frameFilename) - }; - var utilityContext2d = document.createElement("canvas").getContext("2d"); - var canvasDataCache = [undef, undef, undef]; - - function getCanvasData(obj, w, h) { - var canvasData = canvasDataCache.shift(); - if (canvasData === undef) { - canvasData = {}; - canvasData.canvas = document.createElement("canvas"); - canvasData.context = canvasData.canvas.getContext("2d") - } - canvasDataCache.push(canvasData); - var canvas = canvasData.canvas, - context = canvasData.context, - width = w || obj.width, - height = h || obj.height; - canvas.width = width; - canvas.height = height; - if (!obj) context.clearRect(0, 0, width, height); - else if ("data" in obj) context.putImageData(obj, 0, 0); - else { - context.clearRect(0, 0, width, height); - context.drawImage(obj, 0, 0, width, height) - } - return canvasData - } - function buildPixelsObject(pImage) { - return { - getLength: function(aImg) { - return function() { - if (aImg.isRemote) throw "Image is loaded remotely. Cannot get length."; - else return aImg.imageData.data.length ? aImg.imageData.data.length / 4 : 0 - } - }(pImage), - getPixel: function(aImg) { - return function(i) { - var offset = i * 4, - data = aImg.imageData.data; - if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixels."; - return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 - } - }(pImage), - setPixel: function(aImg) { - return function(i, c) { - var offset = i * 4, - data = aImg.imageData.data; - if (aImg.isRemote) throw "Image is loaded remotely. Cannot set pixel."; - data[offset + 0] = (c >> 16) & 255; - data[offset + 1] = (c >> 8) & 255; - data[offset + 2] = c & 255; - data[offset + 3] = (c >> 24) & 255; - aImg.__isDirty = true - } - }(pImage), - toArray: function(aImg) { - return function() { - var arr = [], - data = aImg.imageData.data, - length = aImg.width * aImg.height; - if (aImg.isRemote) throw "Image is loaded remotely. Cannot get pixels."; - for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push((data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255); - return arr - } - }(pImage), - set: function(aImg) { - return function(arr) { - var offset, data, c; - if (this.isRemote) throw "Image is loaded remotely. Cannot set pixels."; - data = aImg.imageData.data; - for (var i = 0, aL = arr.length; i < aL; i++) { - c = arr[i]; - offset = i * 4; - data[offset + 0] = (c >> 16) & 255; - data[offset + 1] = (c >> 8) & 255; - data[offset + 2] = c & 255; - data[offset + 3] = (c >> 24) & 255 - } - aImg.__isDirty = true - } - }(pImage) - } - } - var PImage = function(aWidth, aHeight, aFormat) { - this.__isDirty = false; - if (aWidth instanceof HTMLImageElement) this.fromHTMLImageData(aWidth); - else if (aHeight || aFormat) { - this.width = aWidth || 1; - this.height = aHeight || 1; - var canvas = this.sourceImg = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - var imageData = this.imageData = canvas.getContext("2d").createImageData(this.width, this.height); - this.format = aFormat === 2 || aFormat === 4 ? aFormat : 1; - if (this.format === 1) for (var i = 3, data = this.imageData.data, len = data.length; i < len; i += 4) data[i] = 255; - this.__isDirty = true; - this.updatePixels() - } else { - this.width = 0; - this.height = 0; - this.imageData = utilityContext2d.createImageData(1, 1); - this.format = 2 - } - this.pixels = buildPixelsObject(this) - }; - PImage.prototype = { - __isPImage: true, - updatePixels: function() { - var canvas = this.sourceImg; - if (canvas && canvas instanceof HTMLCanvasElement && this.__isDirty) canvas.getContext("2d").putImageData(this.imageData, 0, 0); - this.__isDirty = false - }, - fromHTMLImageData: function(htmlImg) { - var canvasData = getCanvasData(htmlImg); - try { - var imageData = canvasData.context.getImageData(0, 0, htmlImg.width, htmlImg.height); - this.fromImageData(imageData) - } catch(e) { - if (htmlImg.width && htmlImg.height) { - this.isRemote = true; - this.width = htmlImg.width; - this.height = htmlImg.height - } - } - this.sourceImg = htmlImg - }, - "get": function(x, y, w, h) { - if (!arguments.length) return p.get(this); - if (arguments.length === 2) return p.get(x, y, this); - if (arguments.length === 4) return p.get(x, y, w, h, this) - }, - "set": function(x, y, c) { - p.set(x, y, c, this); - this.__isDirty = true - }, - blend: function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE) { - if (arguments.length === 9) p.blend(this, srcImg, x, y, width, height, dx, dy, dwidth, dheight, this); - else if (arguments.length === 10) p.blend(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE, this); - delete this.sourceImg - }, - copy: function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight) { - if (arguments.length === 8) p.blend(this, srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, 0, this); - else if (arguments.length === 9) p.blend(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight, 0, this); - delete this.sourceImg - }, - filter: function(mode, param) { - if (arguments.length === 2) p.filter(mode, param, this); - else if (arguments.length === 1) p.filter(mode, null, this); - delete this.sourceImg - }, - save: function(file) { - p.save(file, this) - }, - resize: function(w, h) { - if (this.isRemote) throw "Image is loaded remotely. Cannot resize."; - if (this.width !== 0 || this.height !== 0) { - if (w === 0 && h !== 0) w = Math.floor(this.width / this.height * h); - else if (h === 0 && w !== 0) h = Math.floor(this.height / this.width * w); - var canvas = getCanvasData(this.imageData).canvas; - var imageData = getCanvasData(canvas, w, h).context.getImageData(0, 0, w, h); - this.fromImageData(imageData) - } - }, - mask: function(mask) { - var obj = this.toImageData(), - i, size; - if (mask instanceof PImage || mask.__isPImage) if (mask.width === this.width && mask.height === this.height) { - mask = mask.toImageData(); - for (i = 2, size = this.width * this.height * 4; i < size; i += 4) obj.data[i + 1] = mask.data[i] - } else throw "mask must have the same dimensions as PImage."; - else if (mask instanceof - Array) if (this.width * this.height === mask.length) for (i = 0, size = mask.length; i < size; ++i) obj.data[i * 4 + 3] = mask[i]; - else throw "mask array must be the same length as PImage pixels array."; - this.fromImageData(obj) - }, - loadPixels: nop, - toImageData: function() { - if (this.isRemote) return this.sourceImg; - if (!this.__isDirty) return this.imageData; - var canvasData = getCanvasData(this.sourceImg); - return canvasData.context.getImageData(0, 0, this.width, this.height) - }, - toDataURL: function() { - if (this.isRemote) throw "Image is loaded remotely. Cannot create dataURI."; - var canvasData = getCanvasData(this.imageData); - return canvasData.canvas.toDataURL() - }, - fromImageData: function(canvasImg) { - var w = canvasImg.width, - h = canvasImg.height, - canvas = document.createElement("canvas"), - ctx = canvas.getContext("2d"); - this.width = canvas.width = w; - this.height = canvas.height = h; - ctx.putImageData(canvasImg, 0, 0); - this.format = 2; - this.imageData = canvasImg; - this.sourceImg = canvas - } - }; - p.PImage = PImage; - p.createImage = function(w, h, mode) { - return new PImage(w, h, mode) - }; - p.loadImage = function(file, type, callback) { - if (type) file = file + "." + type; - var pimg; - if (curSketch.imageCache.images[file]) { - pimg = new PImage(curSketch.imageCache.images[file]); - pimg.loaded = true; - return pimg - } - pimg = new PImage; - var img = document.createElement("img"); - pimg.sourceImg = img; - img.onload = function(aImage, aPImage, aCallback) { - var image = aImage; - var pimg = aPImage; - var callback = aCallback; - return function() { - pimg.fromHTMLImageData(image); - pimg.loaded = true; - if (callback) callback() - } - }(img, pimg, callback); - img.src = file; - return pimg - }; - p.requestImage = p.loadImage; - - function get$2(x, y) { - var data; - if (x >= p.width || x < 0 || y < 0 || y >= p.height) return 0; - if (isContextReplaced) { - var offset = ((0 | x) + p.width * (0 | y)) * 4; - data = p.imageData.data; - return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 - } - data = p.toImageData(0 | x, 0 | y, 1, 1).data; - return (data[3] & 255) << 24 | (data[0] & 255) << 16 | (data[1] & 255) << 8 | data[2] & 255 - } - function get$3(x, y, img) { - if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y."; - var offset = y * img.width * 4 + x * 4, - data = img.imageData.data; - return (data[offset + 3] & 255) << 24 | (data[offset] & 255) << 16 | (data[offset + 1] & 255) << 8 | data[offset + 2] & 255 - } - function get$4(x, y, w, h) { - var c = new PImage(w, h, 2); - c.fromImageData(p.toImageData(x, y, w, h)); - return c - } - function get$5(x, y, w, h, img) { - if (img.isRemote) throw "Image is loaded remotely. Cannot get x,y,w,h."; - var c = new PImage(w, h, 2), - cData = c.imageData.data, - imgWidth = img.width, - imgHeight = img.height, - imgData = img.imageData.data; - var startRow = Math.max(0, -y), - startColumn = Math.max(0, -x), - stopRow = Math.min(h, imgHeight - y), - stopColumn = Math.min(w, imgWidth - x); - for (var i = startRow; i < stopRow; ++i) { - var sourceOffset = ((y + i) * imgWidth + (x + startColumn)) * 4; - var targetOffset = (i * w + startColumn) * 4; - for (var j = startColumn; j < stopColumn; ++j) { - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++]; - cData[targetOffset++] = imgData[sourceOffset++] - } - } - c.__isDirty = true; - return c - } - p.get = function(x, y, w, h, img) { - if (img !== undefined) return get$5(x, y, w, h, img); - if (h !== undefined) return get$4(x, y, w, h); - if (w !== undefined) return get$3(x, y, w); - if (y !== undefined) return get$2(x, y); - if (x !== undefined) return get$5(0, 0, x.width, x.height, x); - return get$4(0, 0, p.width, p.height) - }; - p.createGraphics = function(w, h, render) { - var pg = new Processing; - pg.size(w, h, render); - pg.background(0, 0); - return pg - }; - - function resetContext() { - if (isContextReplaced) { - curContext = originalContext; - isContextReplaced = false; - p.updatePixels() - } - } - - function SetPixelContextWrapper() { - function wrapFunction(newContext, name) { - function wrapper() { - resetContext(); - curContext[name].apply(curContext, arguments) - } - newContext[name] = wrapper - } - function wrapProperty(newContext, name) { - function getter() { - resetContext(); - return curContext[name] - } - function setter(value) { - resetContext(); - curContext[name] = value - } - p.defineProperty(newContext, name, { - get: getter, - set: setter - }) - } - for (var n in curContext) if (typeof curContext[n] === "function") wrapFunction(this, n); - else wrapProperty(this, n) - } - function replaceContext() { - if (isContextReplaced) return; - p.loadPixels(); - if (proxyContext === null) { - originalContext = curContext; - proxyContext = new SetPixelContextWrapper - } - isContextReplaced = true; - curContext = proxyContext; - setPixelsCached = 0 - } - function set$3(x, y, c) { - if (x < p.width && x >= 0 && y >= 0 && y < p.height) { - replaceContext(); - p.pixels.setPixel((0 | x) + p.width * (0 | y), c); - if (++setPixelsCached > maxPixelsCached) resetContext() - } - } - function set$4(x, y, obj, img) { - if (img.isRemote) throw "Image is loaded remotely. Cannot set x,y."; - var c = p.color.toArray(obj); - var offset = y * img.width * 4 + x * 4; - var data = img.imageData.data; - data[offset] = c[0]; - data[offset + 1] = c[1]; - data[offset + 2] = c[2]; - data[offset + 3] = c[3] - } - p.set = function(x, y, obj, img) { - var color, oldFill; - if (arguments.length === 3) if (typeof obj === "number") set$3(x, y, obj); - else { - if (obj instanceof PImage || obj.__isPImage) p.image(obj, x, y) - } else if (arguments.length === 4) set$4(x, y, obj, img) - }; - p.imageData = {}; - p.pixels = { - getLength: function() { - return p.imageData.data.length ? p.imageData.data.length / 4 : 0 - }, - getPixel: function(i) { - var offset = i * 4, - data = p.imageData.data; - return data[offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255 - }, - setPixel: function(i, c) { - var offset = i * 4, - data = p.imageData.data; - data[offset + 0] = (c & 16711680) >>> 16; - data[offset + 1] = (c & 65280) >>> 8; - data[offset + 2] = c & 255; - data[offset + 3] = (c & 4278190080) >>> 24 - }, - toArray: function() { - var arr = [], - length = p.imageData.width * p.imageData.height, - data = p.imageData.data; - for (var i = 0, offset = 0; i < length; i++, offset += 4) arr.push(data[offset + 3] << 24 & 4278190080 | data[offset + 0] << 16 & 16711680 | data[offset + 1] << 8 & 65280 | data[offset + 2] & 255); - return arr - }, - set: function(arr) { - for (var i = 0, aL = arr.length; i < aL; i++) this.setPixel(i, arr[i]) - } - }; - p.loadPixels = function() { - p.imageData = drawing.$ensureContext().getImageData(0, 0, p.width, p.height) - }; - p.updatePixels = function() { - if (p.imageData) drawing.$ensureContext().putImageData(p.imageData, 0, 0) - }; - p.hint = function(which) { - var curContext = drawing.$ensureContext(); - if (which === 4) { - curContext.disable(curContext.DEPTH_TEST); - curContext.depthMask(false); - curContext.clear(curContext.DEPTH_BUFFER_BIT) - } else if (which === -4) { - curContext.enable(curContext.DEPTH_TEST); - curContext.depthMask(true) - } else if (which === -1 || which === 2) renderSmooth = true; - else if (which === 1) renderSmooth = false - }; - var backgroundHelper = function(arg1, arg2, arg3, arg4) { - var obj; - if (arg1 instanceof PImage || arg1.__isPImage) { - obj = arg1; - if (!obj.loaded) throw "Error using image in background(): PImage not loaded."; - if (obj.width !== p.width || obj.height !== p.height) throw "Background image must be the same dimensions as the canvas."; - } else obj = p.color(arg1, arg2, arg3, arg4); - backgroundObj = obj - }; - Drawing2D.prototype.background = function(arg1, arg2, arg3, arg4) { - if (arg1 !== undef) backgroundHelper(arg1, arg2, arg3, arg4); - if (backgroundObj instanceof PImage || backgroundObj.__isPImage) { - saveContext(); - curContext.setTransform(1, 0, 0, 1, 0, 0); - p.image(backgroundObj, 0, 0); - restoreContext() - } else { - saveContext(); - curContext.setTransform(1, 0, 0, 1, 0, 0); - if (p.alpha(backgroundObj) !== colorModeA) curContext.clearRect(0, 0, p.width, p.height); - curContext.fillStyle = p.color.toString(backgroundObj); - curContext.fillRect(0, 0, p.width, p.height); - isFillDirty = true; - restoreContext() - } - }; - Drawing3D.prototype.background = function(arg1, arg2, arg3, arg4) { - if (arguments.length > 0) backgroundHelper(arg1, arg2, arg3, arg4); - var c = p.color.toGLArray(backgroundObj); - curContext.clearColor(c[0], c[1], c[2], c[3]); - curContext.clear(curContext.COLOR_BUFFER_BIT | curContext.DEPTH_BUFFER_BIT) - }; - Drawing2D.prototype.image = function(img, x, y, w, h) { - x = Math.round(x); - y = Math.round(y); - if (img.width > 0) { - var wid = w || img.width; - var hgt = h || img.height; - var bounds = imageModeConvert(x || 0, y || 0, w || img.width, h || img.height, arguments.length < 4); - var fastImage = !!img.sourceImg && curTint === null; - if (fastImage) { - var htmlElement = img.sourceImg; - if (img.__isDirty) img.updatePixels(); - curContext.drawImage(htmlElement, 0, 0, htmlElement.width, htmlElement.height, bounds.x, bounds.y, bounds.w, bounds.h) - } else { - var obj = img.toImageData(); - if (curTint !== null) { - curTint(obj); - img.__isDirty = true - } - curContext.drawImage(getCanvasData(obj).canvas, 0, 0, img.width, img.height, bounds.x, bounds.y, bounds.w, bounds.h) - } - } - }; - Drawing3D.prototype.image = function(img, x, y, w, h) { - if (img.width > 0) { - x = Math.round(x); - y = Math.round(y); - w = w || img.width; - h = h || img.height; - p.beginShape(p.QUADS); - p.texture(img); - p.vertex(x, y, 0, 0, 0); - p.vertex(x, y + h, 0, 0, h); - p.vertex(x + w, y + h, 0, w, h); - p.vertex(x + w, y, 0, w, 0); - p.endShape() - } - }; - p.tint = function(a1, a2, a3, a4) { - var tintColor = p.color(a1, a2, a3, a4); - var r = p.red(tintColor) / colorModeX; - var g = p.green(tintColor) / colorModeY; - var b = p.blue(tintColor) / colorModeZ; - var a = p.alpha(tintColor) / colorModeA; - curTint = function(obj) { - var data = obj.data, - length = 4 * obj.width * obj.height; - for (var i = 0; i < length;) { - data[i++] *= r; - data[i++] *= g; - data[i++] *= b; - data[i++] *= a - } - }; - curTint3d = function(data) { - for (var i = 0; i < data.length;) { - data[i++] = r; - data[i++] = g; - data[i++] = b; - data[i++] = a - } - } - }; - p.noTint = function() { - curTint = null; - curTint3d = null - }; - p.copy = function(src, sx, sy, sw, sh, dx, dy, dw, dh) { - if (dh === undef) { - dh = dw; - dw = dy; - dy = dx; - dx = sh; - sh = sw; - sw = sy; - sy = sx; - sx = src; - src = p - } - p.blend(src, sx, sy, sw, sh, dx, dy, dw, dh, 0) - }; - p.blend = function(src, sx, sy, sw, sh, dx, dy, dw, dh, mode, pimgdest) { - if (src.isRemote) throw "Image is loaded remotely. Cannot blend image."; - if (mode === undef) { - mode = dh; - dh = dw; - dw = dy; - dy = dx; - dx = sh; - sh = sw; - sw = sy; - sy = sx; - sx = src; - src = p - } - var sx2 = sx + sw, - sy2 = sy + sh, - dx2 = dx + dw, - dy2 = dy + dh, - dest = pimgdest || p; - if (pimgdest === undef || mode === undef) p.loadPixels(); - src.loadPixels(); - if (src === p && p.intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) p.blit_resize(p.get(sx, sy, sx2 - sx, sy2 - sy), 0, 0, sx2 - sx - 1, sy2 - sy - 1, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); - else p.blit_resize(src, sx, sy, sx2, sy2, dest.imageData.data, dest.width, dest.height, dx, dy, dx2, dy2, mode); - if (pimgdest === undef) p.updatePixels() - }; - var buildBlurKernel = function(r) { - var radius = p.floor(r * 3.5), - i, radiusi; - radius = radius < 1 ? 1 : radius < 248 ? radius : 248; - if (p.shared.blurRadius !== radius) { - p.shared.blurRadius = radius; - p.shared.blurKernelSize = 1 + (p.shared.blurRadius << 1); - p.shared.blurKernel = new Float32Array(p.shared.blurKernelSize); - var sharedBlurKernal = p.shared.blurKernel; - var sharedBlurKernelSize = p.shared.blurKernelSize; - var sharedBlurRadius = p.shared.blurRadius; - for (i = 0; i < sharedBlurKernelSize; i++) sharedBlurKernal[i] = 0; - var radiusiSquared = (radius - 1) * (radius - 1); - for (i = 1; i < radius; i++) sharedBlurKernal[radius + i] = sharedBlurKernal[radiusi] = radiusiSquared; - sharedBlurKernal[radius] = radius * radius - } - }; - var blurARGB = function(r, aImg) { - var sum, cr, cg, cb, ca, c, m; - var read, ri, ym, ymi, bk0; - var wh = aImg.pixels.getLength(); - var r2 = new Float32Array(wh); - var g2 = new Float32Array(wh); - var b2 = new Float32Array(wh); - var a2 = new Float32Array(wh); - var yi = 0; - var x, y, i, offset; - buildBlurKernel(r); - var aImgHeight = aImg.height; - var aImgWidth = aImg.width; - var sharedBlurKernelSize = p.shared.blurKernelSize; - var sharedBlurRadius = p.shared.blurRadius; - var sharedBlurKernal = p.shared.blurKernel; - var pix = aImg.imageData.data; - for (y = 0; y < aImgHeight; y++) { - for (x = 0; x < aImgWidth; x++) { - cb = cg = cr = ca = sum = 0; - read = x - sharedBlurRadius; - if (read < 0) { - bk0 = -read; - read = 0 - } else { - if (read >= aImgWidth) break; - bk0 = 0 - } - for (i = bk0; i < sharedBlurKernelSize; i++) { - if (read >= aImgWidth) break; - offset = (read + yi) * 4; - m = sharedBlurKernal[i]; - ca += m * pix[offset + 3]; - cr += m * pix[offset]; - cg += m * pix[offset + 1]; - cb += m * pix[offset + 2]; - sum += m; - read++ - } - ri = yi + x; - a2[ri] = ca / sum; - r2[ri] = cr / sum; - g2[ri] = cg / sum; - b2[ri] = cb / sum - } - yi += aImgWidth - } - yi = 0; - ym = -sharedBlurRadius; - ymi = ym * aImgWidth; - for (y = 0; y < aImgHeight; y++) { - for (x = 0; x < aImgWidth; x++) { - cb = cg = cr = ca = sum = 0; - if (ym < 0) { - bk0 = ri = -ym; - read = x - } else { - if (ym >= aImgHeight) break; - bk0 = 0; - ri = ym; - read = x + ymi - } - for (i = bk0; i < sharedBlurKernelSize; i++) { - if (ri >= aImgHeight) break; - m = sharedBlurKernal[i]; - ca += m * a2[read]; - cr += m * r2[read]; - cg += m * g2[read]; - cb += m * b2[read]; - sum += m; - ri++; - read += aImgWidth - } - offset = (x + yi) * 4; - pix[offset] = cr / sum; - pix[offset + 1] = cg / sum; - pix[offset + 2] = cb / sum; - pix[offset + 3] = ca / sum - } - yi += aImgWidth; - ymi += aImgWidth; - ym++ - } - }; - var dilate = function(isInverted, aImg) { - var currIdx = 0; - var maxIdx = aImg.pixels.getLength(); - var out = new Int32Array(maxIdx); - var currRowIdx, maxRowIdx, colOrig, colOut, currLum; - var idxRight, idxLeft, idxUp, idxDown, colRight, colLeft, colUp, colDown, lumRight, lumLeft, lumUp, lumDown; - if (!isInverted) while (currIdx < maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + aImg.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = aImg.pixels.getPixel(currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - aImg.width; - idxDown = currIdx + aImg.width; - if (idxLeft < currRowIdx) idxLeft = currIdx; - if (idxRight >= maxRowIdx) idxRight = currIdx; - if (idxUp < 0) idxUp = 0; - if (idxDown >= maxIdx) idxDown = currIdx; - colUp = aImg.pixels.getPixel(idxUp); - colLeft = aImg.pixels.getPixel(idxLeft); - colDown = aImg.pixels.getPixel(idxDown); - colRight = aImg.pixels.getPixel(idxRight); - currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); - lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); - lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); - lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (colUp & 255); - lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); - if (lumLeft > currLum) { - colOut = colLeft; - currLum = lumLeft - } - if (lumRight > currLum) { - colOut = colRight; - currLum = lumRight - } - if (lumUp > currLum) { - colOut = colUp; - currLum = lumUp - } - if (lumDown > currLum) { - colOut = colDown; - currLum = lumDown - } - out[currIdx++] = colOut - } - } else while (currIdx < maxIdx) { - currRowIdx = currIdx; - maxRowIdx = currIdx + aImg.width; - while (currIdx < maxRowIdx) { - colOrig = colOut = aImg.pixels.getPixel(currIdx); - idxLeft = currIdx - 1; - idxRight = currIdx + 1; - idxUp = currIdx - aImg.width; - idxDown = currIdx + aImg.width; - if (idxLeft < currRowIdx) idxLeft = currIdx; - if (idxRight >= maxRowIdx) idxRight = currIdx; - if (idxUp < 0) idxUp = 0; - if (idxDown >= maxIdx) idxDown = currIdx; - colUp = aImg.pixels.getPixel(idxUp); - colLeft = aImg.pixels.getPixel(idxLeft); - colDown = aImg.pixels.getPixel(idxDown); - colRight = aImg.pixels.getPixel(idxRight); - currLum = 77 * (colOrig >> 16 & 255) + 151 * (colOrig >> 8 & 255) + 28 * (colOrig & 255); - lumLeft = 77 * (colLeft >> 16 & 255) + 151 * (colLeft >> 8 & 255) + 28 * (colLeft & 255); - lumRight = 77 * (colRight >> 16 & 255) + 151 * (colRight >> 8 & 255) + 28 * (colRight & 255); - lumUp = 77 * (colUp >> 16 & 255) + 151 * (colUp >> 8 & 255) + 28 * (colUp & 255); - lumDown = 77 * (colDown >> 16 & 255) + 151 * (colDown >> 8 & 255) + 28 * (colDown & 255); - if (lumLeft < currLum) { - colOut = colLeft; - currLum = lumLeft - } - if (lumRight < currLum) { - colOut = colRight; - currLum = lumRight - } - if (lumUp < currLum) { - colOut = colUp; - currLum = lumUp - } - if (lumDown < currLum) { - colOut = colDown; - currLum = lumDown - } - out[currIdx++] = colOut - } - } - aImg.pixels.set(out) - }; - p.filter = function(kind, param, aImg) { - var img, col, lum, i; - if (arguments.length === 3) { - aImg.loadPixels(); - img = aImg - } else { - p.loadPixels(); - img = p - } - if (param === undef) param = null; - if (img.isRemote) throw "Image is loaded remotely. Cannot filter image."; - var imglen = img.pixels.getLength(); - switch (kind) { - case 11: - var radius = param || 1; - blurARGB(radius, img); - break; - case 12: - if (img.format === 4) { - for (i = 0; i < imglen; i++) { - col = 255 - img.pixels.getPixel(i); - img.pixels.setPixel(i, 4278190080 | col << 16 | col << 8 | col) - } - img.format = 1 - } else for (i = 0; i < imglen; i++) { - col = img.pixels.getPixel(i); - lum = 77 * (col >> 16 & 255) + 151 * (col >> 8 & 255) + 28 * (col & 255) >> 8; - img.pixels.setPixel(i, col & 4278190080 | lum << 16 | lum << 8 | lum) - } - break; - case 13: - for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel(i) ^ 16777215); - break; - case 15: - if (param === null) throw "Use filter(POSTERIZE, int levels) instead of filter(POSTERIZE)"; - var levels = p.floor(param); - if (levels < 2 || levels > 255) throw "Levels must be between 2 and 255 for filter(POSTERIZE, levels)"; - var levels1 = levels - 1; - for (i = 0; i < imglen; i++) { - var rlevel = img.pixels.getPixel(i) >> 16 & 255; - var glevel = img.pixels.getPixel(i) >> 8 & 255; - var blevel = img.pixels.getPixel(i) & 255; - rlevel = (rlevel * levels >> 8) * 255 / levels1; - glevel = (glevel * levels >> 8) * 255 / levels1; - blevel = (blevel * levels >> 8) * 255 / levels1; - img.pixels.setPixel(i, 4278190080 & img.pixels.getPixel(i) | rlevel << 16 | glevel << 8 | blevel) - } - break; - case 14: - for (i = 0; i < imglen; i++) img.pixels.setPixel(i, img.pixels.getPixel(i) | 4278190080); - img.format = 1; - break; - case 16: - if (param === null) param = 0.5; - if (param < 0 || param > 1) throw "Level must be between 0 and 1 for filter(THRESHOLD, level)"; - var thresh = p.floor(param * 255); - for (i = 0; i < imglen; i++) { - var max = p.max((img.pixels.getPixel(i) & 16711680) >> 16, p.max((img.pixels.getPixel(i) & 65280) >> 8, img.pixels.getPixel(i) & 255)); - img.pixels.setPixel(i, img.pixels.getPixel(i) & 4278190080 | (max < thresh ? 0 : 16777215)) - } - break; - case 17: - dilate(true, img); - break; - case 18: - dilate(false, img); - break - } - img.updatePixels() - }; - p.shared = { - fracU: 0, - ifU: 0, - fracV: 0, - ifV: 0, - u1: 0, - u2: 0, - v1: 0, - v2: 0, - sX: 0, - sY: 0, - iw: 0, - iw1: 0, - ih1: 0, - ul: 0, - ll: 0, - ur: 0, - lr: 0, - cUL: 0, - cLL: 0, - cUR: 0, - cLR: 0, - srcXOffset: 0, - srcYOffset: 0, - r: 0, - g: 0, - b: 0, - a: 0, - srcBuffer: null, - blurRadius: 0, - blurKernelSize: 0, - blurKernel: null - }; - p.intersect = function(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2) { - var sw = sx2 - sx1 + 1; - var sh = sy2 - sy1 + 1; - var dw = dx2 - dx1 + 1; - var dh = dy2 - dy1 + 1; - if (dx1 < sx1) { - dw += dx1 - sx1; - if (dw > sw) dw = sw - } else { - var w = sw + sx1 - dx1; - if (dw > w) dw = w - } - if (dy1 < sy1) { - dh += dy1 - sy1; - if (dh > sh) dh = sh - } else { - var h = sh + sy1 - dy1; - if (dh > h) dh = h - } - return ! (dw <= 0 || dh <= 0) - }; - var blendFuncs = {}; - blendFuncs[1] = p.modes.blend; - blendFuncs[2] = p.modes.add; - blendFuncs[4] = p.modes.subtract; - blendFuncs[8] = p.modes.lightest; - blendFuncs[16] = p.modes.darkest; - blendFuncs[0] = p.modes.replace; - blendFuncs[32] = p.modes.difference; - blendFuncs[64] = p.modes.exclusion; - blendFuncs[128] = p.modes.multiply; - blendFuncs[256] = p.modes.screen; - blendFuncs[512] = p.modes.overlay; - blendFuncs[1024] = p.modes.hard_light; - blendFuncs[2048] = p.modes.soft_light; - blendFuncs[4096] = p.modes.dodge; - blendFuncs[8192] = p.modes.burn; - p.blit_resize = function(img, srcX1, srcY1, srcX2, srcY2, destPixels, screenW, screenH, destX1, destY1, destX2, destY2, mode) { - var x, y; - if (srcX1 < 0) srcX1 = 0; - if (srcY1 < 0) srcY1 = 0; - if (srcX2 >= img.width) srcX2 = img.width - 1; - if (srcY2 >= img.height) srcY2 = img.height - 1; - var srcW = srcX2 - srcX1; - var srcH = srcY2 - srcY1; - var destW = destX2 - destX1; - var destH = destY2 - destY1; - if (destW <= 0 || destH <= 0 || srcW <= 0 || srcH <= 0 || destX1 >= screenW || destY1 >= screenH || srcX1 >= img.width || srcY1 >= img.height) return; - var dx = Math.floor(srcW / destW * 32768); - var dy = Math.floor(srcH / destH * 32768); - var pshared = p.shared; - pshared.srcXOffset = Math.floor(destX1 < 0 ? -destX1 * dx : srcX1 * 32768); - pshared.srcYOffset = Math.floor(destY1 < 0 ? -destY1 * dy : srcY1 * 32768); - if (destX1 < 0) { - destW += destX1; - destX1 = 0 - } - if (destY1 < 0) { - destH += destY1; - destY1 = 0 - } - destW = Math.min(destW, screenW - destX1); - destH = Math.min(destH, screenH - destY1); - var destOffset = destY1 * screenW + destX1; - var destColor; - pshared.srcBuffer = img.imageData.data; - pshared.iw = img.width; - pshared.iw1 = img.width - 1; - pshared.ih1 = img.height - 1; - var filterBilinear = p.filter_bilinear, - filterNewScanline = p.filter_new_scanline, - blendFunc = blendFuncs[mode], - blendedColor, idx, cULoffset, cURoffset, cLLoffset, cLRoffset, ALPHA_MASK = 4278190080, - RED_MASK = 16711680, - GREEN_MASK = 65280, - BLUE_MASK = 255, - PREC_MAXVAL = 32767, - PRECISIONB = 15, - PREC_RED_SHIFT = 1, - PREC_ALPHA_SHIFT = 9, - srcBuffer = pshared.srcBuffer, - min = Math.min; - for (y = 0; y < destH; y++) { - pshared.sX = pshared.srcXOffset; - pshared.fracV = pshared.srcYOffset & PREC_MAXVAL; - pshared.ifV = PREC_MAXVAL - pshared.fracV; - pshared.v1 = (pshared.srcYOffset >> PRECISIONB) * pshared.iw; - pshared.v2 = min((pshared.srcYOffset >> PRECISIONB) + 1, pshared.ih1) * pshared.iw; - for (x = 0; x < destW; x++) { - idx = (destOffset + x) * 4; - destColor = destPixels[idx + 3] << 24 & ALPHA_MASK | destPixels[idx] << 16 & RED_MASK | destPixels[idx + 1] << 8 & GREEN_MASK | destPixels[idx + 2] & BLUE_MASK; - pshared.fracU = pshared.sX & PREC_MAXVAL; - pshared.ifU = PREC_MAXVAL - pshared.fracU; - pshared.ul = pshared.ifU * pshared.ifV >> PRECISIONB; - pshared.ll = pshared.ifU * pshared.fracV >> PRECISIONB; - pshared.ur = pshared.fracU * pshared.ifV >> PRECISIONB; - pshared.lr = pshared.fracU * pshared.fracV >> PRECISIONB; - pshared.u1 = pshared.sX >> PRECISIONB; - pshared.u2 = min(pshared.u1 + 1, pshared.iw1); - cULoffset = (pshared.v1 + pshared.u1) * 4; - cURoffset = (pshared.v1 + pshared.u2) * 4; - cLLoffset = (pshared.v2 + pshared.u1) * 4; - cLRoffset = (pshared.v2 + pshared.u2) * 4; - pshared.cUL = srcBuffer[cULoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cULoffset] << 16 & RED_MASK | srcBuffer[cULoffset + 1] << 8 & GREEN_MASK | srcBuffer[cULoffset + 2] & BLUE_MASK; - pshared.cUR = srcBuffer[cURoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cURoffset] << 16 & RED_MASK | srcBuffer[cURoffset + 1] << 8 & GREEN_MASK | srcBuffer[cURoffset + 2] & BLUE_MASK; - pshared.cLL = srcBuffer[cLLoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cLLoffset] << 16 & RED_MASK | srcBuffer[cLLoffset + 1] << 8 & GREEN_MASK | srcBuffer[cLLoffset + 2] & BLUE_MASK; - pshared.cLR = srcBuffer[cLRoffset + 3] << 24 & ALPHA_MASK | srcBuffer[cLRoffset] << 16 & RED_MASK | srcBuffer[cLRoffset + 1] << 8 & GREEN_MASK | srcBuffer[cLRoffset + 2] & BLUE_MASK; - pshared.r = pshared.ul * ((pshared.cUL & RED_MASK) >> 16) + pshared.ll * ((pshared.cLL & RED_MASK) >> 16) + pshared.ur * ((pshared.cUR & RED_MASK) >> 16) + pshared.lr * ((pshared.cLR & RED_MASK) >> 16) << PREC_RED_SHIFT & RED_MASK; - pshared.g = pshared.ul * (pshared.cUL & GREEN_MASK) + pshared.ll * (pshared.cLL & GREEN_MASK) + pshared.ur * (pshared.cUR & GREEN_MASK) + pshared.lr * (pshared.cLR & GREEN_MASK) >>> PRECISIONB & GREEN_MASK; - pshared.b = pshared.ul * (pshared.cUL & BLUE_MASK) + pshared.ll * (pshared.cLL & BLUE_MASK) + pshared.ur * (pshared.cUR & BLUE_MASK) + pshared.lr * (pshared.cLR & BLUE_MASK) >>> PRECISIONB; - pshared.a = pshared.ul * ((pshared.cUL & ALPHA_MASK) >>> 24) + pshared.ll * ((pshared.cLL & ALPHA_MASK) >>> 24) + pshared.ur * ((pshared.cUR & ALPHA_MASK) >>> 24) + pshared.lr * ((pshared.cLR & ALPHA_MASK) >>> 24) << PREC_ALPHA_SHIFT & ALPHA_MASK; - blendedColor = blendFunc(destColor, pshared.a | pshared.r | pshared.g | pshared.b); - destPixels[idx] = (blendedColor & RED_MASK) >>> 16; - destPixels[idx + 1] = (blendedColor & GREEN_MASK) >>> 8; - destPixels[idx + 2] = blendedColor & BLUE_MASK; - destPixels[idx + 3] = (blendedColor & ALPHA_MASK) >>> 24; - pshared.sX += dx - } - destOffset += screenW; - pshared.srcYOffset += dy - } - }; - p.loadFont = function(name, size) { - if (name === undef) throw "font name required in loadFont."; - if (name.indexOf(".svg") === -1) { - if (size === undef) size = curTextFont.size; - return PFont.get(name, size) - } - var font = p.loadGlyphs(name); - return { - name: name, - css: "12px sans-serif", - glyph: true, - units_per_em: font.units_per_em, - horiz_adv_x: 1 / font.units_per_em * font.horiz_adv_x, - ascent: font.ascent, - descent: font.descent, - width: function(str) { - var width = 0; - var len = str.length; - for (var i = 0; i < len; i++) try { - width += parseFloat(p.glyphLook(p.glyphTable[name], str[i]).horiz_adv_x) - } catch(e) { - Processing.debug(e) - } - return width / p.glyphTable[name].units_per_em - } - } - }; - p.createFont = function(name, size) { - return p.loadFont(name, size) - }; - p.textFont = function(pfont, size) { - if (size !== undef) { - if (!pfont.glyph) pfont = PFont.get(pfont.name, size); - curTextSize = size - } - curTextFont = pfont; - curFontName = curTextFont.name; - curTextAscent = curTextFont.ascent; - curTextDescent = curTextFont.descent; - curTextLeading = curTextFont.leading; - var curContext = drawing.$ensureContext(); - curContext.font = curTextFont.css - }; - p.textSize = function(size) { - curTextFont = PFont.get(curFontName, size); - curTextSize = size; - curTextAscent = curTextFont.ascent; - curTextDescent = curTextFont.descent; - curTextLeading = curTextFont.leading; - var curContext = drawing.$ensureContext(); - curContext.font = curTextFont.css - }; - p.textAscent = function() { - return curTextAscent - }; - p.textDescent = function() { - return curTextDescent - }; - p.textLeading = function(leading) { - curTextLeading = leading - }; - p.textAlign = function(xalign, yalign) { - horizontalTextAlignment = xalign; - verticalTextAlignment = yalign || 0 - }; - - function toP5String(obj) { - if (obj instanceof String) return obj; - if (typeof obj === "number") { - if (obj === (0 | obj)) return obj.toString(); - return p.nf(obj, 0, 3) - } - if (obj === null || obj === undef) return ""; - return obj.toString() - } - Drawing2D.prototype.textWidth = function(str) { - var lines = toP5String(str).split(/\r?\n/g), - width = 0; - var i, linesCount = lines.length; - curContext.font = curTextFont.css; - for (i = 0; i < linesCount; ++i) width = Math.max(width, curTextFont.measureTextWidth(lines[i])); - return width | 0 - }; - Drawing3D.prototype.textWidth = function(str) { - var lines = toP5String(str).split(/\r?\n/g), - width = 0; - var i, linesCount = lines.length; - if (textcanvas === undef) textcanvas = document.createElement("canvas"); - var textContext = textcanvas.getContext("2d"); - textContext.font = curTextFont.css; - for (i = 0; i < linesCount; ++i) width = Math.max(width, textContext.measureText(lines[i]).width); - return width | 0 - }; - p.glyphLook = function(font, chr) { - try { - switch (chr) { - case "1": - return font.one; - case "2": - return font.two; - case "3": - return font.three; - case "4": - return font.four; - case "5": - return font.five; - case "6": - return font.six; - case "7": - return font.seven; - case "8": - return font.eight; - case "9": - return font.nine; - case "0": - return font.zero; - case " ": - return font.space; - case "$": - return font.dollar; - case "!": - return font.exclam; - case '"': - return font.quotedbl; - case "#": - return font.numbersign; - case "%": - return font.percent; - case "&": - return font.ampersand; - case "'": - return font.quotesingle; - case "(": - return font.parenleft; - case ")": - return font.parenright; - case "*": - return font.asterisk; - case "+": - return font.plus; - case ",": - return font.comma; - case "-": - return font.hyphen; - case ".": - return font.period; - case "/": - return font.slash; - case "_": - return font.underscore; - case ":": - return font.colon; - case ";": - return font.semicolon; - case "<": - return font.less; - case "=": - return font.equal; - case ">": - return font.greater; - case "?": - return font.question; - case "@": - return font.at; - case "[": - return font.bracketleft; - case "\\": - return font.backslash; - case "]": - return font.bracketright; - case "^": - return font.asciicircum; - case "`": - return font.grave; - case "{": - return font.braceleft; - case "|": - return font.bar; - case "}": - return font.braceright; - case "~": - return font.asciitilde; - default: - return font[chr] - } - } catch(e) { - Processing.debug(e) - } - }; - Drawing2D.prototype.text$line = function(str, x, y, z, align) { - var textWidth = 0, - xOffset = 0; - if (!curTextFont.glyph) { - if (str && "fillText" in curContext) { - if (isFillDirty) { - curContext.fillStyle = p.color.toString(currentFillColor); - isFillDirty = false - } - if (align === 39 || align === 3) { - textWidth = curTextFont.measureTextWidth(str); - if (align === 39) xOffset = -textWidth; - else xOffset = -textWidth / 2 - } - curContext.fillText(str, x + xOffset, y) - } - } else { - var font = p.glyphTable[curFontName]; - saveContext(); - curContext.translate(x, y + curTextSize); - if (align === 39 || align === 3) { - textWidth = font.width(str); - if (align === 39) xOffset = -textWidth; - else xOffset = -textWidth / 2 - } - var upem = font.units_per_em, - newScale = 1 / upem * curTextSize; - curContext.scale(newScale, newScale); - for (var i = 0, len = str.length; i < len; i++) try { - p.glyphLook(font, str[i]).draw() - } catch(e) { - Processing.debug(e) - } - restoreContext() - } - }; - Drawing3D.prototype.text$line = function(str, x, y, z, align) { - if (textcanvas === undef) textcanvas = document.createElement("canvas"); - var oldContext = curContext; - curContext = textcanvas.getContext("2d"); - curContext.font = curTextFont.css; - var textWidth = curTextFont.measureTextWidth(str); - textcanvas.width = textWidth; - textcanvas.height = curTextSize; - curContext = textcanvas.getContext("2d"); - curContext.font = curTextFont.css; - curContext.textBaseline = "top"; - Drawing2D.prototype.text$line(str, 0, 0, 0, 37); - var aspect = textcanvas.width / textcanvas.height; - curContext = oldContext; - curContext.bindTexture(curContext.TEXTURE_2D, textTex); - curContext.texImage2D(curContext.TEXTURE_2D, 0, curContext.RGBA, curContext.RGBA, curContext.UNSIGNED_BYTE, textcanvas); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MAG_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_MIN_FILTER, curContext.LINEAR); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_T, curContext.CLAMP_TO_EDGE); - curContext.texParameteri(curContext.TEXTURE_2D, curContext.TEXTURE_WRAP_S, curContext.CLAMP_TO_EDGE); - var xOffset = 0; - if (align === 39) xOffset = -textWidth; - else if (align === 3) xOffset = -textWidth / 2; - var model = new PMatrix3D; - var scalefactor = curTextSize * 0.5; - model.translate(x + xOffset - scalefactor / 2, y - scalefactor, z); - model.scale(-aspect * scalefactor, -scalefactor, scalefactor); - model.translate(-1, -1, -1); - model.transpose(); - var view = new PMatrix3D; - view.scale(1, -1, 1); - view.apply(modelView.array()); - view.transpose(); - curContext.useProgram(programObject2D); - vertexAttribPointer("aVertex2d", programObject2D, "aVertex", 3, textBuffer); - vertexAttribPointer("aTextureCoord2d", programObject2D, "aTextureCoord", 2, textureBuffer); - uniformi("uSampler2d", programObject2D, "uSampler", [0]); - uniformi("uIsDrawingText2d", programObject2D, "uIsDrawingText", true); - uniformMatrix("uModel2d", programObject2D, "uModel", false, model.array()); - uniformMatrix("uView2d", programObject2D, "uView", false, view.array()); - uniformf("uColor2d", programObject2D, "uColor", fillStyle); - curContext.bindBuffer(curContext.ELEMENT_ARRAY_BUFFER, indexBuffer); - curContext.drawElements(curContext.TRIANGLES, 6, curContext.UNSIGNED_SHORT, 0) - }; - - function text$4(str, x, y, z) { - var lines, linesCount; - if (str.indexOf("\n") < 0) { - lines = [str]; - linesCount = 1 - } else { - lines = str.split(/\r?\n/g); - linesCount = lines.length - } - var yOffset = 0; - if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescent; - else if (verticalTextAlignment === 3) yOffset = curTextAscent / 2 - (linesCount - 1) * curTextLeading / 2; - else if (verticalTextAlignment === 102) yOffset = -(curTextDescent + (linesCount - 1) * curTextLeading); - for (var i = 0; i < linesCount; ++i) { - var line = lines[i]; - drawing.text$line(line, x, y + yOffset, z, horizontalTextAlignment); - yOffset += curTextLeading - } - } - function text$6(str, x, y, width, height, z) { - if (str.length === 0 || width === 0 || height === 0) return; - if (curTextSize > height) return; - var spaceMark = -1; - var start = 0; - var lineWidth = 0; - var drawCommands = []; - for (var charPos = 0, len = str.length; charPos < len; charPos++) { - var currentChar = str[charPos]; - var spaceChar = currentChar === " "; - var letterWidth = curTextFont.measureTextWidth(currentChar); - if (currentChar !== "\n" && lineWidth + letterWidth <= width) { - if (spaceChar) spaceMark = charPos; - lineWidth += letterWidth - } else { - if (spaceMark + 1 === start) if (charPos > 0) spaceMark = charPos; - else return; - if (currentChar === "\n") { - drawCommands.push({ - text: str.substring(start, charPos), - width: lineWidth - }); - start = charPos + 1 - } else { - drawCommands.push({ - text: str.substring(start, spaceMark + 1), - width: lineWidth - }); - start = spaceMark + 1 - } - lineWidth = 0; - charPos = start - 1 - } - } - if (start < len) drawCommands.push({ - text: str.substring(start), - width: lineWidth - }); - var xOffset = 1, - yOffset = curTextAscent; - if (horizontalTextAlignment === 3) xOffset = width / 2; - else if (horizontalTextAlignment === 39) xOffset = width; - var linesCount = drawCommands.length, - visibleLines = Math.min(linesCount, Math.floor(height / curTextLeading)); - if (verticalTextAlignment === 101) yOffset = curTextAscent + curTextDescent; - else if (verticalTextAlignment === 3) yOffset = height / 2 - curTextLeading * (visibleLines / 2 - 1); - else if (verticalTextAlignment === 102) yOffset = curTextDescent + curTextLeading; - var command, drawCommand, leading; - for (command = 0; command < linesCount; command++) { - leading = command * curTextLeading; - if (yOffset + leading > height - curTextDescent) break; - drawCommand = drawCommands[command]; - drawing.text$line(drawCommand.text, x + xOffset, y + yOffset + leading, z, horizontalTextAlignment) - } - } - p.text = function() { - if (textMode === 5) return; - if (arguments.length === 3) text$4(toP5String(arguments[0]), arguments[1], arguments[2], 0); - else if (arguments.length === 4) text$4(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3]); - else if (arguments.length === 5) text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], 0); - else if (arguments.length === 6) text$6(toP5String(arguments[0]), arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]) - }; - p.textMode = function(mode) { - textMode = mode - }; - p.loadGlyphs = function(url) { - var x, y, cx, cy, nx, ny, d, a, lastCom, lenC, horiz_adv_x, getXY = "[0-9\\-]+", - path; - var regex = function(needle, hay) { - var i = 0, - results = [], - latest, regexp = new RegExp(needle, "g"); - latest = results[i] = regexp.exec(hay); - while (latest) { - i++; - latest = results[i] = regexp.exec(hay) - } - return results - }; - var buildPath = function(d) { - var c = regex("[A-Za-z][0-9\\- ]+|Z", d); - var beforePathDraw = function() { - saveContext(); - return drawing.$ensureContext() - }; - var afterPathDraw = function() { - executeContextFill(); - executeContextStroke(); - restoreContext() - }; - path = "return {draw:function(){var curContext=beforePathDraw();curContext.beginPath();"; - x = 0; - y = 0; - cx = 0; - cy = 0; - nx = 0; - ny = 0; - d = 0; - a = 0; - lastCom = ""; - lenC = c.length - 1; - for (var j = 0; j < lenC; j++) { - var com = c[j][0], - xy = regex(getXY, com); - switch (com[0]) { - case "M": - x = parseFloat(xy[0][0]); - y = parseFloat(xy[1][0]); - path += "curContext.moveTo(" + x + "," + -y + ");"; - break; - case "L": - x = parseFloat(xy[0][0]); - y = parseFloat(xy[1][0]); - path += "curContext.lineTo(" + x + "," + -y + ");"; - break; - case "H": - x = parseFloat(xy[0][0]); - path += "curContext.lineTo(" + x + "," + -y + ");"; - break; - case "V": - y = parseFloat(xy[0][0]); - path += "curContext.lineTo(" + x + "," + -y + ");"; - break; - case "T": - nx = parseFloat(xy[0][0]); - ny = parseFloat(xy[1][0]); - if (lastCom === "Q" || lastCom === "T") { - d = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(cy - y, 2)); - a = Math.PI + Math.atan2(cx - x, cy - y); - cx = x + Math.sin(a) * d; - cy = y + Math.cos(a) * d - } else { - cx = x; - cy = y - } - path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");"; - x = nx; - y = ny; - break; - case "Q": - cx = parseFloat(xy[0][0]); - cy = parseFloat(xy[1][0]); - nx = parseFloat(xy[2][0]); - ny = parseFloat(xy[3][0]); - path += "curContext.quadraticCurveTo(" + cx + "," + -cy + "," + nx + "," + -ny + ");"; - x = nx; - y = ny; - break; - case "Z": - path += "curContext.closePath();"; - break - } - lastCom = com[0] - } - path += "afterPathDraw();"; - path += "curContext.translate(" + horiz_adv_x + ",0);"; - path += "}}"; - return (new Function("beforePathDraw", "afterPathDraw", path))(beforePathDraw, afterPathDraw) - }; - var parseSVGFont = function(svg) { - var font = svg.getElementsByTagName("font"); - p.glyphTable[url].horiz_adv_x = font[0].getAttribute("horiz-adv-x"); - var font_face = svg.getElementsByTagName("font-face")[0]; - p.glyphTable[url].units_per_em = parseFloat(font_face.getAttribute("units-per-em")); - p.glyphTable[url].ascent = parseFloat(font_face.getAttribute("ascent")); - p.glyphTable[url].descent = parseFloat(font_face.getAttribute("descent")); - var glyph = svg.getElementsByTagName("glyph"), - len = glyph.length; - for (var i = 0; i < len; i++) { - var unicode = glyph[i].getAttribute("unicode"); - var name = glyph[i].getAttribute("glyph-name"); - horiz_adv_x = glyph[i].getAttribute("horiz-adv-x"); - if (horiz_adv_x === null) horiz_adv_x = p.glyphTable[url].horiz_adv_x; - d = glyph[i].getAttribute("d"); - if (d !== undef) { - path = buildPath(d); - p.glyphTable[url][name] = { - name: name, - unicode: unicode, - horiz_adv_x: horiz_adv_x, - draw: path.draw - } - } - } - }; - var loadXML = function() { - var xmlDoc; - try { - xmlDoc = document.implementation.createDocument("", "", null) - } catch(e_fx_op) { - Processing.debug(e_fx_op.message); - return - } - try { - xmlDoc.async = false; - xmlDoc.load(url); - parseSVGFont(xmlDoc.getElementsByTagName("svg")[0]) - } catch(e_sf_ch) { - Processing.debug(e_sf_ch); - try { - var xmlhttp = new window.XMLHttpRequest; - xmlhttp.open("GET", url, false); - xmlhttp.send(null); - parseSVGFont(xmlhttp.responseXML.documentElement) - } catch(e) { - Processing.debug(e_sf_ch) - } - } - }; - p.glyphTable[url] = {}; - loadXML(url); - return p.glyphTable[url] - }; - p.param = function(name) { - var attributeName = "data-processing-" + name; - if (curElement.hasAttribute(attributeName)) return curElement.getAttribute(attributeName); - for (var i = 0, len = curElement.childNodes.length; i < len; ++i) { - var item = curElement.childNodes.item(i); - if (item.nodeType !== 1 || item.tagName.toLowerCase() !== "param") continue; - if (item.getAttribute("name") === name) return item.getAttribute("value") - } - if (curSketch.params.hasOwnProperty(name)) return curSketch.params[name]; - return null - }; - - function wireDimensionalFunctions(mode) { - if (mode === "3D") drawing = new Drawing3D; - else if (mode === "2D") drawing = new Drawing2D; - else drawing = new DrawingPre; - for (var i in DrawingPre.prototype) if (DrawingPre.prototype.hasOwnProperty(i) && i.indexOf("$") < 0) p[i] = drawing[i]; - drawing.$init() - } - function createDrawingPreFunction(name) { - return function() { - wireDimensionalFunctions("2D"); - return drawing[name].apply(this, arguments) - } - } - DrawingPre.prototype.translate = createDrawingPreFunction("translate"); - DrawingPre.prototype.transform = createDrawingPreFunction("transform"); - DrawingPre.prototype.scale = createDrawingPreFunction("scale"); - DrawingPre.prototype.pushMatrix = createDrawingPreFunction("pushMatrix"); - DrawingPre.prototype.popMatrix = createDrawingPreFunction("popMatrix"); - DrawingPre.prototype.resetMatrix = createDrawingPreFunction("resetMatrix"); - DrawingPre.prototype.applyMatrix = createDrawingPreFunction("applyMatrix"); - DrawingPre.prototype.rotate = createDrawingPreFunction("rotate"); - DrawingPre.prototype.rotateZ = createDrawingPreFunction("rotateZ"); - DrawingPre.prototype.shearX = createDrawingPreFunction("shearX"); - DrawingPre.prototype.shearY = createDrawingPreFunction("shearY"); - DrawingPre.prototype.redraw = createDrawingPreFunction("redraw"); - DrawingPre.prototype.toImageData = createDrawingPreFunction("toImageData"); - DrawingPre.prototype.ambientLight = createDrawingPreFunction("ambientLight"); - DrawingPre.prototype.directionalLight = createDrawingPreFunction("directionalLight"); - DrawingPre.prototype.lightFalloff = createDrawingPreFunction("lightFalloff"); - DrawingPre.prototype.lightSpecular = createDrawingPreFunction("lightSpecular"); - DrawingPre.prototype.pointLight = createDrawingPreFunction("pointLight"); - DrawingPre.prototype.noLights = createDrawingPreFunction("noLights"); - DrawingPre.prototype.spotLight = createDrawingPreFunction("spotLight"); - DrawingPre.prototype.beginCamera = createDrawingPreFunction("beginCamera"); - DrawingPre.prototype.endCamera = createDrawingPreFunction("endCamera"); - DrawingPre.prototype.frustum = createDrawingPreFunction("frustum"); - DrawingPre.prototype.box = createDrawingPreFunction("box"); - DrawingPre.prototype.sphere = createDrawingPreFunction("sphere"); - DrawingPre.prototype.ambient = createDrawingPreFunction("ambient"); - DrawingPre.prototype.emissive = createDrawingPreFunction("emissive"); - DrawingPre.prototype.shininess = createDrawingPreFunction("shininess"); - DrawingPre.prototype.specular = createDrawingPreFunction("specular"); - DrawingPre.prototype.fill = createDrawingPreFunction("fill"); - DrawingPre.prototype.stroke = createDrawingPreFunction("stroke"); - DrawingPre.prototype.strokeWeight = createDrawingPreFunction("strokeWeight"); - DrawingPre.prototype.smooth = createDrawingPreFunction("smooth"); - DrawingPre.prototype.noSmooth = createDrawingPreFunction("noSmooth"); - DrawingPre.prototype.point = createDrawingPreFunction("point"); - DrawingPre.prototype.vertex = createDrawingPreFunction("vertex"); - DrawingPre.prototype.endShape = createDrawingPreFunction("endShape"); - DrawingPre.prototype.bezierVertex = createDrawingPreFunction("bezierVertex"); - DrawingPre.prototype.curveVertex = createDrawingPreFunction("curveVertex"); - DrawingPre.prototype.curve = createDrawingPreFunction("curve"); - DrawingPre.prototype.line = createDrawingPreFunction("line"); - DrawingPre.prototype.bezier = createDrawingPreFunction("bezier"); - DrawingPre.prototype.rect = createDrawingPreFunction("rect"); - DrawingPre.prototype.ellipse = createDrawingPreFunction("ellipse"); - DrawingPre.prototype.background = createDrawingPreFunction("background"); - DrawingPre.prototype.image = createDrawingPreFunction("image"); - DrawingPre.prototype.textWidth = createDrawingPreFunction("textWidth"); - DrawingPre.prototype.text$line = createDrawingPreFunction("text$line"); - DrawingPre.prototype.$ensureContext = createDrawingPreFunction("$ensureContext"); - DrawingPre.prototype.$newPMatrix = createDrawingPreFunction("$newPMatrix"); - DrawingPre.prototype.size = function(aWidth, aHeight, aMode) { - wireDimensionalFunctions(aMode === 2 ? "3D" : "2D"); - p.size(aWidth, aHeight, aMode) - }; - DrawingPre.prototype.$init = nop; - Drawing2D.prototype.$init = function() { - p.size(p.width, p.height); - curContext.lineCap = "round"; - p.noSmooth(); - p.disableContextMenu() - }; - Drawing3D.prototype.$init = function() { - p.use3DContext = true; - p.disableContextMenu() - }; - DrawingShared.prototype.$ensureContext = function() { - return curContext - }; - - function calculateOffset(curElement, event) { - var element = curElement, - offsetX = 0, - offsetY = 0; - p.pmouseX = p.mouseX; - p.pmouseY = p.mouseY; - if (element.offsetParent) { - do { - offsetX += element.offsetLeft; - offsetY += element.offsetTop - } while ( !! (element = element.offsetParent)) - } - element = curElement; - do { - offsetX -= element.scrollLeft || 0; - offsetY -= element.scrollTop || 0 - } while ( !! (element = element.parentNode)); - offsetX += stylePaddingLeft; - offsetY += stylePaddingTop; - offsetX += styleBorderLeft; - offsetY += styleBorderTop; - offsetX += window.pageXOffset; - offsetY += window.pageYOffset; - return { - "X": offsetX, - "Y": offsetY - } - } - function updateMousePosition(curElement, event) { - var offset = calculateOffset(curElement, event); - p.mouseX = event.pageX - offset.X; - p.mouseY = event.pageY - offset.Y - } - function addTouchEventOffset(t) { - var offset = calculateOffset(t.changedTouches[0].target, t.changedTouches[0]), - i; - for (i = 0; i < t.touches.length; i++) { - var touch = t.touches[i]; - touch.offsetX = touch.pageX - offset.X; - touch.offsetY = touch.pageY - offset.Y - } - for (i = 0; i < t.targetTouches.length; i++) { - var targetTouch = t.targetTouches[i]; - targetTouch.offsetX = targetTouch.pageX - offset.X; - targetTouch.offsetY = targetTouch.pageY - offset.Y - } - for (i = 0; i < t.changedTouches.length; i++) { - var changedTouch = t.changedTouches[i]; - changedTouch.offsetX = changedTouch.pageX - offset.X; - changedTouch.offsetY = changedTouch.pageY - offset.Y - } - return t - } - attachEventHandler(curElement, "touchstart", function(t) { - curElement.setAttribute("style", "-webkit-user-select: none"); - curElement.setAttribute("onclick", "void(0)"); - curElement.setAttribute("style", "-webkit-tap-highlight-color:rgba(0,0,0,0)"); - for (var i = 0, ehl = eventHandlers.length; i < ehl; i++) { - var type = eventHandlers[i].type; - if (type === "mouseout" || type === "mousemove" || type === "mousedown" || type === "mouseup" || type === "DOMMouseScroll" || type === "mousewheel" || type === "touchstart") detachEventHandler(eventHandlers[i]) - } - if (p.touchStart !== undef || p.touchMove !== undef || p.touchEnd !== undef || p.touchCancel !== undef) { - attachEventHandler(curElement, "touchstart", function(t) { - if (p.touchStart !== undef) { - t = addTouchEventOffset(t); - p.touchStart(t) - } - }); - attachEventHandler(curElement, "touchmove", function(t) { - if (p.touchMove !== undef) { - t.preventDefault(); - t = addTouchEventOffset(t); - p.touchMove(t) - } - }); - attachEventHandler(curElement, "touchend", function(t) { - if (p.touchEnd !== undef) { - t = addTouchEventOffset(t); - p.touchEnd(t) - } - }); - attachEventHandler(curElement, "touchcancel", function(t) { - if (p.touchCancel !== undef) { - t = addTouchEventOffset(t); - p.touchCancel(t) - } - }) - } else { - attachEventHandler(curElement, "touchstart", function(e) { - updateMousePosition(curElement, e.touches[0]); - p.__mousePressed = true; - p.mouseDragging = false; - p.mouseButton = 37; - if (typeof p.mousePressed === "function") p.mousePressed() - }); - attachEventHandler(curElement, "touchmove", function(e) { - e.preventDefault(); - updateMousePosition(curElement, e.touches[0]); - if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMoved(); - if (typeof p.mouseDragged === "function" && p.__mousePressed) { - p.mouseDragged(); - p.mouseDragging = true - } - }); - attachEventHandler(curElement, "touchend", function(e) { - p.__mousePressed = false; - if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseClicked(); - if (typeof p.mouseReleased === "function") p.mouseReleased() - }) - } - curElement.dispatchEvent(t) - }); - (function() { - var enabled = true, - contextMenu = function(e) { - e.preventDefault(); - e.stopPropagation() - }; - p.disableContextMenu = function() { - if (!enabled) return; - attachEventHandler(curElement, "contextmenu", contextMenu); - enabled = false - }; - p.enableContextMenu = function() { - if (enabled) return; - detachEventHandler({ - elem: curElement, - type: "contextmenu", - fn: contextMenu - }); - enabled = true - } - })(); - attachEventHandler(curElement, "mousemove", function(e) { - updateMousePosition(curElement, e); - if (typeof p.mouseMoved === "function" && !p.__mousePressed) p.mouseMoved(); - if (typeof p.mouseDragged === "function" && p.__mousePressed) { - p.mouseDragged(); - p.mouseDragging = true - } - }); - attachEventHandler(curElement, "mouseout", function(e) { - if (typeof p.mouseOut === "function") p.mouseOut() - }); - attachEventHandler(curElement, "mouseover", function(e) { - updateMousePosition(curElement, e); - if (typeof p.mouseOver === "function") p.mouseOver() - }); - curElement.onmousedown = function() { - curElement.focus(); - return false - }; - attachEventHandler(curElement, "mousedown", function(e) { - p.__mousePressed = true; - p.mouseDragging = false; - switch (e.which) { - case 1: - p.mouseButton = 37; - break; - case 2: - p.mouseButton = 3; - break; - case 3: - p.mouseButton = 39; - break - } - if (typeof p.mousePressed === "function") p.mousePressed() - }); - attachEventHandler(curElement, "mouseup", function(e) { - p.__mousePressed = false; - if (typeof p.mouseClicked === "function" && !p.mouseDragging) p.mouseClicked(); - if (typeof p.mouseReleased === "function") p.mouseReleased() - }); - var mouseWheelHandler = function(e) { - var delta = 0; - if (e.wheelDelta) { - delta = e.wheelDelta / 120; - if (window.opera) delta = -delta - } else if (e.detail) delta = -e.detail / 3; - p.mouseScroll = delta; - if (delta && typeof p.mouseScrolled === "function") p.mouseScrolled() - }; - attachEventHandler(document, "DOMMouseScroll", mouseWheelHandler); - attachEventHandler(document, "mousewheel", mouseWheelHandler); - if (!curElement.getAttribute("tabindex")) curElement.setAttribute("tabindex", 0); - - function getKeyCode(e) { - var code = e.which || e.keyCode; - switch (code) { - case 13: - return 10; - case 91: - case 93: - case 224: - return 157; - case 57392: - return 17; - case 46: - return 127; - case 45: - return 155 - } - return code - } - function getKeyChar(e) { - var c = e.which || e.keyCode; - var anyShiftPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey; - switch (c) { - case 13: - c = anyShiftPressed ? 13 : 10; - break; - case 8: - c = anyShiftPressed ? 127 : 8; - break - } - return new Char(c) - } - function suppressKeyEvent(e) { - if (typeof e.preventDefault === "function") e.preventDefault(); - else if (typeof e.stopPropagation === "function") e.stopPropagation(); - return false - } - function updateKeyPressed() { - var ch; - for (ch in pressedKeysMap) if (pressedKeysMap.hasOwnProperty(ch)) { - p.__keyPressed = true; - return - } - p.__keyPressed = false - } - function resetKeyPressed() { - p.__keyPressed = false; - pressedKeysMap = []; - lastPressedKeyCode = null - } - function simulateKeyTyped(code, c) { - pressedKeysMap[code] = c; - lastPressedKeyCode = null; - p.key = c; - p.keyCode = code; - p.keyPressed(); - p.keyCode = 0; - p.keyTyped(); - updateKeyPressed() - } - function handleKeydown(e) { - var code = getKeyCode(e); - if (code === 127) { - simulateKeyTyped(code, new Char(127)); - return - } - if (codedKeys.indexOf(code) < 0) { - lastPressedKeyCode = code; - return - } - var c = new Char(65535); - p.key = c; - p.keyCode = code; - pressedKeysMap[code] = c; - p.keyPressed(); - lastPressedKeyCode = null; - updateKeyPressed(); - return suppressKeyEvent(e) - } - function handleKeypress(e) { - if (lastPressedKeyCode === null) return; - var code = lastPressedKeyCode, - c = getKeyChar(e); - simulateKeyTyped(code, c); - return suppressKeyEvent(e) - } - function handleKeyup(e) { - var code = getKeyCode(e), - c = pressedKeysMap[code]; - if (c === undef) return; - p.key = c; - p.keyCode = code; - p.keyReleased(); - delete pressedKeysMap[code]; - updateKeyPressed() - } - if (!pgraphicsMode) { - if (aCode instanceof Processing.Sketch) curSketch = aCode; - else if (typeof aCode === "function") curSketch = new Processing.Sketch(aCode); - else if (!aCode) curSketch = new Processing.Sketch(function() {}); - else curSketch = Processing.compile(aCode); - p.externals.sketch = curSketch; - wireDimensionalFunctions(); - curElement.onfocus = function() { - p.focused = true - }; - curElement.onblur = function() { - p.focused = false; - if (!curSketch.options.globalKeyEvents) resetKeyPressed() - }; - if (curSketch.options.pauseOnBlur) { - attachEventHandler(window, "focus", function() { - if (doLoop) p.loop() - }); - attachEventHandler(window, "blur", function() { - if (doLoop && loopStarted) { - p.noLoop(); - doLoop = true - } - resetKeyPressed() - }) - } - var keyTrigger = curSketch.options.globalKeyEvents ? window : curElement; - attachEventHandler(keyTrigger, "keydown", handleKeydown); - attachEventHandler(keyTrigger, "keypress", handleKeypress); - attachEventHandler(keyTrigger, "keyup", handleKeyup); - for (var i in Processing.lib) if (Processing.lib.hasOwnProperty(i)) if (Processing.lib[i].hasOwnProperty("attach")) Processing.lib[i].attach(p); - else if (Processing.lib[i] instanceof Function) Processing.lib[i].call(this); - var retryInterval = 100; - var executeSketch = function(processing) { - if (! (curSketch.imageCache.pending || PFont.preloading.pending(retryInterval))) { - if (window.opera) { - var link, element, operaCache = curSketch.imageCache.operaCache; - for (link in operaCache) if (operaCache.hasOwnProperty(link)) { - element = operaCache[link]; - if (element !== null) document.body.removeChild(element); - delete operaCache[link] - } - } - curSketch.attach(processing, defaultScope); - curSketch.onLoad(processing); - if (processing.setup) { - processing.setup(); - processing.resetMatrix(); - curSketch.onSetup() - } - resetContext(); - if (processing.draw) if (!doLoop) processing.redraw(); - else processing.loop() - } else window.setTimeout(function() { - executeSketch(processing) - }, - retryInterval) - }; - addInstance(this); - executeSketch(p) - } else { - curSketch = new Processing.Sketch; - wireDimensionalFunctions(); - p.size = function(w, h, render) { - if (render && render === 2) wireDimensionalFunctions("3D"); - else wireDimensionalFunctions("2D"); - p.size(w, h, render) - } - } - }; - Processing.debug = debug; - Processing.prototype = defaultScope; - - function getGlobalMembers() { - var names = ["abs", "acos", "alpha", "ambient", "ambientLight", "append", - "applyMatrix", "arc", "arrayCopy", "asin", "atan", "atan2", "background", "beginCamera", "beginDraw", "beginShape", "bezier", "bezierDetail", "bezierPoint", "bezierTangent", "bezierVertex", "binary", "blend", "blendColor", "blit_resize", "blue", "box", "breakShape", "brightness", "camera", "ceil", "Character", "color", "colorMode", "concat", "constrain", "copy", "cos", "createFont", "createGraphics", "createImage", "cursor", "curve", "curveDetail", "curvePoint", "curveTangent", "curveTightness", "curveVertex", "day", "degrees", "directionalLight", - "disableContextMenu", "dist", "draw", "ellipse", "ellipseMode", "emissive", "enableContextMenu", "endCamera", "endDraw", "endShape", "exit", "exp", "expand", "externals", "fill", "filter", "floor", "focused", "frameCount", "frameRate", "frustum", "get", "glyphLook", "glyphTable", "green", "height", "hex", "hint", "hour", "hue", "image", "imageMode", "intersect", "join", "key", "keyCode", "keyPressed", "keyReleased", "keyTyped", "lerp", "lerpColor", "lightFalloff", "lights", "lightSpecular", "line", "link", "loadBytes", "loadFont", "loadGlyphs", - "loadImage", "loadPixels", "loadShape", "loadXML", "loadStrings", "log", "loop", "mag", "map", "match", "matchAll", "max", "millis", "min", "minute", "mix", "modelX", "modelY", "modelZ", "modes", "month", "mouseButton", "mouseClicked", "mouseDragged", "mouseMoved", "mouseOut", "mouseOver", "mousePressed", "mouseReleased", "mouseScroll", "mouseScrolled", "mouseX", "mouseY", "name", "nf", "nfc", "nfp", "nfs", "noCursor", "noFill", "noise", "noiseDetail", "noiseSeed", "noLights", "noLoop", "norm", "normal", "noSmooth", "noStroke", "noTint", "ortho", - "param", "parseBoolean", "parseByte", "parseChar", "parseFloat", "parseInt", "peg", "perspective", "PImage", "pixels", "PMatrix2D", "PMatrix3D", "PMatrixStack", "pmouseX", "pmouseY", "point", "pointLight", "popMatrix", "popStyle", "pow", "print", "printCamera", "println", "printMatrix", "printProjection", "PShape", "PShapeSVG", "pushMatrix", "pushStyle", "quad", "radians", "random", "Random", "randomSeed", "rect", "rectMode", "red", "redraw", "requestImage", "resetMatrix", "reverse", "rotate", "rotateX", "rotateY", "rotateZ", "round", "saturation", - "save", "saveFrame", "saveStrings", "scale", "screenX", "screenY", "screenZ", "second", "set", "setup", "shape", "shapeMode", "shared", "shearX", "shearY", "shininess", "shorten", "sin", "size", "smooth", "sort", "specular", "sphere", "sphereDetail", "splice", "split", "splitTokens", "spotLight", "sq", "sqrt", "status", "str", "stroke", "strokeCap", "strokeJoin", "strokeWeight", "subset", "tan", "text", "textAlign", "textAscent", "textDescent", "textFont", "textLeading", "textMode", "textSize", "texture", "textureMode", "textWidth", "tint", "toImageData", - "touchCancel", "touchEnd", "touchMove", "touchStart", "translate", "transform", "triangle", "trim", "unbinary", "unhex", "updatePixels", "use3DContext", "vertex", "width", "XMLElement", "XML", "year", "__contains", "__equals", "__equalsIgnoreCase", "__frameRate", "__hashCode", "__int_cast", "__instanceof", "__keyPressed", "__mousePressed", "__printStackTrace", "__replace", "__replaceAll", "__replaceFirst", "__toCharArray", "__split", "__codePointAt", "__startsWith", "__endsWith", "__matches"]; - var members = {}; - var i, l; - for (i = 0, l = names.length; i < l; ++i) members[names[i]] = null; - for (var lib in Processing.lib) if (Processing.lib.hasOwnProperty(lib)) if (Processing.lib[lib].exports) { - var exportedNames = Processing.lib[lib].exports; - for (i = 0, l = exportedNames.length; i < l; ++i) members[exportedNames[i]] = null - } - return members - } - function parseProcessing(code) { - var globalMembers = getGlobalMembers(); - - function splitToAtoms(code) { - var atoms = []; - var items = code.split(/([\{\[\(\)\]\}])/); - var result = items[0]; - var stack = []; - for (var i = 1; i < items.length; i += 2) { - var item = items[i]; - if (item === "[" || item === "{" || item === "(") { - stack.push(result); - result = item - } else if (item === "]" || item === "}" || item === ")") { - var kind = item === "}" ? "A" : item === ")" ? "B" : "C"; - var index = atoms.length; - atoms.push(result + item); - result = stack.pop() + '"' + kind + (index + 1) + '"' - } - result += items[i + 1] - } - atoms.unshift(result); - return atoms - } - function injectStrings(code, strings) { - return code.replace(/'(\d+)'/g, function(all, index) { - var val = strings[index]; - if (val.charAt(0) === "/") return val; - return /^'((?:[^'\\\n])|(?:\\.[0-9A-Fa-f]*))'$/.test(val) ? "(new $p.Character(" + val + "))" : val - }) - } - function trimSpaces(string) { - var m1 = /^\s*/.exec(string), - result; - if (m1[0].length === string.length) result = { - left: m1[0], - middle: "", - right: "" - }; - else { - var m2 = /\s*$/.exec(string); - result = { - left: m1[0], - middle: string.substring(m1[0].length, m2.index), - right: m2[0] - } - } - result.untrim = function(t) { - return this.left + t + this.right - }; - return result - } - function trim(string) { - return string.replace(/^\s+/, "").replace(/\s+$/, "") - } - function appendToLookupTable(table, array) { - for (var i = 0, l = array.length; i < l; ++i) table[array[i]] = null; - return table - } - function isLookupTableEmpty(table) { - for (var i in table) if (table.hasOwnProperty(i)) return false; - return true - } - function getAtomIndex(templ) { - return templ.substring(2, templ.length - 1) - } - var codeWoExtraCr = code.replace(/\r\n?|\n\r/g, "\n"); - var strings = []; - var codeWoStrings = codeWoExtraCr.replace(/("(?:[^"\\\n]|\\.)*")|('(?:[^'\\\n]|\\.)*')|(([\[\(=|&!\^:?]\s*)(\/(?![*\/])(?:[^\/\\\n]|\\.)*\/[gim]*)\b)|(\/\/[^\n]*\n)|(\/\*(?:(?!\*\/)(?:.|\n))*\*\/)/g, function(all, quoted, aposed, regexCtx, prefix, regex, singleComment, comment) { - var index; - if (quoted || aposed) { - index = strings.length; - strings.push(all); - return "'" + index + "'" - } - if (regexCtx) { - index = strings.length; - strings.push(regex); - return prefix + "'" + index + "'" - } - return comment !== "" ? " " : "\n" - }); - codeWoStrings = codeWoStrings.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { - return "__x005F_x" + hexCode - }); - codeWoStrings = codeWoStrings.replace(/\$/g, "__x0024"); - var genericsWereRemoved; - var codeWoGenerics = codeWoStrings; - var replaceFunc = function(all, before, types, after) { - if ( !! before || !!after) return all; - genericsWereRemoved = true; - return "" - }; - do { - genericsWereRemoved = false; - codeWoGenerics = codeWoGenerics.replace(/([<]?)<\s*((?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?(?:\s*,\s*(?:\?|[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\[\])*(?:\s+(?:extends|super)\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)?)*)\s*>([=]?)/g, replaceFunc) - } while (genericsWereRemoved); - var atoms = splitToAtoms(codeWoGenerics); - var replaceContext; - var declaredClasses = {}, - currentClassId, classIdSeed = 0; - - function addAtom(text, type) { - var lastIndex = atoms.length; - atoms.push(text); - return '"' + type + lastIndex + '"' - } - function generateClassId() { - return "class" + ++classIdSeed - } - function appendClass(class_, classId, scopeId) { - class_.classId = classId; - class_.scopeId = scopeId; - declaredClasses[classId] = class_ - } - var transformClassBody, transformInterfaceBody, transformStatementsBlock, transformStatements, transformMain, transformExpression; - var classesRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)(class|interface)\s+([A-Za-z_$][\w$]*\b)(\s+extends\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?(\s+implements\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\b)*)?\s*("A\d+")/g; - var methodsRegex = /\b((?:(?:public|private|final|protected|static|abstract|synchronized)\s+)*)((?!(?:else|new|return|throw|function|public|private|protected)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+"|;)/g; - var fieldTest = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:else|new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*([A-Za-z_$][\w$]*\b)\s*(?:"C\d+"\s*)*([=,]|$)/; - var cstrsRegex = /\b((?:(?:public|private|final|protected|static|abstract)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b)\s*("B\d+")(\s*throws\s+[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*,\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)*)?\s*("A\d+")/g; - var attrAndTypeRegex = /^((?:(?:public|private|final|protected|static)\s+)*)((?!(?:new|return|throw)\b)[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*(?:\s*"C\d+")*)\s*/; - var functionsRegex = /\bfunction(?:\s+([A-Za-z_$][\w$]*))?\s*("B\d+")\s*("A\d+")/g; - - function extractClassesAndMethods(code) { - var s = code; - s = s.replace(classesRegex, function(all) { - return addAtom(all, "E") - }); - s = s.replace(methodsRegex, function(all) { - return addAtom(all, "D") - }); - s = s.replace(functionsRegex, function(all) { - return addAtom(all, "H") - }); - return s - } - function extractConstructors(code, className) { - var result = code.replace(cstrsRegex, function(all, attr, name, params, throws_, body) { - if (name !== className) return all; - return addAtom(all, "G") - }); - return result - } - function AstParam(name) { - this.name = name - } - AstParam.prototype.toString = function() { - return this.name - }; - - function AstParams(params, methodArgsParam) { - this.params = params; - this.methodArgsParam = methodArgsParam - } - AstParams.prototype.getNames = function() { - var names = []; - for (var i = 0, l = this.params.length; i < l; ++i) names.push(this.params[i].name); - return names - }; - AstParams.prototype.prependMethodArgs = function(body) { - if (!this.methodArgsParam) return body; - return "{\nvar " + this.methodArgsParam.name + " = Array.prototype.slice.call(arguments, " + this.params.length + ");\n" + body.substring(1) - }; - AstParams.prototype.toString = function() { - if (this.params.length === 0) return "()"; - var result = "("; - for (var i = 0, l = this.params.length; i < l; ++i) result += this.params[i] + ", "; - return result.substring(0, result.length - 2) + ")" - }; - - function transformParams(params) { - var paramsWoPars = trim(params.substring(1, params.length - 1)); - var result = [], - methodArgsParam = null; - if (paramsWoPars !== "") { - var paramList = paramsWoPars.split(","); - for (var i = 0; i < paramList.length; ++i) { - var param = /\b([A-Za-z_$][\w$]*\b)(\s*"[ABC][\d]*")*\s*$/.exec(paramList[i]); - if (i === paramList.length - 1 && paramList[i].indexOf("...") >= 0) { - methodArgsParam = new AstParam(param[1]); - break - } - result.push(new AstParam(param[1])) - } - } - return new AstParams(result, methodArgsParam) - } - function preExpressionTransform(expr) { - var s = expr; - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"C\d+")+\s*("A\d+")/g, function(all, type, init) { - return init - }); - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)(?:\s*"B\d+")\s*("A\d+")/g, function(all, type, init) { - return addAtom(all, "F") - }); - s = s.replace(functionsRegex, function(all) { - return addAtom(all, "H") - }); - s = s.replace(/\bnew\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*("C\d+"(?:\s*"C\d+")*)/g, function(all, type, index) { - var args = index.replace(/"C(\d+)"/g, function(all, j) { - return atoms[j] - }).replace(/\[\s*\]/g, "[null]").replace(/\s*\]\s*\[\s*/g, ", "); - var arrayInitializer = "{" + args.substring(1, args.length - 1) + "}"; - var createArrayArgs = "('" + type + "', " + addAtom(arrayInitializer, "A") + ")"; - return "$p.createJavaArray" + addAtom(createArrayArgs, "B") - }); - s = s.replace(/(\.\s*length)\s*"B\d+"/g, "$1"); - s = s.replace(/#([0-9A-Fa-f]{6})\b/g, function(all, digits) { - return "0xFF" + digits - }); - s = s.replace(/"B(\d+)"(\s*(?:[\w$']|"B))/g, function(all, index, next) { - var atom = atoms[index]; - if (!/^\(\s*[A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*\s*(?:"C\d+"\s*)*\)$/.test(atom)) return all; - if (/^\(\s*int\s*\)$/.test(atom)) return "(int)" + next; - var indexParts = atom.split(/"C(\d+)"/g); - if (indexParts.length > 1) if (!/^\[\s*\]$/.test(atoms[indexParts[1]])) return all; - return "" + next - }); - s = s.replace(/\(int\)([^,\]\)\}\?\:\*\+\-\/\^\|\%\&\~<\>\=]+)/g, function(all, arg) { - var trimmed = trimSpaces(arg); - return trimmed.untrim("__int_cast(" + trimmed.middle + ")") - }); - s = s.replace(/\bsuper(\s*"B\d+")/g, "$$superCstr$1").replace(/\bsuper(\s*\.)/g, "$$super$1"); - s = s.replace(/\b0+((\d*)(?:\.[\d*])?(?:[eE][\-\+]?\d+)?[fF]?)\b/, function(all, numberWo0, intPart) { - if (numberWo0 === intPart) return all; - return intPart === "" ? "0" + numberWo0 : numberWo0 - }); - s = s.replace(/\b(\.?\d+\.?)[fF]\b/g, "$1"); - s = s.replace(/([^\s])%([^=\s])/g, "$1 % $2"); - s = s.replace(/\b(frameRate|keyPressed|mousePressed)\b(?!\s*"B)/g, "__$1"); - s = s.replace(/\b(boolean|byte|char|float|int)\s*"B/g, function(all, name) { - return "parse" + name.substring(0, 1).toUpperCase() + name.substring(1) + '"B' - }); - s = s.replace(/\bpixels\b\s*(("C(\d+)")|\.length)?(\s*=(?!=)([^,\]\)\}]+))?/g, function(all, indexOrLength, index, atomIndex, equalsPart, rightSide) { - if (index) { - var atom = atoms[atomIndex]; - if (equalsPart) return "pixels.setPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + "," + rightSide + ")", "B"); - return "pixels.getPixel" + addAtom("(" + atom.substring(1, atom.length - 1) + ")", "B") - } - if (indexOrLength) return "pixels.getLength" + addAtom("()", "B"); - if (equalsPart) return "pixels.set" + addAtom("(" + rightSide + ")", "B"); - return "pixels.toArray" + addAtom("()", "B") - }); - var repeatJavaReplacement; - - function replacePrototypeMethods(all, subject, method, atomIndex) { - var atom = atoms[atomIndex]; - repeatJavaReplacement = true; - var trimmed = trimSpaces(atom.substring(1, atom.length - 1)); - return "__" + method + (trimmed.middle === "" ? addAtom("(" + subject.replace(/\.\s*$/, "") + ")", "B") : addAtom("(" + subject.replace(/\.\s*$/, "") + "," + trimmed.middle + ")", "B")) - } - do { - repeatJavaReplacement = false; - s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*\.\s*(?:[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*\.\s*)*)(replace|replaceAll|replaceFirst|contains|equals|equalsIgnoreCase|hashCode|toCharArray|printStackTrace|split|startsWith|endsWith|codePointAt|matches)\s*"B(\d+)"/g, replacePrototypeMethods) - } while (repeatJavaReplacement); - - function replaceInstanceof(all, subject, type) { - repeatJavaReplacement = true; - return "__instanceof" + addAtom("(" + subject + ", " + type + ")", "B") - } - do { - repeatJavaReplacement = false; - s = s.replace(/((?:'\d+'|\b[A-Za-z_$][\w$]*\s*(?:"[BC]\d+")*)\s*(?:\.\s*[A-Za-z_$][\w$]*\s*(?:"[BC]\d+"\s*)*)*)instanceof\s+([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)/g, replaceInstanceof) - } while (repeatJavaReplacement); - s = s.replace(/\bthis(\s*"B\d+")/g, "$$constr$1"); - return s - } - function AstInlineClass(baseInterfaceName, body) { - this.baseInterfaceName = baseInterfaceName; - this.body = body; - body.owner = this - } - AstInlineClass.prototype.toString = function() { - return "new (" + this.body + ")" - }; - - function transformInlineClass(class_) { - var m = (new RegExp(/\bnew\s*([A-Za-z_$][\w$]*\s*(?:\.\s*[A-Za-z_$][\w$]*)*)\s*"B\d+"\s*"A(\d+)"/)).exec(class_); - var oldClassId = currentClassId, - newClassId = generateClassId(); - currentClassId = newClassId; - var uniqueClassName = m[1] + "$" + newClassId; - var inlineClass = new AstInlineClass(uniqueClassName, transformClassBody(atoms[m[2]], uniqueClassName, "", "implements " + m[1])); - appendClass(inlineClass, newClassId, oldClassId); - currentClassId = oldClassId; - return inlineClass - } - - function AstFunction(name, params, body) { - this.name = name; - this.params = params; - this.body = body - } - AstFunction.prototype.toString = function() { - var oldContext = replaceContext; - var names = appendToLookupTable({ - "this": null - }, - this.params.getNames()); - replaceContext = function(subject) { - return names.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) - }; - var result = "function"; - if (this.name) result += " " + this.name; - var body = this.params.prependMethodArgs(this.body.toString()); - result += this.params + " " + body; - replaceContext = oldContext; - return result - }; - - function transformFunction(class_) { - var m = (new RegExp(/\b([A-Za-z_$][\w$]*)\s*"B(\d+)"\s*"A(\d+)"/)).exec(class_); - return new AstFunction(m[1] !== "function" ? m[1] : null, transformParams(atoms[m[2]]), transformStatementsBlock(atoms[m[3]])) - } - function AstInlineObject(members) { - this.members = members - } - AstInlineObject.prototype.toString = function() { - var oldContext = replaceContext; - replaceContext = function(subject) { - return subject.name === "this" ? "this" : oldContext(subject) - }; - var result = ""; - for (var i = 0, l = this.members.length; i < l; ++i) { - if (this.members[i].label) result += this.members[i].label + ": "; - result += this.members[i].value.toString() + ", " - } - replaceContext = oldContext; - return result.substring(0, result.length - 2) - }; - - function transformInlineObject(obj) { - var members = obj.split(","); - for (var i = 0; i < members.length; ++i) { - var label = members[i].indexOf(":"); - if (label < 0) members[i] = { - value: transformExpression(members[i]) - }; - else members[i] = { - label: trim(members[i].substring(0, label)), - value: transformExpression(trim(members[i].substring(label + 1))) - } - } - return new AstInlineObject(members) - } - - function expandExpression(expr) { - if (expr.charAt(0) === "(" || expr.charAt(0) === "[") return expr.charAt(0) + expandExpression(expr.substring(1, expr.length - 1)) + expr.charAt(expr.length - 1); - if (expr.charAt(0) === "{") { - if (/^\{\s*(?:[A-Za-z_$][\w$]*|'\d+')\s*:/.test(expr)) return "{" + addAtom(expr.substring(1, expr.length - 1), "I") + "}"; - return "[" + expandExpression(expr.substring(1, expr.length - 1)) + "]" - } - var trimmed = trimSpaces(expr); - var result = preExpressionTransform(trimmed.middle); - result = result.replace(/"[ABC](\d+)"/g, function(all, index) { - return expandExpression(atoms[index]) - }); - return trimmed.untrim(result) - } - function replaceContextInVars(expr) { - return expr.replace(/(\.\s*)?((?:\b[A-Za-z_]|\$)[\w$]*)(\s*\.\s*([A-Za-z_$][\w$]*)(\s*\()?)?/g, function(all, memberAccessSign, identifier, suffix, subMember, callSign) { - if (memberAccessSign) return all; - var subject = { - name: identifier, - member: subMember, - callSign: !!callSign - }; - return replaceContext(subject) + (suffix === undef ? "" : suffix) - }) - } - function AstExpression(expr, transforms) { - this.expr = expr; - this.transforms = transforms - } - AstExpression.prototype.toString = function() { - var transforms = this.transforms; - var expr = replaceContextInVars(this.expr); - return expr.replace(/"!(\d+)"/g, function(all, index) { - return transforms[index].toString() - }) - }; - transformExpression = function(expr) { - var transforms = []; - var s = expandExpression(expr); - s = s.replace(/"H(\d+)"/g, function(all, index) { - transforms.push(transformFunction(atoms[index])); - return '"!' + (transforms.length - 1) + '"' - }); - s = s.replace(/"F(\d+)"/g, function(all, index) { - transforms.push(transformInlineClass(atoms[index])); - return '"!' + (transforms.length - 1) + '"' - }); - s = s.replace(/"I(\d+)"/g, function(all, index) { - transforms.push(transformInlineObject(atoms[index])); - return '"!' + (transforms.length - 1) + '"' - }); - return new AstExpression(s, transforms) - }; - - function AstVarDefinition(name, value, isDefault) { - this.name = name; - this.value = value; - this.isDefault = isDefault - } - AstVarDefinition.prototype.toString = function() { - return this.name + " = " + this.value - }; - - function transformVarDefinition(def, defaultTypeValue) { - var eqIndex = def.indexOf("="); - var name, value, isDefault; - if (eqIndex < 0) { - name = def; - value = defaultTypeValue; - isDefault = true - } else { - name = def.substring(0, eqIndex); - value = transformExpression(def.substring(eqIndex + 1)); - isDefault = false - } - return new AstVarDefinition(trim(name.replace(/(\s*"C\d+")+/g, "")), value, isDefault) - } - function getDefaultValueForType(type) { - if (type === "int" || type === "float") return "0"; - if (type === "boolean") return "false"; - if (type === "color") return "0x00000000"; - return "null" - } - function AstVar(definitions, varType) { - this.definitions = definitions; - this.varType = varType - } - AstVar.prototype.getNames = function() { - var names = []; - for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.definitions[i].name); - return names - }; - AstVar.prototype.toString = function() { - return "var " + this.definitions.join(",") - }; - - function AstStatement(expression) { - this.expression = expression - } - AstStatement.prototype.toString = function() { - return this.expression.toString() - }; - - function transformStatement(statement) { - if (fieldTest.test(statement)) { - var attrAndType = attrAndTypeRegex.exec(statement); - var definitions = statement.substring(attrAndType[0].length).split(","); - var defaultTypeValue = getDefaultValueForType(attrAndType[2]); - for (var i = 0; i < definitions.length; ++i) definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); - return new AstVar(definitions, attrAndType[2]) - } - return new AstStatement(transformExpression(statement)) - } - function AstForExpression(initStatement, condition, step) { - this.initStatement = initStatement; - this.condition = condition; - this.step = step - } - AstForExpression.prototype.toString = function() { - return "(" + this.initStatement + "; " + this.condition + "; " + this.step + ")" - }; - - function AstForInExpression(initStatement, container) { - this.initStatement = initStatement; - this.container = container - } - AstForInExpression.prototype.toString = function() { - var init = this.initStatement.toString(); - if (init.indexOf("=") >= 0) init = init.substring(0, init.indexOf("=")); - return "(" + init + " in " + this.container + ")" - }; - - function AstForEachExpression(initStatement, container) { - this.initStatement = initStatement; - this.container = container - } - AstForEachExpression.iteratorId = 0; - AstForEachExpression.prototype.toString = function() { - var init = this.initStatement.toString(); - var iterator = "$it" + AstForEachExpression.iteratorId++; - var variableName = init.replace(/^\s*var\s*/, "").split("=")[0]; - var initIteratorAndVariable = "var " + iterator + " = new $p.ObjectIterator(" + this.container + "), " + variableName + " = void(0)"; - var nextIterationCondition = iterator + ".hasNext() && ((" + variableName + " = " + iterator + ".next()) || true)"; - return "(" + initIteratorAndVariable + "; " + nextIterationCondition + ";)" - }; - - function transformForExpression(expr) { - var content; - if (/\bin\b/.test(expr)) { - content = expr.substring(1, expr.length - 1).split(/\bin\b/g); - return new AstForInExpression(transformStatement(trim(content[0])), transformExpression(content[1])) - } - if (expr.indexOf(":") >= 0 && expr.indexOf(";") < 0) { - content = expr.substring(1, expr.length - 1).split(":"); - return new AstForEachExpression(transformStatement(trim(content[0])), transformExpression(content[1])) - } - content = expr.substring(1, expr.length - 1).split(";"); - return new AstForExpression(transformStatement(trim(content[0])), transformExpression(content[1]), transformExpression(content[2])) - } - - function sortByWeight(array) { - array.sort(function(a, b) { - return b.weight - a.weight - }) - } - function AstInnerInterface(name, body, isStatic) { - this.name = name; - this.body = body; - this.isStatic = isStatic; - body.owner = this - } - AstInnerInterface.prototype.toString = function() { - return "" + this.body - }; - - function AstInnerClass(name, body, isStatic) { - this.name = name; - this.body = body; - this.isStatic = isStatic; - body.owner = this - } - AstInnerClass.prototype.toString = function() { - return "" + this.body - }; - - function transformInnerClass(class_) { - var m = classesRegex.exec(class_); - classesRegex.lastIndex = 0; - var isStatic = m[1].indexOf("static") >= 0; - var body = atoms[getAtomIndex(m[6])], - innerClass; - var oldClassId = currentClassId, - newClassId = generateClassId(); - currentClassId = newClassId; - if (m[2] === "interface") innerClass = new AstInnerInterface(m[3], transformInterfaceBody(body, m[3], m[4]), isStatic); - else innerClass = new AstInnerClass(m[3], transformClassBody(body, m[3], m[4], m[5]), isStatic); - appendClass(innerClass, newClassId, oldClassId); - currentClassId = oldClassId; - return innerClass - } - function AstClassMethod(name, params, body, isStatic) { - this.name = name; - this.params = params; - this.body = body; - this.isStatic = isStatic - } - AstClassMethod.prototype.toString = function() { - var paramNames = appendToLookupTable({}, - this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function(subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) - }; - var body = this.params.prependMethodArgs(this.body.toString()); - var result = "function " + this.methodId + this.params + " " + body + "\n"; - replaceContext = oldContext; - return result - }; - - function transformClassMethod(method) { - var m = methodsRegex.exec(method); - methodsRegex.lastIndex = 0; - var isStatic = m[1].indexOf("static") >= 0; - var body = m[6] !== ";" ? atoms[getAtomIndex(m[6])] : "{}"; - return new AstClassMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), transformStatementsBlock(body), isStatic) - } - function AstClassField(definitions, fieldType, isStatic) { - this.definitions = definitions; - this.fieldType = fieldType; - this.isStatic = isStatic - } - AstClassField.prototype.getNames = function() { - var names = []; - for (var i = 0, l = this.definitions.length; i < l; ++i) names.push(this.definitions[i].name); - return names - }; - AstClassField.prototype.toString = function() { - var thisPrefix = replaceContext({ - name: "[this]" - }); - if (this.isStatic) { - var className = this.owner.name; - var staticDeclarations = []; - for (var i = 0, l = this.definitions.length; i < l; ++i) { - var definition = this.definitions[i]; - var name = definition.name, - staticName = className + "." + name; - var declaration = "if(" + staticName + " === void(0)) {\n" + " " + staticName + " = " + definition.value + "; }\n" + "$p.defineProperty(" + thisPrefix + ", " + "'" + name + "', { get: function(){return " + staticName + ";}, " + "set: function(val){" + staticName + " = val;} });\n"; - staticDeclarations.push(declaration) - } - return staticDeclarations.join("") - } - return thisPrefix + "." + this.definitions.join("; " + thisPrefix + ".") - }; - - function transformClassField(statement) { - var attrAndType = attrAndTypeRegex.exec(statement); - var isStatic = attrAndType[1].indexOf("static") >= 0; - var definitions = statement.substring(attrAndType[0].length).split(/,\s*/g); - var defaultTypeValue = getDefaultValueForType(attrAndType[2]); - for (var i = 0; i < definitions.length; ++i) definitions[i] = transformVarDefinition(definitions[i], defaultTypeValue); - return new AstClassField(definitions, attrAndType[2], isStatic) - } - function AstConstructor(params, body) { - this.params = params; - this.body = body - } - AstConstructor.prototype.toString = function() { - var paramNames = appendToLookupTable({}, - this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function(subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) - }; - var prefix = "function $constr_" + this.params.params.length + this.params.toString(); - var body = this.params.prependMethodArgs(this.body.toString()); - if (!/\$(superCstr|constr)\b/.test(body)) body = "{\n$superCstr();\n" + body.substring(1); - replaceContext = oldContext; - return prefix + body + "\n" - }; - - function transformConstructor(cstr) { - var m = (new RegExp(/"B(\d+)"\s*"A(\d+)"/)).exec(cstr); - var params = transformParams(atoms[m[1]]); - return new AstConstructor(params, transformStatementsBlock(atoms[m[2]])) - } - function AstInterfaceBody(name, interfacesNames, methodsNames, fields, innerClasses, misc) { - var i, l; - this.name = name; - this.interfacesNames = interfacesNames; - this.methodsNames = methodsNames; - this.fields = fields; - this.innerClasses = innerClasses; - this.misc = misc; - for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this - } - AstInterfaceBody.prototype.getMembers = function(classFields, classMethods, classInners) { - if (this.owner.base) this.owner.base.body.getMembers(classFields, classMethods, classInners); - var i, j, l, m; - for (i = 0, l = this.fields.length; i < l; ++i) { - var fieldNames = this.fields[i].getNames(); - for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j]] = this.fields[i] - } - for (i = 0, l = this.methodsNames.length; i < l; ++i) { - var methodName = this.methodsNames[i]; - classMethods[methodName] = true - } - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - classInners[innerClass.name] = innerClass - } - }; - AstInterfaceBody.prototype.toString = function() { - function getScopeLevel(p) { - var i = 0; - while (p) { - ++i; - p = p.scope - } - return i - } - var scopeLevel = getScopeLevel(this.owner); - var className = this.name; - var staticDefinitions = ""; - var metadata = ""; - var thisClassFields = {}, - thisClassMethods = {}, - thisClassInners = {}; - this.getMembers(thisClassFields, thisClassMethods, thisClassInners); - var i, l, j, m; - if (this.owner.interfaces) { - var resolvedInterfaces = [], - resolvedInterface; - for (i = 0, l = this.interfacesNames.length; i < l; ++i) { - if (!this.owner.interfaces[i]) continue; - resolvedInterface = replaceContext({ - name: this.interfacesNames[i] - }); - resolvedInterfaces.push(resolvedInterface); - staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" - } - metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" - } - metadata += className + ".$isInterface = true;\n"; - metadata += className + ".$methods = ['" + this.methodsNames.join("', '") + "'];\n"; - sortByWeight(this.innerClasses); - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - if (innerClass.isStatic) staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n" - } - for (i = 0, l = this.fields.length; i < l; ++i) { - var field = this.fields[i]; - if (field.isStatic) staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n" - } - return "(function() {\n" + "function " + className + "() { throw 'Unable to create the interface'; }\n" + staticDefinitions + metadata + "return " + className + ";\n" + "})()" - }; - transformInterfaceBody = function(body, name, baseInterfaces) { - var declarations = body.substring(1, body.length - 1); - declarations = extractClassesAndMethods(declarations); - declarations = extractConstructors(declarations, name); - var methodsNames = [], - classes = []; - declarations = declarations.replace(/"([DE])(\d+)"/g, function(all, type, index) { - if (type === "D") methodsNames.push(index); - else if (type === "E") classes.push(index); - return "" - }); - var fields = declarations.split(/;(?:\s*;)*/g); - var baseInterfaceNames; - var i, l; - if (baseInterfaces !== undef) baseInterfaceNames = baseInterfaces.replace(/^\s*extends\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); - for (i = 0, l = methodsNames.length; i < l; ++i) { - var method = transformClassMethod(atoms[methodsNames[i]]); - methodsNames[i] = method.name - } - for (i = 0, l = fields.length - 1; i < l; ++i) { - var field = trimSpaces(fields[i]); - fields[i] = transformClassField(field.middle) - } - var tail = fields.pop(); - for (i = 0, l = classes.length; i < l; ++i) classes[i] = transformInnerClass(atoms[classes[i]]); - return new AstInterfaceBody(name, baseInterfaceNames, methodsNames, fields, classes, { - tail: tail - }) - }; - - function AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, innerClasses, misc) { - var i, l; - this.name = name; - this.baseClassName = baseClassName; - this.interfacesNames = interfacesNames; - this.functions = functions; - this.methods = methods; - this.fields = fields; - this.cstrs = cstrs; - this.innerClasses = innerClasses; - this.misc = misc; - for (i = 0, l = fields.length; i < l; ++i) fields[i].owner = this - } - AstClassBody.prototype.getMembers = function(classFields, classMethods, classInners) { - if (this.owner.base) this.owner.base.body.getMembers(classFields, classMethods, classInners); - var i, j, l, m; - for (i = 0, l = this.fields.length; i < l; ++i) { - var fieldNames = this.fields[i].getNames(); - for (j = 0, m = fieldNames.length; j < m; ++j) classFields[fieldNames[j]] = this.fields[i] - } - for (i = 0, l = this.methods.length; i < l; ++i) { - var method = this.methods[i]; - classMethods[method.name] = method - } - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - classInners[innerClass.name] = innerClass - } - }; - AstClassBody.prototype.toString = function() { - function getScopeLevel(p) { - var i = 0; - while (p) { - ++i; - p = p.scope - } - return i - } - var scopeLevel = getScopeLevel(this.owner); - var selfId = "$this_" + scopeLevel; - var className = this.name; - var result = "var " + selfId + " = this;\n"; - var staticDefinitions = ""; - var metadata = ""; - var thisClassFields = {}, - thisClassMethods = {}, - thisClassInners = {}; - this.getMembers(thisClassFields, thisClassMethods, thisClassInners); - var oldContext = replaceContext; - replaceContext = function(subject) { - var name = subject.name; - if (name === "this") return subject.callSign || !subject.member ? selfId + ".$self" : selfId; - if (thisClassFields.hasOwnProperty(name)) return thisClassFields[name].isStatic ? className + "." + name : selfId + "." + name; - if (thisClassInners.hasOwnProperty(name)) return selfId + "." + name; - if (thisClassMethods.hasOwnProperty(name)) return thisClassMethods[name].isStatic ? className + "." + name : selfId + ".$self." + name; - return oldContext(subject) - }; - var resolvedBaseClassName; - if (this.baseClassName) { - resolvedBaseClassName = oldContext({ - name: this.baseClassName - }); - result += "var $super = { $upcast: " + selfId + " };\n"; - result += "function $superCstr(){" + resolvedBaseClassName + ".apply($super,arguments);if(!('$self' in $super)) $p.extendClassChain($super)}\n"; - metadata += className + ".$base = " + resolvedBaseClassName + ";\n" - } else result += "function $superCstr(){$p.extendClassChain(" + selfId + ")}\n"; - if (this.owner.base) staticDefinitions += "$p.extendStaticMembers(" + className + ", " + resolvedBaseClassName + ");\n"; - var i, l, j, m; - if (this.owner.interfaces) { - var resolvedInterfaces = [], - resolvedInterface; - for (i = 0, l = this.interfacesNames.length; i < l; ++i) { - if (!this.owner.interfaces[i]) continue; - resolvedInterface = oldContext({ - name: this.interfacesNames[i] - }); - resolvedInterfaces.push(resolvedInterface); - staticDefinitions += "$p.extendInterfaceMembers(" + className + ", " + resolvedInterface + ");\n" - } - metadata += className + ".$interfaces = [" + resolvedInterfaces.join(", ") + "];\n" - } - if (this.functions.length > 0) result += this.functions.join("\n") + "\n"; - sortByWeight(this.innerClasses); - for (i = 0, l = this.innerClasses.length; i < l; ++i) { - var innerClass = this.innerClasses[i]; - if (innerClass.isStatic) { - staticDefinitions += className + "." + innerClass.name + " = " + innerClass + ";\n"; - result += selfId + "." + innerClass.name + " = " + className + "." + innerClass.name + ";\n" - } else result += selfId + "." + innerClass.name + " = " + innerClass + ";\n" - } - for (i = 0, l = this.fields.length; i < l; ++i) { - var field = this.fields[i]; - if (field.isStatic) { - staticDefinitions += className + "." + field.definitions.join(";\n" + className + ".") + ";\n"; - for (j = 0, m = field.definitions.length; j < m; ++j) { - var fieldName = field.definitions[j].name, - staticName = className + "." + fieldName; - result += "$p.defineProperty(" + selfId + ", '" + fieldName + "', {" + "get: function(){return " + staticName + "}, " + "set: function(val){" + staticName + " = val}});\n" - } - } else result += selfId + "." + field.definitions.join(";\n" + selfId + ".") + ";\n" - } - var methodOverloads = {}; - for (i = 0, l = this.methods.length; i < l; ++i) { - var method = this.methods[i]; - var overload = methodOverloads[method.name]; - var methodId = method.name + "$" + method.params.params.length; - var hasMethodArgs = !!method.params.methodArgsParam; - if (overload) { - ++overload; - methodId += "_" + overload - } else overload = 1; - method.methodId = methodId; - methodOverloads[method.name] = overload; - if (method.isStatic) { - staticDefinitions += method; - staticDefinitions += "$p.addMethod(" + className + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n"; - result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n" - } else { - result += method; - result += "$p.addMethod(" + selfId + ", '" + method.name + "', " + methodId + ", " + hasMethodArgs + ");\n" - } - } - result += trim(this.misc.tail); - if (this.cstrs.length > 0) result += this.cstrs.join("\n") + "\n"; - result += "function $constr() {\n"; - var cstrsIfs = []; - for (i = 0, l = this.cstrs.length; i < l; ++i) { - var paramsLength = this.cstrs[i].params.params.length; - var methodArgsPresent = !!this.cstrs[i].params.methodArgsParam; - cstrsIfs.push("if(arguments.length " + (methodArgsPresent ? ">=" : "===") + " " + paramsLength + ") { " + "$constr_" + paramsLength + ".apply(" + selfId + ", arguments); }") - } - if (cstrsIfs.length > 0) result += cstrsIfs.join(" else ") + " else "; - result += "$superCstr();\n}\n"; - result += "$constr.apply(null, arguments);\n"; - replaceContext = oldContext; - return "(function() {\n" + "function " + className + "() {\n" + result + "}\n" + staticDefinitions + metadata + "return " + className + ";\n" + "})()" - }; - transformClassBody = function(body, name, baseName, interfaces) { - var declarations = body.substring(1, body.length - 1); - declarations = extractClassesAndMethods(declarations); - declarations = extractConstructors(declarations, name); - var methods = [], - classes = [], - cstrs = [], - functions = []; - declarations = declarations.replace(/"([DEGH])(\d+)"/g, function(all, type, index) { - if (type === "D") methods.push(index); - else if (type === "E") classes.push(index); - else if (type === "H") functions.push(index); - else cstrs.push(index); - return "" - }); - var fields = declarations.replace(/^(?:\s*;)+/, "").split(/;(?:\s*;)*/g); - var baseClassName, interfacesNames; - var i; - if (baseName !== undef) baseClassName = baseName.replace(/^\s*extends\s+([A-Za-z_$][\w$]*\b(?:\s*\.\s*[A-Za-z_$][\w$]*\b)*)\s*$/g, "$1"); - if (interfaces !== undef) interfacesNames = interfaces.replace(/^\s*implements\s+(.+?)\s*$/g, "$1").split(/\s*,\s*/g); - for (i = 0; i < functions.length; ++i) functions[i] = transformFunction(atoms[functions[i]]); - for (i = 0; i < methods.length; ++i) methods[i] = transformClassMethod(atoms[methods[i]]); - for (i = 0; i < fields.length - 1; ++i) { - var field = trimSpaces(fields[i]); - fields[i] = transformClassField(field.middle) - } - var tail = fields.pop(); - for (i = 0; i < cstrs.length; ++i) cstrs[i] = transformConstructor(atoms[cstrs[i]]); - for (i = 0; i < classes.length; ++i) classes[i] = transformInnerClass(atoms[classes[i]]); - return new AstClassBody(name, baseClassName, interfacesNames, functions, methods, fields, cstrs, classes, { - tail: tail - }) - }; - - function AstInterface(name, body) { - this.name = name; - this.body = body; - body.owner = this - } - AstInterface.prototype.toString = function() { - return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" - }; - - function AstClass(name, body) { - this.name = name; - this.body = body; - body.owner = this - } - AstClass.prototype.toString = function() { - return "var " + this.name + " = " + this.body + ";\n" + "$p." + this.name + " = " + this.name + ";\n" - }; - - function transformGlobalClass(class_) { - var m = classesRegex.exec(class_); - classesRegex.lastIndex = 0; - var body = atoms[getAtomIndex(m[6])]; - var oldClassId = currentClassId, - newClassId = generateClassId(); - currentClassId = newClassId; - var globalClass; - if (m[2] === "interface") globalClass = new AstInterface(m[3], transformInterfaceBody(body, m[3], m[4])); - else globalClass = new AstClass(m[3], transformClassBody(body, m[3], m[4], m[5])); - appendClass(globalClass, newClassId, oldClassId); - currentClassId = oldClassId; - return globalClass - } - function AstMethod(name, params, body) { - this.name = name; - this.params = params; - this.body = body - } - AstMethod.prototype.toString = function() { - var paramNames = appendToLookupTable({}, - this.params.getNames()); - var oldContext = replaceContext; - replaceContext = function(subject) { - return paramNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) - }; - var body = this.params.prependMethodArgs(this.body.toString()); - var result = "function " + this.name + this.params + " " + body + "\n" + "$p." + this.name + " = " + this.name + ";"; - replaceContext = oldContext; - return result - }; - - function transformGlobalMethod(method) { - var m = methodsRegex.exec(method); - var result = methodsRegex.lastIndex = 0; - return new AstMethod(m[3], transformParams(atoms[getAtomIndex(m[4])]), transformStatementsBlock(atoms[getAtomIndex(m[6])])) - } - function preStatementsTransform(statements) { - var s = statements; - s = s.replace(/\b(catch\s*"B\d+"\s*"A\d+")(\s*catch\s*"B\d+"\s*"A\d+")+/g, "$1"); - return s - } - function AstForStatement(argument, misc) { - this.argument = argument; - this.misc = misc - } - AstForStatement.prototype.toString = function() { - return this.misc.prefix + this.argument.toString() - }; - - function AstCatchStatement(argument, misc) { - this.argument = argument; - this.misc = misc - } - AstCatchStatement.prototype.toString = function() { - return this.misc.prefix + this.argument.toString() - }; - - function AstPrefixStatement(name, argument, misc) { - this.name = name; - this.argument = argument; - this.misc = misc - } - AstPrefixStatement.prototype.toString = function() { - var result = this.misc.prefix; - if (this.argument !== undef) result += this.argument.toString(); - return result - }; - - function AstSwitchCase(expr) { - this.expr = expr - } - AstSwitchCase.prototype.toString = function() { - return "case " + this.expr + ":" - }; - - function AstLabel(label) { - this.label = label - } - AstLabel.prototype.toString = function() { - return this.label - }; - transformStatements = function(statements, transformMethod, transformClass) { - var nextStatement = new RegExp(/\b(catch|for|if|switch|while|with)\s*"B(\d+)"|\b(do|else|finally|return|throw|try|break|continue)\b|("[ADEH](\d+)")|\b(case)\s+([^:]+):|\b([A-Za-z_$][\w$]*\s*:)|(;)/g); - var res = []; - statements = preStatementsTransform(statements); - var lastIndex = 0, - m, space; - while ((m = nextStatement.exec(statements)) !== null) { - if (m[1] !== undef) { - var i = statements.lastIndexOf('"B', nextStatement.lastIndex); - var statementsPrefix = statements.substring(lastIndex, i); - if (m[1] === "for") res.push(new AstForStatement(transformForExpression(atoms[m[2]]), { - prefix: statementsPrefix - })); - else if (m[1] === "catch") res.push(new AstCatchStatement(transformParams(atoms[m[2]]), { - prefix: statementsPrefix - })); - else res.push(new AstPrefixStatement(m[1], transformExpression(atoms[m[2]]), { - prefix: statementsPrefix - })) - } else if (m[3] !== undef) res.push(new AstPrefixStatement(m[3], undef, { - prefix: statements.substring(lastIndex, nextStatement.lastIndex) - })); - else if (m[4] !== undef) { - space = statements.substring(lastIndex, nextStatement.lastIndex - m[4].length); - if (trim(space).length !== 0) continue; - res.push(space); - var kind = m[4].charAt(1), - atomIndex = m[5]; - if (kind === "D") res.push(transformMethod(atoms[atomIndex])); - else if (kind === "E") res.push(transformClass(atoms[atomIndex])); - else if (kind === "H") res.push(transformFunction(atoms[atomIndex])); - else res.push(transformStatementsBlock(atoms[atomIndex])) - } else if (m[6] !== undef) res.push(new AstSwitchCase(transformExpression(trim(m[7])))); - else if (m[8] !== undef) { - space = statements.substring(lastIndex, nextStatement.lastIndex - m[8].length); - if (trim(space).length !== 0) continue; - res.push(new AstLabel(statements.substring(lastIndex, nextStatement.lastIndex))) - } else { - var statement = trimSpaces(statements.substring(lastIndex, nextStatement.lastIndex - 1)); - res.push(statement.left); - res.push(transformStatement(statement.middle)); - res.push(statement.right + ";") - } - lastIndex = nextStatement.lastIndex - } - var statementsTail = trimSpaces(statements.substring(lastIndex)); - res.push(statementsTail.left); - if (statementsTail.middle !== "") { - res.push(transformStatement(statementsTail.middle)); - res.push(";" + statementsTail.right) - } - return res - }; - - function getLocalNames(statements) { - var localNames = []; - for (var i = 0, l = statements.length; i < l; ++i) { - var statement = statements[i]; - if (statement instanceof AstVar) localNames = localNames.concat(statement.getNames()); - else if (statement instanceof AstForStatement && statement.argument.initStatement instanceof AstVar) localNames = localNames.concat(statement.argument.initStatement.getNames()); - else if (statement instanceof AstInnerInterface || statement instanceof AstInnerClass || statement instanceof AstInterface || statement instanceof AstClass || statement instanceof AstMethod || statement instanceof AstFunction) localNames.push(statement.name) - } - return appendToLookupTable({}, - localNames) - } - function AstStatementsBlock(statements) { - this.statements = statements - } - AstStatementsBlock.prototype.toString = function() { - var localNames = getLocalNames(this.statements); - var oldContext = replaceContext; - if (!isLookupTableEmpty(localNames)) replaceContext = function(subject) { - return localNames.hasOwnProperty(subject.name) ? subject.name : oldContext(subject) - }; - var result = "{\n" + this.statements.join("") + "\n}"; - replaceContext = oldContext; - return result - }; - transformStatementsBlock = function(block) { - var content = trimSpaces(block.substring(1, block.length - 1)); - return new AstStatementsBlock(transformStatements(content.middle)) - }; - - function AstRoot(statements) { - this.statements = statements - } - AstRoot.prototype.toString = function() { - var classes = [], - otherStatements = [], - statement; - for (var i = 0, len = this.statements.length; i < len; ++i) { - statement = this.statements[i]; - if (statement instanceof AstClass || statement instanceof AstInterface) classes.push(statement); - else otherStatements.push(statement) - } - sortByWeight(classes); - var localNames = getLocalNames(this.statements); - replaceContext = function(subject) { - var name = subject.name; - if (localNames.hasOwnProperty(name)) return name; - if (globalMembers.hasOwnProperty(name) || PConstants.hasOwnProperty(name) || defaultScope.hasOwnProperty(name)) return "$p." + name; - return name - }; - var result = "// this code was autogenerated from PJS\n" + "(function($p) {\n" + classes.join("") + "\n" + otherStatements.join("") + "\n})"; - replaceContext = null; - return result - }; - transformMain = function() { - var statements = extractClassesAndMethods(atoms[0]); - statements = statements.replace(/\bimport\s+[^;]+;/g, ""); - return new AstRoot(transformStatements(statements, transformGlobalMethod, transformGlobalClass)) - }; - - function generateMetadata(ast) { - var globalScope = {}; - var id, class_; - for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - var scopeId = class_.scopeId, - name = class_.name; - if (scopeId) { - var scope = declaredClasses[scopeId]; - class_.scope = scope; - if (scope.inScope === undef) scope.inScope = {}; - scope.inScope[name] = class_ - } else globalScope[name] = class_ - } - function findInScopes(class_, name) { - var parts = name.split("."); - var currentScope = class_.scope, - found; - while (currentScope) { - if (currentScope.hasOwnProperty(parts[0])) { - found = currentScope[parts[0]]; - break - } - currentScope = currentScope.scope - } - if (found === undef) found = globalScope[parts[0]]; - for (var i = 1, l = parts.length; i < l && found; ++i) found = found.inScope[parts[i]]; - return found - } - for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - var baseClassName = class_.body.baseClassName; - if (baseClassName) { - var parent = findInScopes(class_, baseClassName); - if (parent) { - class_.base = parent; - if (!parent.derived) parent.derived = []; - parent.derived.push(class_) - } - } - var interfacesNames = class_.body.interfacesNames, - interfaces = [], - i, l; - if (interfacesNames && interfacesNames.length > 0) { - for (i = 0, l = interfacesNames.length; i < l; ++i) { - var interface_ = findInScopes(class_, interfacesNames[i]); - interfaces.push(interface_); - if (!interface_) continue; - if (!interface_.derived) interface_.derived = []; - interface_.derived.push(class_) - } - if (interfaces.length > 0) class_.interfaces = interfaces - } - } - } - function setWeight(ast) { - var queue = [], - tocheck = {}; - var id, scopeId, class_; - for (id in declaredClasses) if (declaredClasses.hasOwnProperty(id)) { - class_ = declaredClasses[id]; - if (!class_.inScope && !class_.derived) { - queue.push(id); - class_.weight = 0 - } else { - var dependsOn = []; - if (class_.inScope) for (scopeId in class_.inScope) if (class_.inScope.hasOwnProperty(scopeId)) dependsOn.push(class_.inScope[scopeId]); - if (class_.derived) dependsOn = dependsOn.concat(class_.derived); - tocheck[id] = dependsOn - } - } - function removeDependentAndCheck(targetId, from) { - var dependsOn = tocheck[targetId]; - if (!dependsOn) return false; - var i = dependsOn.indexOf(from); - if (i < 0) return false; - dependsOn.splice(i, 1); - if (dependsOn.length > 0) return false; - delete tocheck[targetId]; - return true - } - while (queue.length > 0) { - id = queue.shift(); - class_ = declaredClasses[id]; - if (class_.scopeId && removeDependentAndCheck(class_.scopeId, class_)) { - queue.push(class_.scopeId); - declaredClasses[class_.scopeId].weight = class_.weight + 1 - } - if (class_.base && removeDependentAndCheck(class_.base.classId, class_)) { - queue.push(class_.base.classId); - class_.base.weight = class_.weight + 1 - } - if (class_.interfaces) { - var i, l; - for (i = 0, l = class_.interfaces.length; i < l; ++i) { - if (!class_.interfaces[i] || !removeDependentAndCheck(class_.interfaces[i].classId, class_)) continue; - queue.push(class_.interfaces[i].classId); - class_.interfaces[i].weight = class_.weight + 1 - } - } - } - } - var transformed = transformMain(); - generateMetadata(transformed); - setWeight(transformed); - var redendered = transformed.toString(); - redendered = redendered.replace(/\s*\n(?:[\t ]*\n)+/g, "\n\n"); - redendered = redendered.replace(/__x([0-9A-F]{4})/g, function(all, hexCode) { - return String.fromCharCode(parseInt(hexCode, 16)) - }); - return injectStrings(redendered, strings) - } - - function preprocessCode(aCode, sketch) { - var dm = (new RegExp(/\/\*\s*@pjs\s+((?:[^\*]|\*+[^\*\/])*)\*\//g)).exec(aCode); - if (dm && dm.length === 2) { - var jsonItems = [], - directives = dm.splice(1, 2)[0].replace(/\{([\s\S]*?)\}/g, function() { - return function(all, item) { - jsonItems.push(item); - return "{" + (jsonItems.length - 1) + "}" - } - }()).replace("\n", "").replace("\r", "").split(";"); - var clean = function(s) { - return s.replace(/^\s*["']?/, "").replace(/["']?\s*$/, "") - }; - for (var i = 0, dl = directives.length; i < dl; i++) { - var pair = directives[i].split("="); - if (pair && pair.length === 2) { - var key = clean(pair[0]), - value = clean(pair[1]), - list = []; - if (key === "preload") { - list = value.split(","); - for (var j = 0, jl = list.length; j < jl; j++) { - var imageName = clean(list[j]); - sketch.imageCache.add(imageName) - } - } else if (key === "font") { - list = value.split(","); - for (var x = 0, xl = list.length; x < xl; x++) { - var fontName = clean(list[x]), - index = /^\{(\d*?)\}$/.exec(fontName); - PFont.preloading.add(index ? JSON.parse("{" + jsonItems[index[1]] + "}") : fontName) - } - } else if (key === "pauseOnBlur") sketch.options.pauseOnBlur = value === "true"; - else if (key === "globalKeyEvents") sketch.options.globalKeyEvents = value === "true"; - else if (key.substring(0, 6) === "param-") sketch.params[key.substring(6)] = value; - else sketch.options[key] = value - } - } - } - return aCode - } - Processing.compile = function(pdeCode) { - var sketch = new Processing.Sketch; - var code = preprocessCode(pdeCode, sketch); - var compiledPde = parseProcessing(code); - sketch.sourceCode = compiledPde; - return sketch - }; - var tinylogLite = function() { - var tinylogLite = {}, - undef = "undefined", - func = "function", - False = !1, - True = !0, - logLimit = 512, - log = "log"; - if (typeof tinylog !== undef && typeof tinylog[log] === func) tinylogLite[log] = tinylog[log]; - else if (typeof document !== undef && !document.fake)(function() { - var doc = document, - $div = "div", - $style = "style", - $title = "title", - containerStyles = { - zIndex: 1E4, - position: "fixed", - bottom: "0px", - width: "100%", - height: "15%", - fontFamily: "sans-serif", - color: "#ccc", - backgroundColor: "black" - }, - outputStyles = { - position: "relative", - fontFamily: "monospace", - overflow: "auto", - height: "100%", - paddingTop: "5px" - }, - resizerStyles = { - height: "5px", - marginTop: "-5px", - cursor: "n-resize", - backgroundColor: "darkgrey" - }, - closeButtonStyles = { - position: "absolute", - top: "5px", - right: "20px", - color: "#111", - MozBorderRadius: "4px", - webkitBorderRadius: "4px", - borderRadius: "4px", - cursor: "pointer", - fontWeight: "normal", - textAlign: "center", - padding: "3px 5px", - backgroundColor: "#333", - fontSize: "12px" - }, - entryStyles = { - minHeight: "16px" - }, - entryTextStyles = { - fontSize: "12px", - margin: "0 8px 0 8px", - maxWidth: "100%", - whiteSpace: "pre-wrap", - overflow: "auto" - }, - view = doc.defaultView, - docElem = doc.documentElement, - docElemStyle = docElem[$style], - setStyles = function() { - var i = arguments.length, - elemStyle, styles, style; - while (i--) { - styles = arguments[i--]; - elemStyle = arguments[i][$style]; - for (style in styles) if (styles.hasOwnProperty(style)) elemStyle[style] = styles[style] - } - }, - observer = function(obj, event, handler) { - if (obj.addEventListener) obj.addEventListener(event, handler, False); - else if (obj.attachEvent) obj.attachEvent("on" + event, handler); - return [obj, event, handler] - }, - unobserve = function(obj, event, handler) { - if (obj.removeEventListener) obj.removeEventListener(event, handler, False); - else if (obj.detachEvent) obj.detachEvent("on" + event, handler) - }, - clearChildren = function(node) { - var children = node.childNodes, - child = children.length; - while (child--) node.removeChild(children.item(0)) - }, - append = function(to, elem) { - return to.appendChild(elem) - }, - createElement = function(localName) { - return doc.createElement(localName) - }, - createTextNode = function(text) { - return doc.createTextNode(text) - }, - createLog = tinylogLite[log] = function(message) { - var uninit, originalPadding = docElemStyle.paddingBottom, - container = createElement($div), - containerStyle = container[$style], - resizer = append(container, createElement($div)), - output = append(container, createElement($div)), - closeButton = append(container, createElement($div)), - resizingLog = False, - previousHeight = False, - previousScrollTop = False, - messages = 0, - updateSafetyMargin = function() { - docElemStyle.paddingBottom = container.clientHeight + "px" - }, - setContainerHeight = function(height) { - var viewHeight = view.innerHeight, - resizerHeight = resizer.clientHeight; - if (height < 0) height = 0; - else if (height + resizerHeight > viewHeight) height = viewHeight - resizerHeight; - containerStyle.height = height / viewHeight * 100 + "%"; - updateSafetyMargin() - }, - observers = [observer(doc, "mousemove", function(evt) { - if (resizingLog) { - setContainerHeight(view.innerHeight - evt.clientY); - output.scrollTop = previousScrollTop - } - }), observer(doc, "mouseup", function() { - if (resizingLog) resizingLog = previousScrollTop = False - }), observer(resizer, "dblclick", function(evt) { - evt.preventDefault(); - if (previousHeight) { - setContainerHeight(previousHeight); - previousHeight = False - } else { - previousHeight = container.clientHeight; - containerStyle.height = "0px" - } - }), observer(resizer, "mousedown", function(evt) { - evt.preventDefault(); - resizingLog = True; - previousScrollTop = output.scrollTop - }), observer(resizer, "contextmenu", function() { - resizingLog = False - }), observer(closeButton, "click", function() { - uninit() - })]; - uninit = function() { - var i = observers.length; - while (i--) unobserve.apply(tinylogLite, observers[i]); - docElem.removeChild(container); - docElemStyle.paddingBottom = originalPadding; - clearChildren(output); - clearChildren(container); - tinylogLite[log] = createLog - }; - setStyles(container, containerStyles, output, outputStyles, resizer, resizerStyles, closeButton, closeButtonStyles); - closeButton[$title] = "Close Log"; - append(closeButton, createTextNode("\u2716")); - resizer[$title] = "Double-click to toggle log minimization"; - docElem.insertBefore(container, docElem.firstChild); - tinylogLite[log] = function(message) { - if (messages === logLimit) output.removeChild(output.firstChild); - else messages++; - var entry = append(output, createElement($div)), - entryText = append(entry, createElement($div)); - entry[$title] = (new Date).toLocaleTimeString(); - setStyles(entry, entryStyles, entryText, entryTextStyles); - append(entryText, createTextNode(message)); - output.scrollTop = output.scrollHeight - }; - tinylogLite[log](message); - updateSafetyMargin() - } - })(); - else if (typeof print === func) tinylogLite[log] = print; - return tinylogLite - }(); - Processing.logger = tinylogLite; - Processing.version = "1.4.1"; - Processing.lib = {}; - Processing.registerLibrary = function(name, desc) { - Processing.lib[name] = desc; - if (desc.hasOwnProperty("init")) desc.init(defaultScope) - }; - Processing.instances = processingInstances; - Processing.getInstanceById = function(name) { - return processingInstances[processingInstanceIds[name]] - }; - Processing.Sketch = function(attachFunction) { - this.attachFunction = attachFunction; - this.options = { - pauseOnBlur: false, - globalKeyEvents: false - }; - this.onLoad = nop; - this.onSetup = nop; - this.onPause = nop; - this.onLoop = nop; - this.onFrameStart = nop; - this.onFrameEnd = nop; - this.onExit = nop; - this.params = {}; - this.imageCache = { - pending: 0, - images: {}, - operaCache: {}, - add: function(href, img) { - if (this.images[href]) return; - if (!isDOMPresent) this.images[href] = null; - if (!img) { - img = new Image; - img.onload = function(owner) { - return function() { - owner.pending-- - } - }(this); - this.pending++; - img.src = href - } - this.images[href] = img; - if (window.opera) { - var div = document.createElement("div"); - div.appendChild(img); - div.style.position = "absolute"; - div.style.opacity = 0; - div.style.width = "1px"; - div.style.height = "1px"; - if (!this.operaCache[href]) { - document.body.appendChild(div); - this.operaCache[href] = div - } - } - } - }; - this.sourceCode = undefined; - this.attach = function(processing) { - if (typeof this.attachFunction === "function") this.attachFunction(processing); - else if (this.sourceCode) { - var func = (new Function("return (" + this.sourceCode + ");"))(); - func(processing); - this.attachFunction = func - } else throw "Unable to attach sketch to the processing instance"; - }; - this.toString = function() { - var i; - var code = "((function(Sketch) {\n"; - code += "var sketch = new Sketch(\n" + this.sourceCode + ");\n"; - for (i in this.options) if (this.options.hasOwnProperty(i)) { - var value = this.options[i]; - code += "sketch.options." + i + " = " + (typeof value === "string" ? '"' + value + '"' : "" + value) + ";\n" - } - for (i in this.imageCache) if (this.options.hasOwnProperty(i)) code += 'sketch.imageCache.add("' + i + '");\n'; - code += "return sketch;\n})(Processing.Sketch))"; - return code - } - }; - var loadSketchFromSources = function(canvas, sources) { - var code = [], - errors = [], - sourcesCount = sources.length, - loaded = 0; - - function ajaxAsync(url, callback) { - var xhr = new XMLHttpRequest; - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var error; - if (xhr.status !== 200 && xhr.status !== 0) error = "Invalid XHR status " + xhr.status; - else if (xhr.responseText === "") if ("withCredentials" in new XMLHttpRequest && (new XMLHttpRequest).withCredentials === false && window.location.protocol === "file:") error = "XMLHttpRequest failure, possibly due to a same-origin policy violation. You can try loading this page in another browser, or load it from http://localhost using a local webserver. See the Processing.js README for a more detailed explanation of this problem and solutions."; - else error = "File is empty."; - callback(xhr.responseText, error) - } - }; - xhr.open("GET", url, true); - if (xhr.overrideMimeType) xhr.overrideMimeType("application/json"); - xhr.setRequestHeader("If-Modified-Since", "Fri, 01 Jan 1960 00:00:00 GMT"); - xhr.send(null) - } - function loadBlock(index, filename) { - function callback(block, error) { - code[index] = block; - ++loaded; - if (error) errors.push(filename + " ==> " + error); - if (loaded === sourcesCount) if (errors.length === 0) try { - return new Processing(canvas, code.join("\n")) - } catch(e) { - throw "Processing.js: Unable to execute pjs sketch: " + e; - } else throw "Processing.js: Unable to load pjs sketch files: " + errors.join("\n"); - } - if (filename.charAt(0) === "#") { - var scriptElement = document.getElementById(filename.substring(1)); - if (scriptElement) callback(scriptElement.text || scriptElement.textContent); - else callback("", "Unable to load pjs sketch: element with id '" + filename.substring(1) + "' was not found"); - return - } - ajaxAsync(filename, callback) - } - for (var i = 0; i < sourcesCount; ++i) loadBlock(i, sources[i]) - }; - var init = function() { - document.removeEventListener("DOMContentLoaded", init, false); - processingInstances = []; - var canvas = document.getElementsByTagName("canvas"), - filenames; - for (var i = 0, l = canvas.length; i < l; i++) { - var processingSources = canvas[i].getAttribute("data-processing-sources"); - if (processingSources === null) { - processingSources = canvas[i].getAttribute("data-src"); - if (processingSources === null) processingSources = canvas[i].getAttribute("datasrc") - } - if (processingSources) { - filenames = processingSources.split(/\s+/g); - for (var j = 0; j < filenames.length;) if (filenames[j]) j++; - else filenames.splice(j, 1); - loadSketchFromSources(canvas[i], filenames) - } - } - var s, last, source, instance, nodelist = document.getElementsByTagName("script"), - scripts = []; - for (s = nodelist.length - 1; s >= 0; s--) scripts.push(nodelist[s]); - for (s = 0, last = scripts.length; s < last; s++) { - var script = scripts[s]; - if (!script.getAttribute) continue; - var type = script.getAttribute("type"); - if (type && (type.toLowerCase() === "text/processing" || type.toLowerCase() === "application/processing")) { - var target = script.getAttribute("data-processing-target"); - canvas = undef; - if (target) canvas = document.getElementById(target); - else { - var nextSibling = script.nextSibling; - while (nextSibling && nextSibling.nodeType !== 1) nextSibling = nextSibling.nextSibling; - if (nextSibling && nextSibling.nodeName.toLowerCase() === "canvas") canvas = nextSibling - } - if (canvas) { - if (script.getAttribute("src")) { - filenames = script.getAttribute("src").split(/\s+/); - loadSketchFromSources(canvas, filenames); - continue - } - source = script.textContent || script.text; - instance = new Processing(canvas, source) - } - } - } - }; - Processing.reload = function() { - if (processingInstances.length > 0) for (var i = processingInstances.length - 1; i >= 0; i--) if (processingInstances[i]) processingInstances[i].exit(); - init() - }; - Processing.loadSketchFromSources = loadSketchFromSources; - Processing.disableInit = function() { - if (isDOMPresent) document.removeEventListener("DOMContentLoaded", init, false) - }; - if (isDOMPresent) { - window["Processing"] = Processing; - document.addEventListener("DOMContentLoaded", init, false) - } else this.Processing = Processing -})(window, window.document, Math); - From c66eba022a82aa7eedc245c8f3bc9660328e6395 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Sat, 9 Mar 2013 14:18:45 -0500 Subject: [PATCH 14/25] removing stray sketch.properties file --- .../Topics/Advanced Data/LoadingXMLObjects/sketch.properties | 1 - 1 file changed, 1 deletion(-) delete mode 100644 java/examples/Topics/Advanced Data/LoadingXMLObjects/sketch.properties diff --git a/java/examples/Topics/Advanced Data/LoadingXMLObjects/sketch.properties b/java/examples/Topics/Advanced Data/LoadingXMLObjects/sketch.properties deleted file mode 100644 index 28faa5897..000000000 --- a/java/examples/Topics/Advanced Data/LoadingXMLObjects/sketch.properties +++ /dev/null @@ -1 +0,0 @@ -mode=Standard From deb9e304a1f5835267b906e1732abd2ab0ccb607 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Sat, 9 Mar 2013 14:22:20 -0500 Subject: [PATCH 15/25] adding feature to limit table size to 10 to table example --- .../Topics/Advanced Data/LoadSaveTable/LoadSaveTable.pde | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/examples/Topics/Advanced Data/LoadSaveTable/LoadSaveTable.pde b/java/examples/Topics/Advanced Data/LoadSaveTable/LoadSaveTable.pde index 2e3f2a20e..e8fcc64ae 100644 --- a/java/examples/Topics/Advanced Data/LoadSaveTable/LoadSaveTable.pde +++ b/java/examples/Topics/Advanced Data/LoadSaveTable/LoadSaveTable.pde @@ -69,6 +69,12 @@ void mousePressed() { row.setFloat("y", mouseY); row.setFloat("diameter", random(40, 80)); row.setString("name", "Blah"); + + // If the table has more than 10 rows + if (table.getRowCount() > 10) { + // Delete the oldest row + table.removeRow(0); + } // Writing the CSV back to the same file saveTable(table,"data/data.csv"); From e915e22800ae6309f92658add0fc6e3a676daad5 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Sat, 9 Mar 2013 14:26:16 -0500 Subject: [PATCH 16/25] starting new XML example --- .../Advanced Data/LoadSaveXML/Bubble.pde | 40 +++++++++ .../Advanced Data/LoadSaveXML/LoadSaveXML.pde | 84 +++++++++++++++++++ .../LoadSaveXML/data/bubbles.xml | 1 + .../Advanced Data/LoadSaveXML/data/data.csv | 5 ++ 4 files changed, 130 insertions(+) create mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/Bubble.pde create mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde create mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml create mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/Bubble.pde b/java/examples/Topics/Advanced Data/LoadSaveXML/Bubble.pde new file mode 100644 index 000000000..3a7b9b7f9 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/Bubble.pde @@ -0,0 +1,40 @@ +// A Bubble class + +class Bubble { + float x,y; + float diameter; + String name; + + boolean over = false; + + // Create the Bubble + Bubble(float x_, float y_, float diameter_, String s) { + x = x_; + y = y_; + diameter = diameter_; + name = s; + } + + // CHecking if mouse is over the Bubble + void rollover(float px, float py) { + float d = dist(px,py,x,y); + if (d < diameter/2) { + over = true; + } else { + over = false; + } + } + + // Display the Bubble + void display() { + stroke(0); + strokeWeight(2); + noFill(); + ellipse(x,y,diameter,diameter); + if (over) { + fill(0); + textAlign(CENTER); + text(name,x,y+diameter/2+20); + } + } +} diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde new file mode 100644 index 000000000..dae9a851f --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde @@ -0,0 +1,84 @@ +/** + * Loading XML Data + * by Daniel Shiffman. + * + * This example demonstrates how to use loadXML() + * to retrieve data from an XML file and make objects + * from that data. + * + * Here is what the XML looks like: + * + x,y,diameter,name + 160,103,43.19838,Happy + 372,137,52.42526,Sad + 273,235,61.14072,Joyous + 121,179,44.758068,Melancholy + */ + +// An Array of Bubble objects +Bubble[] bubbles; +// A Table object +Table table; + +void setup() { + size(640, 360); + loadData(); +} + +void draw() { + background(255); + // Display all bubbles + for (Bubble b : bubbles) { + b.display(); + b.rollover(mouseX, mouseY); + } + + textAlign(LEFT); + fill(0); + text("Click to add bubbles.", 10, height-10); +} + +void loadData() { + // Load CSV file into a Table object + // "header" option indicates the file has a header row + table = loadTable("data.csv","header"); + + // The size of the array of Bubble objects is determined by the total number of rows in the CSV + bubbles = new Bubble[table.getRowCount()]; + + // You can access iterate over all the rows in a table + int rowCount = 0; + for (TableRow row : table.rows()) { + // You can access the fields via their column name (or index) + float x = row.getFloat("x"); + float y = row.getFloat("y"); + float d = row.getFloat("diameter"); + String n = row.getString("name"); + // Make a Bubble object out of the data read + bubbles[rowCount] = new Bubble(x, y, d, n); + rowCount++; + } + +} + +void mousePressed() { + // Create a new row + TableRow row = table.addRow(); + // Set the values of that row + row.setFloat("x", mouseX); + row.setFloat("y", mouseY); + row.setFloat("diameter", random(40, 80)); + row.setString("name", "Blah"); + + // If the table has more than 10 rows + if (table.getRowCount() > 10) { + // Delete the oldest row + table.removeRow(0); + } + + // Writing the CSV back to the same file + saveTable(table,"data/data.csv"); + // And reloading it + loadData(); +} + diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml b/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml new file mode 100644 index 000000000..a63b7f5a8 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml @@ -0,0 +1 @@ +x,y,diameter,name 160,103,43.19838,Happy 372,137,52.42526,Sad 273,235,61.14072,Joyous 121,179,44.758068,Melancholy 43.19838 52.42526 43.19838 43.19838 \ No newline at end of file diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv new file mode 100644 index 000000000..88ac4c1b7 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv @@ -0,0 +1,5 @@ +x,y,diameter,name +160,103,43.19838,Happy +372,137,52.42526,Sad +273,235,61.14072,Joyous +121,179,44.758068,Melancholy \ No newline at end of file From b9cb81b0985720d323c6df321a9bbc1bec45f43d Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Sun, 10 Mar 2013 22:12:02 -0400 Subject: [PATCH 17/25] working on XML example, still need functionality for adding and deleting from XML tree --- .../Advanced Data/LoadSaveXML/LoadSaveXML.pde | 66 ++++++++++++------- .../LoadSaveXML/data/bubbles.xml | 1 - .../Advanced Data/LoadSaveXML/data/data.csv | 5 -- .../Advanced Data/LoadSaveXML/data/data.xml | 1 + 4 files changed, 44 insertions(+), 29 deletions(-) delete mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml delete mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv create mode 100644 java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde index dae9a851f..238ddc3ed 100644 --- a/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde @@ -8,17 +8,25 @@ * * Here is what the XML looks like: * - x,y,diameter,name - 160,103,43.19838,Happy - 372,137,52.42526,Sad - 273,235,61.14072,Joyous - 121,179,44.758068,Melancholy + + + + + 43.19838 + + + + + 52.42526 + + + */ // An Array of Bubble objects Bubble[] bubbles; // A Table object -Table table; +XML xml; void setup() { size(640, 360); @@ -39,29 +47,41 @@ void draw() { } void loadData() { - // Load CSV file into a Table object - // "header" option indicates the file has a header row - table = loadTable("data.csv","header"); + // Load XML file + xml = loadXML("data.xml"); + // Get all the child nodes named "bubble" + XML[] children = xml.getChildren("bubble"); - // The size of the array of Bubble objects is determined by the total number of rows in the CSV - bubbles = new Bubble[table.getRowCount()]; + // The size of the array of Bubble objects is determined by the total XML elements named "bubble" + bubbles = new Bubble[children.length]; + + for (int i = 0; i < bubbles.length; i++) { + + + // The position element has two attributes: x and y + XML positionElement = children[i].getChild("position"); + // Note how with attributes we can get an integer or float directly + float x = positionElement.getInt("x"); + float y = positionElement.getInt("y"); + + // The diameter is the content of the child named "diamater" + XML diameterElement = children[i].getChild("diameter"); + // Note how with the content of an XML node, we retrieve as a String and then convert + float diameter = float(diameterElement.getContent()); + + // The label is the content of the child named "label" + XML labelElement = children[i].getChild("label"); + String label = labelElement.getContent(); - // You can access iterate over all the rows in a table - int rowCount = 0; - for (TableRow row : table.rows()) { - // You can access the fields via their column name (or index) - float x = row.getFloat("x"); - float y = row.getFloat("y"); - float d = row.getFloat("diameter"); - String n = row.getString("name"); // Make a Bubble object out of the data read - bubbles[rowCount] = new Bubble(x, y, d, n); - rowCount++; + bubbles[i] = new Bubble(x, y, diameter, label); } } -void mousePressed() { +// Still need to work on adding and deleting + +/*void mousePressed() { // Create a new row TableRow row = table.addRow(); // Set the values of that row @@ -80,5 +100,5 @@ void mousePressed() { saveTable(table,"data/data.csv"); // And reloading it loadData(); -} +}*/ diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml b/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml deleted file mode 100644 index a63b7f5a8..000000000 --- a/java/examples/Topics/Advanced Data/LoadSaveXML/data/bubbles.xml +++ /dev/null @@ -1 +0,0 @@ -x,y,diameter,name 160,103,43.19838,Happy 372,137,52.42526,Sad 273,235,61.14072,Joyous 121,179,44.758068,Melancholy 43.19838 52.42526 43.19838 43.19838 \ No newline at end of file diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv deleted file mode 100644 index 88ac4c1b7..000000000 --- a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.csv +++ /dev/null @@ -1,5 +0,0 @@ -x,y,diameter,name -160,103,43.19838,Happy -372,137,52.42526,Sad -273,235,61.14072,Joyous -121,179,44.758068,Melancholy \ No newline at end of file diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml new file mode 100644 index 000000000..807dd0ba4 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml @@ -0,0 +1 @@ + 43.19838 52.42526 61.14072 44.758068 \ No newline at end of file From 426e9a62eb622dbc16568df40b3fe7d14ae22d69 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Mon, 11 Mar 2013 00:09:05 -0400 Subject: [PATCH 18/25] removing old XML objects example, new one will replace --- .../LoadingXMLObjects/Bubble.pde | 29 --------- .../LoadingXMLObjects/LoadingXMLObjects.pde | 62 ------------------- .../LoadingXMLObjects/data/bubbles.xml | 1 - 3 files changed, 92 deletions(-) delete mode 100644 java/examples/Topics/Advanced Data/LoadingXMLObjects/Bubble.pde delete mode 100644 java/examples/Topics/Advanced Data/LoadingXMLObjects/LoadingXMLObjects.pde delete mode 100644 java/examples/Topics/Advanced Data/LoadingXMLObjects/data/bubbles.xml diff --git a/java/examples/Topics/Advanced Data/LoadingXMLObjects/Bubble.pde b/java/examples/Topics/Advanced Data/LoadingXMLObjects/Bubble.pde deleted file mode 100644 index e99f2a93d..000000000 --- a/java/examples/Topics/Advanced Data/LoadingXMLObjects/Bubble.pde +++ /dev/null @@ -1,29 +0,0 @@ -// A Bubble class -class Bubble { - - float x,y; - float diameter; - color c; - - Bubble(float r,float g, float b, float d) { - x = width/2; - y = height/2; - c = color(r, g, b, 204); - diameter = d; - } - - // Display Bubble - void display() { - noStroke(); - fill(c); - ellipse(x, y, diameter, diameter); - } - - // Bubble drifts upwards - void drift() { - x += random(-1, 1); - y += random(-1, 1); - x = constrain(x, 0, width); - y = constrain(y, 0, height); - } -} diff --git a/java/examples/Topics/Advanced Data/LoadingXMLObjects/LoadingXMLObjects.pde b/java/examples/Topics/Advanced Data/LoadingXMLObjects/LoadingXMLObjects.pde deleted file mode 100644 index d3fb2ef85..000000000 --- a/java/examples/Topics/Advanced Data/LoadingXMLObjects/LoadingXMLObjects.pde +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Loading XML Data - * by Daniel Shiffman. - * - * This example demonstrates how to use loadXML() - * to retrieve data from an XML document and make - * objects from that data - * - * Here is what the XML looks like: - * - * - - 40 - - - - */ - -// An array of Bubble objects -Bubble[] bubbles; - -void setup() { - size(640, 360); - - // Load an XML document - XML xml = loadXML("bubbles.xml"); - - // Get all the child elements - XML[] children = xml.getChildren("bubble"); - - // Make an array of objects the same size - bubbles = new Bubble[children.length]; - - for (int i = 0; i < children.length; i++ ) { - - // The diameter is the content of the child named "Diamater" - XML diameterElement = children[i].getChild("diameter"); - int diameter = int(diameterElement.getContent()); - - // The color element has three attributes - XML colorElement = children[i].getChild("color"); - // An int for r g and b - int r = colorElement.getInt("red"); - int g = colorElement.getInt("green"); - int b = colorElement.getInt("blue"); - - // Make a new Bubble object with values from XML document - bubbles[i] = new Bubble(r, g, b, diameter); - } -} - - -void draw() { - background(255); - - // Display and move all bubbles - for (int i = 0; i < bubbles.length; i++ ) { - bubbles[i].display(); - bubbles[i].drift(); - } -} - diff --git a/java/examples/Topics/Advanced Data/LoadingXMLObjects/data/bubbles.xml b/java/examples/Topics/Advanced Data/LoadingXMLObjects/data/bubbles.xml deleted file mode 100644 index fc79fb9a7..000000000 --- a/java/examples/Topics/Advanced Data/LoadingXMLObjects/data/bubbles.xml +++ /dev/null @@ -1 +0,0 @@ - 40 20 80 \ No newline at end of file From 42d8064804ec68f03f5f73e2a4ccf31c8fdb7399 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Mon, 11 Mar 2013 13:21:10 -0400 Subject: [PATCH 19/25] XML example is finalized and now mirrors Table example --- .../Advanced Data/LoadSaveXML/LoadSaveXML.pde | 50 ++++++++++++------- .../Advanced Data/LoadSaveXML/data/data.xml | 24 ++++++++- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde index 238ddc3ed..27ef12fdd 100644 --- a/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/LoadSaveXML.pde @@ -57,7 +57,6 @@ void loadData() { for (int i = 0; i < bubbles.length; i++) { - // The position element has two attributes: x and y XML positionElement = children[i].getChild("position"); // Note how with attributes we can get an integer or float directly @@ -81,24 +80,39 @@ void loadData() { // Still need to work on adding and deleting -/*void mousePressed() { - // Create a new row - TableRow row = table.addRow(); - // Set the values of that row - row.setFloat("x", mouseX); - row.setFloat("y", mouseY); - row.setFloat("diameter", random(40, 80)); - row.setString("name", "Blah"); +void mousePressed() { - // If the table has more than 10 rows - if (table.getRowCount() > 10) { - // Delete the oldest row - table.removeRow(0); + // Create a new XML bubble element + XML bubble = xml.addChild("bubble"); + + // Set the poisition element + XML position = bubble.addChild("position"); + // Here we can set attributes as integers directly + position.setInt("x",mouseX); + position.setInt("y",mouseY); + + // Set the diameter element + XML diameter = bubble.addChild("diameter"); + // Here for a node's content, we have to convert to a String + diameter.setContent("" + random(40,80)); + + // Set a label + XML label = bubble.addChild("label"); + label.setContent("New label"); + + + // Here we are removing the oldest bubble if there are more than 10 + XML[] children = xml.getChildren("bubble"); + // If the XML file has more than 10 bubble elements + if (children.length > 10) { + // Delete the first one + xml.removeChild(children[0]); } - - // Writing the CSV back to the same file - saveTable(table,"data/data.csv"); - // And reloading it + + // Save a new XML file + saveXML(xml,"data/data.xml"); + + // reload the new data loadData(); -}*/ +} diff --git a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml index 807dd0ba4..24bbf2acf 100644 --- a/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml +++ b/java/examples/Topics/Advanced Data/LoadSaveXML/data/data.xml @@ -1 +1,23 @@ - 43.19838 52.42526 61.14072 44.758068 \ No newline at end of file + + + + + 43.19838 + + + + + 52.42526 + + + + + 61.14072 + + + + + 44.758068 + + + From f382ce6d1c02a732608f6a78778804fd40dc5620 Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Mon, 11 Mar 2013 13:33:43 -0400 Subject: [PATCH 20/25] trying a JSON example, but not getting very far yet --- .../Advanced Data/LoadSaveJSON/Bubble.pde | 40 ++++++ .../LoadSaveJSON/LoadSaveJSON.pde | 132 ++++++++++++++++++ .../Advanced Data/LoadSaveJSON/data/data.json | 38 +++++ 3 files changed, 210 insertions(+) create mode 100644 java/examples/Topics/Advanced Data/LoadSaveJSON/Bubble.pde create mode 100644 java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde create mode 100644 java/examples/Topics/Advanced Data/LoadSaveJSON/data/data.json diff --git a/java/examples/Topics/Advanced Data/LoadSaveJSON/Bubble.pde b/java/examples/Topics/Advanced Data/LoadSaveJSON/Bubble.pde new file mode 100644 index 000000000..3a7b9b7f9 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveJSON/Bubble.pde @@ -0,0 +1,40 @@ +// A Bubble class + +class Bubble { + float x,y; + float diameter; + String name; + + boolean over = false; + + // Create the Bubble + Bubble(float x_, float y_, float diameter_, String s) { + x = x_; + y = y_; + diameter = diameter_; + name = s; + } + + // CHecking if mouse is over the Bubble + void rollover(float px, float py) { + float d = dist(px,py,x,y); + if (d < diameter/2) { + over = true; + } else { + over = false; + } + } + + // Display the Bubble + void display() { + stroke(0); + strokeWeight(2); + noFill(); + ellipse(x,y,diameter,diameter); + if (over) { + fill(0); + textAlign(CENTER); + text(name,x,y+diameter/2+20); + } + } +} diff --git a/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde b/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde new file mode 100644 index 000000000..06f6e20d2 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveJSON/LoadSaveJSON.pde @@ -0,0 +1,132 @@ +/** + * Loading XML Data + * by Daniel Shiffman. + * + * This example demonstrates how to use loadJSON() + * to retrieve data from a JSON file and make objects + * from that data. + * + * Here is what the JSON looks like (partial): + * +{ + "bubbles": { + "bubble": [ + { + "position": { + "x": 160, + "y": 103 + }, + "diameter": 43.19838, + "label": "Happy" + }, + { + "position": { + "x": 121, + "y": 179 + }, + "diameter": 44.758068, + "label": "Melancholy" + } + ] + } +} + */ + +// An Array of Bubble objects +Bubble[] bubbles; +// A Table object +JSONArray json; + +void setup() { + size(640, 360); + loadData(); +} + +void draw() { + background(255); + // Display all bubbles +// for (Bubble b : bubbles) { +// b.display(); +// b.rollover(mouseX, mouseY); +// } +// +// textAlign(LEFT); +// fill(0); +// text("Click to add bubbles.", 10, height-10); +} + +void loadData() { + // Load JSON file + String jsonString = join(loadStrings("data.json"),"\n"); + //println(jsonString); + + json = JSONArray.parse(jsonString); + println(json); + + // Get all the child nodes named "bubble" +// XML[] children = xml.getChildren("bubble"); +// +// // The size of the array of Bubble objects is determined by the total XML elements named "bubble" +// bubbles = new Bubble[children.length]; +// +// for (int i = 0; i < bubbles.length; i++) { +// +// // The position element has two attributes: x and y +// XML positionElement = children[i].getChild("position"); +// // Note how with attributes we can get an integer or float directly +// float x = positionElement.getInt("x"); +// float y = positionElement.getInt("y"); +// +// // The diameter is the content of the child named "diamater" +// XML diameterElement = children[i].getChild("diameter"); +// // Note how with the content of an XML node, we retrieve as a String and then convert +// float diameter = float(diameterElement.getContent()); +// +// // The label is the content of the child named "label" +// XML labelElement = children[i].getChild("label"); +// String label = labelElement.getContent(); +// +// // Make a Bubble object out of the data read +// bubbles[i] = new Bubble(x, y, diameter, label); +// } + +} + +// Still need to work on adding and deleting + +void mousePressed() { + + // Create a new XML bubble element +// XML bubble = xml.addChild("bubble"); +// +// // Set the poisition element +// XML position = bubble.addChild("position"); +// // Here we can set attributes as integers directly +// position.setInt("x",mouseX); +// position.setInt("y",mouseY); +// +// // Set the diameter element +// XML diameter = bubble.addChild("diameter"); +// // Here for a node's content, we have to convert to a String +// diameter.setContent("" + random(40,80)); +// +// // Set a label +// XML label = bubble.addChild("label"); +// label.setContent("New label"); +// +// +// // Here we are removing the oldest bubble if there are more than 10 +// XML[] children = xml.getChildren("bubble"); +// // If the XML file has more than 10 bubble elements +// if (children.length > 10) { +// // Delete the first one +// xml.removeChild(children[0]); +// } +// +// // Save a new XML file +// saveXML(xml,"data/data.xml"); +// +// // reload the new data +// loadData(); +} + diff --git a/java/examples/Topics/Advanced Data/LoadSaveJSON/data/data.json b/java/examples/Topics/Advanced Data/LoadSaveJSON/data/data.json new file mode 100644 index 000000000..6e0449866 --- /dev/null +++ b/java/examples/Topics/Advanced Data/LoadSaveJSON/data/data.json @@ -0,0 +1,38 @@ +{ + "bubbles": { + "bubble": [ + { + "position": { + "x": 160, + "y": 103 + }, + "diameter": 43.19838, + "label": "Happy" + }, + { + "position": { + "x": 372, + "y": 137 + }, + "diameter": 52.42526, + "label": "Sad" + }, + { + "position": { + "x": 273, + "y": 235 + }, + "diameter": 61.14072, + "label": "Joyous" + }, + { + "position": { + "x": 121, + "y": 179 + }, + "diameter": 44.758068, + "label": "Melancholy" + } + ] + } +} \ No newline at end of file From e3ae88f1614f9f7b0fd52ffacd78881c4dbc9fcb Mon Sep 17 00:00:00 2001 From: Daniel Shiffman Date: Mon, 11 Mar 2013 13:57:58 -0400 Subject: [PATCH 21/25] IntHash works. Oh I am so happy. --- .../CountingStrings/CountingStrings.pde | 75 + .../Advanced Data/CountingStrings/Word.pde | 15 + .../CountingStrings/data/Georgia.ttf | Bin 0 -> 155068 bytes .../CountingStrings/data/dracula.txt | 16624 ++++++++++++++++ .../CountingStrings/data/hamlet.txt | 6771 +++++++ 5 files changed, 23485 insertions(+) create mode 100644 java/examples/Topics/Advanced Data/CountingStrings/CountingStrings.pde create mode 100644 java/examples/Topics/Advanced Data/CountingStrings/Word.pde create mode 100644 java/examples/Topics/Advanced Data/CountingStrings/data/Georgia.ttf create mode 100644 java/examples/Topics/Advanced Data/CountingStrings/data/dracula.txt create mode 100644 java/examples/Topics/Advanced Data/CountingStrings/data/hamlet.txt diff --git a/java/examples/Topics/Advanced Data/CountingStrings/CountingStrings.pde b/java/examples/Topics/Advanced Data/CountingStrings/CountingStrings.pde new file mode 100644 index 000000000..d8fadcff1 --- /dev/null +++ b/java/examples/Topics/Advanced Data/CountingStrings/CountingStrings.pde @@ -0,0 +1,75 @@ +/** + * CountingString example + * by Daniel Shiffman. + * + * This example demonstrates how to use a StringHash to store + * a number associated with a String. Java HashMaps can also + * be used for this, however, this example uses the simple StringHash + * class offered by Processing's data package. + + */ + +// The next line is needed if running in JavaScript Mode with Processing.js +/* @pjs font="Georgia.ttf"; */ + +IntHash concordance; // HashMap object +String[] tokens; +int counter = 0; + +void setup() { + size(640, 360); + + concordance = new IntHash(); + + // Load file and chop it up + String[] lines = loadStrings("dracula.txt"); + String allText = join(lines, " "); + tokens = splitTokens(allText, " ,.?!:;[]-"); + + // Create the font + textFont(createFont("Georgia", 24)); +} + +void draw() { + background(51); + fill(255); + + // Look at words one at a time + String s = tokens[counter]; + counter = (counter + 1) % tokens.length; + concordance.increment(s); + + // x and y will be used to locate each word + float x = 0; + float y = 100; + + concordance.sortValues(); + + String[] keys = concordance.keyArray(); + + // Look at each word + for (String word : keys) { + int count = concordance.get(word); + + // Only display words that appear 3 times + if (count > 3) { + // The size is the count + int fsize = constrain(count, 0, 100); + textSize(fsize); + text(word, x, y); + // Move along the x-axis + x += textWidth(word + " "); + } + + // If x gets to the end, move y + if (x > width) { + x = 0; + y += 100; + // If y gets to the end, we're done + if (y > height) { + break; + } + } + } +} + diff --git a/java/examples/Topics/Advanced Data/CountingStrings/Word.pde b/java/examples/Topics/Advanced Data/CountingStrings/Word.pde new file mode 100644 index 000000000..cc8568491 --- /dev/null +++ b/java/examples/Topics/Advanced Data/CountingStrings/Word.pde @@ -0,0 +1,15 @@ +class Word { + + int count; + String word; + + Word(String s) { + word = s; + count = 1; + } + + void count() { + count++; + } + +} diff --git a/java/examples/Topics/Advanced Data/CountingStrings/data/Georgia.ttf b/java/examples/Topics/Advanced Data/CountingStrings/data/Georgia.ttf new file mode 100644 index 0000000000000000000000000000000000000000..27d1c19515bb0566699a6ccad7fcf5bc9c203c94 GIT binary patch literal 155068 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