Created
January 25, 2018 20:37
-
-
Save codeanticode/c6890ccaa66f98b929f3ff50958b7e9f to your computer and use it in GitHub Desktop.
A test for the new P2D renderer in https://github.com/processing/processing/tree/super-fast-P2D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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