Skip to content

Instantly share code, notes, and snippets.

@codeanticode
Created January 25, 2018 20:37
Show Gist options
  • Save codeanticode/c6890ccaa66f98b929f3ff50958b7e9f to your computer and use it in GitHub Desktop.
Save codeanticode/c6890ccaa66f98b929f3ff50958b7e9f to your computer and use it in GitHub Desktop.
package test;
import java.util.ArrayList;
import com.jogamp.opengl.GL4;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphics;
import processing.core.PImage;
import processing.core.PVector;
import processing.opengl.PGraphics2D;
import processing.opengl.PJOGL;
///CONTROLS:
///0-9 to turn demos on and off
///QWE to change stroke join (for all demos)
///ASD to change stroke cap (for all demos)
///R+F to open/close stroke on demo 1
///T+G to turn matrix premultiplication on/off
///Z+X to change matrix scale for demo 1
///C+V to change stroke weight for demo 1
///SPACE to toggle wireframe (for all demos)
public final class Main extends PApplet {
public static final Main main = new Main();
@Override
public void settings() {
size(1280, 720, P2D);
pixelDensity(displayDensity());
smooth(4);
}
@Override
public void setup() {
//FIXME: framerate hovers at 54-58 fps while under light load (or no load)
//but hits 60 once we start drawing enough geometry, e.g. when running the benchmark.
//even more puzzling, it sticks at 60 for a few seconds after going back to light load
//before dropping back down to 54-58. this happens on both P2D, P3D, and P4D, but not JAVA2D
frameRate(60);
ballmer = loadImage("balmer_developers_poster.png");
montserrat = createFont("Montserrat-Bold.ttf", 72);
//setup for demo 2
for (int i = 0; i < c.length; ++i) {
c[i] = color(random(255), random(255), random(255));
}
}
PImage ballmer;
PFont montserrat;
float sc = 1;
float weight = 1;
boolean runDemo[] = new boolean[16];
@Override
public void draw() {
background(255);
fill(255, 0, 63, 127);
stroke(255, 0, 255, 127);
strokeWeight(12);
strokeJoin(ROUND);
noStroke();
if (keyPressed && key == 'z') {
sc /= 1.01;
} else if (keyPressed && key == 'x') {
sc *= 1.01;
} else if (keyPressed && key == 'c') {
weight /= 1.01;
} else if (keyPressed && key == 'v') {
weight *= 1.01;
}
scale(sc);
println();
println("FRAME #" + frameCount + " " + pixelWidth + ", " + pixelHeight);
println();
surface.setTitle((int)frameRate + " fps");
strokeCap(cap);
strokeJoin(join);
if (runDemo[ 5]) demo5();
if (runDemo[ 2]) demo2();
fill(255, 0, 255, 127);
if (runDemo[ 1]) demo1();
if (runDemo[10]) demo0();
if (runDemo[ 3]) demo3();
if (runDemo[ 4]) demo4();
translate(100, 200);
if (runDemo[ 3]) demo3();
if (runDemo[ 6]) demo6();
if (runDemo[ 7]) demo7();
translate(-100, -200);
if (runDemo[ 8]) demo8();
if (runDemo[ 9]) demo9();
if (runDemo[ 0]) demo10();
if (runDemo[11]) demo11();
if (runDemo[12]) demo12();
if (runDemo[13]) demo13();
if (runDemo[14]) demo14();
}
//useful for debugging
private boolean printDemo = false;
//manually setting pixels
private void demo0() {
if (printDemo) println("demo0");
int pink = color(255, 102, 204);
loadPixels();
for (int i = 0; i < (width*height/2)-width/2; i++) {
pixels[i] = pink;
}
updatePixels();
}
//basic self-intersecting polygon
private void demo1() {
if (printDemo) println("demo1");
strokeWeight(6 * weight);
stroke(0, 127, 95, 191);
beginShape();
vertex(100, 200);
vertex(200, 100);
vertex(300, 200);
vertex(400, 100);
vertex(350, 200);
vertex(450, 100);
vertex(300, 300);
vertex(mouseX, mouseY);
vertex(600, 200);
vertex(550, 100);
vertex(550, 400);
vertex(750, 400);
vertex(750, 600);
vertex(100, 600);
endShape(mode);
}
//data for demo 2
int[] c = new int[4096];
ArrayList<PVector> points = new ArrayList<PVector>();
//mouse controlled polygon
private void demo2() {
if (printDemo) println("demo2");
//NOTE: we draw each vertex with a random fill color to test how it behaves.
//in P2D, the colors are interpolated across the triangles output by the GLU tessellator.
//in JAVA2D, when endShape() is called, the currently active color is used for all vertices.
//for now P4D follows the behavior of P2D, but switching to JAVA2D's behavior
//would allow us to simplify our implementation a bit
beginShape();
for (int i = 0; i < points.size(); ++i) {
fill(c[i]);
vertex(points.get(i).x, points.get(i).y);
}
endShape();
}
//textured polygon
private void demo3() {
if (printDemo) println("demo3");
//test that textured shapes and tint() work correctly
float s = 4;
beginShape();
texture(ballmer);
vertex(10*s, 20*s, 0, 0);
tint(0, 255, 127, 127);
vertex(80*s, 5*s, 800, 0);
vertex(95*s, 90*s, 800, 800);
noTint();
vertex(40*s, 95*s, 0, 800);
endShape();
//test that image() function works correctly
tint(255, 31);
rotate(-1);
image(ballmer, -200, 100);
rotate(1);
tint(255);
image(ballmer, 700, 100, 200, 100);
}
//text rendering
private void demo4() {
if (printDemo) println("demo4");
textFont(montserrat);
text("Now is the time for all good men to come to the aid of their country.\n"
+ "If they do not the quick brown fox may never jump over the lazy sleeping dog again.\n"
+ "He may, however, take up knitting as a suitable hobby for all retired quick brown foxes.\n"
+ "This is test #1 of 9,876,543,210.\n"
+ "Collect them all!", 0, 100);
}
//shapes benchmark
private void demo5() {
if (printDemo) println("demo5");
strokeWeight(2 * weight);
stroke(0);
fill(200);
float dev = 10; //deviation
//change these parameters to benchmark various things
int unit = 100;
//line, triangle, rect, ellipse, point
int[] amount = { 20, 15, 10, 5, 40 };
// int[] amount = { 0, 0, 0, 10, 0 };
// int[] amount = { 0, 0, 0, 0, 0 };
for (int i = 0; i < amount[0]*unit; ++i) {
float x = random(width);
float y = random(height);
line(x, y, x + random(-dev, dev), y + random(-dev, dev));
}
for (int i = 0; i < amount[1]*unit; ++i) {
float x = random(width);
float y = random(height);
triangle(x, y,
x + random(-dev*2, dev*2), y + random(-dev*2, dev*2),
x + random(-dev*2, dev*2), y + random(-dev*2, dev*2));
}
for (int i = 0; i < amount[2]*unit; ++i) {
rect(random(width), random(height), random(dev), random(dev));
}
for (int i = 0; i < amount[3]*unit; ++i) {
ellipse(random(width), random(height), random(dev*2), random(dev*2));
}
for (int i = 0; i < amount[4]*unit; ++i) {
point(random(width), random(height));
}
//large ellipse to test smoothness of outline
ellipse(width/2, height/2, width/2, height/4);
ellipse(width/2, height/2, width/4, width/4);
strokeWeight(weight * 4);
stroke(0, 255, 0);
noFill();
beginShape();
float x = width/2;
float y = height/2;
float w = width/8;
float h = width/8;
vertex(x, y - h);
quadraticVertex(x + w, y - h, x + w, y);
quadraticVertex(x + w, y + h, x, y + h);
quadraticVertex(x - w, y + h, x - w, y);
quadraticVertex(x - w, y - h, x, y - h);
endShape();
}
//duplicate vertex test
private void demo6() {
if (printDemo) println("demo6");
//NOTE: yes, this produces the wrong result in P4D
//see PGraphics4D.shapeVertex() for why
beginShape();
vertex(500, 300);
vertex(600, 400); //dupe
vertex(700, 300);
vertex(650, 300);
vertex(600, 400); //dupe
vertex(550, 300);
endShape(CLOSE);
}
//user-define contours
private void demo7() {
if (printDemo) println("demo7");
//from https://processing.org/reference/beginContour_.html
fill(127, 255, 127);
stroke(255, 0, 0);
beginShape();
// Exterior part of shape, clockwise winding
vertex(-40, -40);
vertex(40, -40);
vertex(40, 40);
vertex(-40, 40);
// Interior part of shape, counter-clockwise winding
beginContour();
vertex(-20, -20);
vertex(-20, 20);
vertex(20, 20);
vertex(20, -20);
endContour();
endShape(CLOSE);
}
//primitive types
private void demo8() {
if (printDemo) println("demo8");
//from https://processing.org/reference/beginShape_.html
stroke(0);
strokeWeight(4);
fill(255, 127, 127);
pushMatrix();
resetMatrix();
scale(2);
beginShape();
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape(CLOSE);
translate(100, 0);
beginShape(POINTS);
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape();
translate(100, 0);
beginShape(LINES);
vertex(30, 40);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape();
translate(100, 0);
pushStyle();
noFill();
beginShape();
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape();
popStyle();
translate(100, 0);
pushStyle();
noFill();
beginShape();
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape(CLOSE);
popStyle();
translate(100, 0);
beginShape(TRIANGLES);
vertex(30, 75);
vertex(40, 20);
vertex(50, 75);
vertex(60, 20);
vertex(70, 75);
vertex(80, 20);
endShape();
resetMatrix();
scale(2);
translate(0, 100);
beginShape(TRIANGLE_STRIP);
vertex(30, 75);
vertex(40, 20);
vertex(50, 75);
vertex(60, 20);
vertex(70, 75);
vertex(80, 20);
vertex(90, 75);
endShape();
translate(100, 0);
beginShape(TRIANGLE_FAN);
vertex(57.5f, 50);
vertex(57.5f, 15);
vertex(92, 50);
vertex(57.5f, 85);
vertex(22, 50);
vertex(57.5f, 15);
endShape();
translate(100, 0);
beginShape(QUADS);
vertex(30, 20);
vertex(30, 75);
vertex(50, 75);
vertex(50, 20);
vertex(65, 20);
vertex(65, 75);
vertex(85, 75);
vertex(85, 20);
endShape();
translate(100, 0);
beginShape(QUAD_STRIP);
vertex(30, 20);
vertex(30, 75);
vertex(50, 20);
vertex(50, 75);
vertex(65, 20);
vertex(65, 75);
vertex(85, 20);
vertex(85, 75);
endShape();
translate(100, 0);
beginShape();
vertex(20, 20);
vertex(40, 20);
vertex(40, 40);
vertex(60, 40);
vertex(60, 60);
vertex(20, 60);
endShape(CLOSE);
//test handling of concave and self-intersecting quads
//NOTE: JAVA2D currently draws these correctly, but P2D does not
resetMatrix();
scale(2);
translate(0, 200);
strokeWeight(2);
float t = frameCount * 0.01f;
beginShape(QUADS);
vertex(50, 10);
vertex(90, 50);
vertex(30 + 20*sin(t), 70 + 20*cos(t));
vertex(30 - 20*sin(t), 70 - 20*cos(t));
endShape(CLOSE);
translate(100, 0);
beginShape(QUAD_STRIP);
vertex(50, 10);
vertex(90, 50);
vertex(30 + 20*sin(t), 70 + 20*cos(t));
vertex(30 - 20*sin(t), 70 - 20*cos(t));
endShape(CLOSE);
popMatrix();
}
//testing angular stuff
private void demo9() {
if (printDemo) println("demo9");
strokeWeight(4);
stroke(127, 0, 0);
fill(255, 255, 255);
//testing the behavior of floating point % operator (for dealing with angles)
float py = 0;
for (int i = 0; i < width; ++i) {
float x = (i - width/2) * 0.1f;
float y = height/2 - (x % PI) * 10;
line(i, y, i - 1, py);
py = y;
}
//testing the behavior of P2D arc() at various angles
//NOTE: arcs with negative angle aren't drawn
arc(100, 100, 100, 100, -1, new PVector(mouseX, mouseY).sub(100, 100).heading());
//test for whether LINES primitive type has self-overlap
//NOTE: it does in JAVA2D, but not in P2D
stroke(0, 127, 127, 127);
beginShape(LINES);
vertex(0, 0);
vertex(width, height + 100);
vertex(width, 0);
vertex(0, height + 100);
endShape();
}
//curve tests
private void demo10() {
if (printDemo) println("demo10");
noFill();
stroke(0);
strokeWeight(4);
pushMatrix();
scale(2);
beginShape();
curveVertex(84, 91);
curveVertex(84, 91);
curveVertex(68, 19);
curveVertex(21, 17);
curveVertex(32, 100);
curveVertex(32, 100);
endShape();
translate(100, 0);
beginShape();
vertex(30, 20);
bezierVertex(80, 0, 80, 75, 30, 75);
bezierVertex(50, 80, 60, 25, 30, 20);
endShape();
translate(100, 0);
beginShape();
vertex(20, 20);
quadraticVertex(80, 20, 50, 50);
quadraticVertex(20, 80, 80, 80);
vertex(80, 60);
endShape();
popMatrix();
}
//clip test
private void demo11() {
if (printDemo) println("demo11");
stroke(0);
if (mousePressed) {
clip(mouseX, mouseY, 100, 100);
}
line(0, 0, width, height);
line(0, height, width, 0);
ellipse(200, 200, 100, 200);
noClip();
}
//rounded rectangle test
private void demo12() {
if (printDemo) println("demo12");
stroke(0);
strokeWeight(weight * 2);
fill(200);
pushMatrix();
scale(2);
rect(30, 20, 55, 55);
translate(100, 0);
rect(30, 20, 55, 55, 7);
translate(100, 0);
rect(30, 20, 55, 55, 3, 6, 12, 18);
translate(100, 0);
rect(30, 20, 55, 55, 0, 6, 12, 180); //making sure we properly clamp too-large radius values
translate(100, 0);
rect(30, 20, 55, 55, 3, 6, 12, -18); //testing behavior of negative radius values
popMatrix();
}
//testing arcs
private void demo13() {
if (printDemo) println("demo13");
stroke(0);
strokeWeight(weight * 2);
fill(200);
pushMatrix();
scale(2);
arc(50, 55, 50, 50, 0, HALF_PI);
noFill();
arc(50, 55, 60, 60, HALF_PI, PI);
arc(50, 55, 70, 70, PI, PI+QUARTER_PI);
arc(50, 55, 80, 80, PI+QUARTER_PI, TWO_PI);
fill(200);
translate(100, 0);
arc(50, 50, 80, 80, 0, PI+QUARTER_PI, OPEN);
translate(100, 0);
arc(50, 50, 80, 80, 0, PI+QUARTER_PI, CHORD);
translate(100, 0);
arc(50, 50, 80, 80, 0, PI+QUARTER_PI, PIE);
translate(100, 0);
float t = (frameCount * 0.1f) % (TWO_PI * 2);
arc(50, 50, 80, 80, 0, t);
popMatrix();
float dx = mouseX - width/2;
float dy = mouseY - height/2;
float angle = atan2(dx, dy);
float begin = frameCount * 0.01f;
arc(width/2, height/2, 200, 300, begin, begin + PI - angle);
}
private void demo14() {
if (printDemo) println("demo14");
PGraphics tile = createGraphics(50, 50);
tile.beginDraw();
tile.noStroke();
for (int i = 0; i < 10; ++i) {
float x = random(20, tile.width - 20);
float y = random(20, tile.height - 20);
tile.fill(0, i * 20);
tile.ellipse(x, y, 10, 10);
}
tile.endDraw();
for (int y = 0; y < height; y += tile.height) {
for (int x = 0; x < width; x += tile.width) {
image(tile, x, y);
}
}
}
//behavior for demo 2
@Override
public void mousePressed() {
if (mouseButton == LEFT) {
points.add(new PVector(mouseX, mouseY));
}
}
@Override
public void mouseDragged() {
if (mouseButton == LEFT) {
points.get(points.size() - 1).x = mouseX;
points.get(points.size() - 1).y = mouseY;
}
}
boolean wireframe = false;
int join = MITER, cap = SQUARE, mode = OPEN;
boolean usingOldP2D = false;
@Override
public void keyPressed() {
if (key == ENTER || key == RETURN) {
if (usingOldP2D) {
((PGraphics2D)g).useNewP2D();
usingOldP2D = false;
} else {
((PGraphics2D)g).useOldP2D();
usingOldP2D = true;
}
} else if (key == 'q') {
join = MITER;
} else if (key == 'w') {
join = BEVEL;
} else if (key == 'e') {
join = ROUND;
} else if (key == 'a') {
cap = SQUARE;
} else if (key == 's') {
cap = PROJECT;
} else if (key == 'd') {
cap = ROUND;
} else if (key == 'r') {
mode = OPEN;
} else if (key == 'f') {
mode = CLOSE;
} else if (key == 't') {
PGraphics2D.premultiplyMatrices = true;
} else if (key == 'g') {
PGraphics2D.premultiplyMatrices = false;
} else if (key == ' ') {
PJOGL pgl = (PJOGL)((PGraphics2D)this.g).pgl;
if (wireframe)
pgl.gl.getGL4().glPolygonMode(GL4.GL_FRONT_AND_BACK, GL4.GL_FILL);
else
pgl.gl.getGL4().glPolygonMode(GL4.GL_FRONT_AND_BACK, GL4.GL_LINE);
wireframe = !wireframe;
} else if (key - '0' >= 0 && key - '0' < 10) {
runDemo[key - '0'] = !runDemo[key - '0'];
} else if (key == '`') {
runDemo[10] = !runDemo[10];
} else if (key == '-') {
runDemo[11] = !runDemo[11];
} else if (key == '=') {
runDemo[12] = !runDemo[12];
} else if (key == '[') {
runDemo[13] = !runDemo[13];
} else if (key == ']') {
runDemo[14] = !runDemo[14];
}
}
public static void main(String[] args) {
PApplet.runSketch(new String[] { Main.class.getName() }, main);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment