diff --git a/.idea/modules.xml b/.idea/modules.xml
index ab31269e4..c60fa0002 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -15,7 +15,6 @@
-
\ No newline at end of file
diff --git a/java/libraries/javafx/.classpath b/java/libraries/javafx/.classpath
deleted file mode 100644
index cfc5fc9ac..000000000
--- a/java/libraries/javafx/.classpath
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/libraries/javafx/.gitignore b/java/libraries/javafx/.gitignore
deleted file mode 100644
index 4d04bf96b..000000000
--- a/java/libraries/javafx/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# ignore the sdk download files
-javafx-*.zip
-
-# everything is downloaded from online
-/library
diff --git a/java/libraries/javafx/.project b/java/libraries/javafx/.project
deleted file mode 100644
index 7dbb5da11..000000000
--- a/java/libraries/javafx/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- processing4-javafx
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
-
-
diff --git a/java/libraries/javafx/.settings/org.eclipse.jdt.core.prefs b/java/libraries/javafx/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index cd8d089a1..000000000
--- a/java/libraries/javafx/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,15 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=11
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
-org.eclipse.jdt.core.compiler.release=disabled
-org.eclipse.jdt.core.compiler.source=11
diff --git a/java/libraries/javafx/build.xml b/java/libraries/javafx/build.xml
deleted file mode 100644
index b6a9b6882..000000000
--- a/java/libraries/javafx/build.xml
+++ /dev/null
@@ -1,181 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/libraries/javafx/library.properties b/java/libraries/javafx/library.properties
deleted file mode 100644
index 00d042f25..000000000
--- a/java/libraries/javafx/library.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-name = JavaFX
-version = 1
diff --git a/java/libraries/javafx/processing4-javafx.iml b/java/libraries/javafx/processing4-javafx.iml
deleted file mode 100644
index e169dfb69..000000000
--- a/java/libraries/javafx/processing4-javafx.iml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/java/libraries/javafx/src/processing/javafx/PGraphicsFX2D.java b/java/libraries/javafx/src/processing/javafx/PGraphicsFX2D.java
deleted file mode 100644
index 4e73a1709..000000000
--- a/java/libraries/javafx/src/processing/javafx/PGraphicsFX2D.java
+++ /dev/null
@@ -1,2330 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2015 The Processing Foundation
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, version 2.1.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-*/
-
-package processing.javafx;
-
-import com.sun.javafx.geom.Path2D;
-import com.sun.javafx.geom.PathIterator;
-import com.sun.javafx.geom.Shape;
-
-import java.nio.IntBuffer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javafx.scene.SnapshotParameters;
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.effect.BlendMode;
-import javafx.scene.image.PixelFormat;
-import javafx.scene.image.PixelReader;
-import javafx.scene.image.PixelWriter;
-import javafx.scene.image.WritableImage;
-import javafx.scene.image.WritablePixelFormat;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.ArcType;
-import javafx.scene.shape.StrokeLineCap;
-import javafx.scene.shape.StrokeLineJoin;
-import javafx.scene.text.Font;
-import javafx.scene.text.Text;
-import javafx.scene.transform.Affine;
-import javafx.scene.transform.Transform;
-
-import processing.core.*;
-
-
-public class PGraphicsFX2D extends PGraphics {
- GraphicsContext context;
-
- static final WritablePixelFormat argbFormat =
- PixelFormat.getIntArgbInstance();
-
- WritableImage snapshotImage;
-
- Path2D workPath = new Path2D();
- Path2D auxPath = new Path2D();
- boolean openContour;
- boolean adjustedForThinLines;
- /// break the shape at the next vertex (next vertex() call is a moveto())
- boolean breakShape;
-
- private float[] pathCoordsBuffer = new float[6];
-
- /// coordinates for internal curve calculation
- float[] curveCoordX;
- float[] curveCoordY;
- float[] curveDrawX;
- float[] curveDrawY;
-
- int transformCount;
- Affine[] transformStack = new Affine[MATRIX_STACK_DEPTH];
-
-// Line2D.Float line = new Line2D.Float();
-// Ellipse2D.Float ellipse = new Ellipse2D.Float();
-// Rectangle2D.Float rect = new Rectangle2D.Float();
-// Arc2D.Float arc = new Arc2D.Float();
-//
-// protected Color tintColorObject;
-//
-// protected Color fillColorObject;
-// public boolean fillGradient;
-// public Paint fillGradientObject;
-//
-// protected Color strokeColorObject;
-// public boolean strokeGradient;
-// public Paint strokeGradientObject;
-
-
-
- //////////////////////////////////////////////////////////////
-
- // INTERNAL
-
-
- public PGraphicsFX2D() { }
-
-
- //public void setParent(PApplet parent)
-
-
- //public void setPrimary(boolean primary)
-
-
- //public void setPath(String path)
-
-
- //public void setSize(int width, int height)
-
-
- //public void dispose()
-
-
- @Override
- public PSurface createSurface() {
- return surface = new PSurfaceFX(this);
- }
-
-
- /** Returns the javafx.scene.canvas.GraphicsContext used by this renderer. */
- @Override
- public Object getNative() {
- return context;
- }
-
-
- //////////////////////////////////////////////////////////////
-
- // FRAME
-
-
-// @Override
-// public boolean canDraw() {
-// return true;
-// }
-
-
- @Override
- public void beginDraw() {
- checkSettings();
- resetMatrix(); // reset model matrix
- vertexCount = 0;
- }
-
-
- @Override
- public void endDraw() {
- flush();
-
- if (!primaryGraphics) {
- // TODO this is probably overkill for most tasks...
- loadPixels();
- }
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SETTINGS
-
-
- //protected void checkSettings()
-
-
- //protected void defaultSettings()
-
-
- //protected void reapplySettings()
-
-
-
- //////////////////////////////////////////////////////////////
-
- // HINT
-
-
- //public void hint(int which)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SHAPE CREATION
-
-
- //protected PShape createShapeFamily(int type)
-
-
- //protected PShape createShapePrimitive(int kind, float... p)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SHAPE
-
-
- @Override
- public void beginShape(int kind) {
- shape = kind;
- vertexCount = 0;
- curveVertexCount = 0;
-
- workPath.reset();
- auxPath.reset();
-
- flushPixels();
-
- if (drawingThinLines()) {
- adjustedForThinLines = true;
- translate(0.5f, 0.5f);
- }
- }
-
-
- //public boolean edge(boolean e)
-
-
- //public void normal(float nx, float ny, float nz) {
-
-
- //public void textureMode(int mode)
-
-
- @Override
- public void texture(PImage image) {
- showMethodWarning("texture");
- }
-
-
- @Override
- public void vertex(float x, float y) {
- if (vertexCount == vertices.length) {
- float[][] temp = new float[vertexCount<<1][VERTEX_FIELD_COUNT];
- System.arraycopy(vertices, 0, temp, 0, vertexCount);
- vertices = temp;
- //message(CHATTER, "allocating more vertices " + vertices.length);
- }
- // not everyone needs this, but just easier to store rather
- // than adding another moving part to the code...
- vertices[vertexCount][X] = x;
- vertices[vertexCount][Y] = y;
- vertexCount++;
-
- switch (shape) {
-
- case POINTS:
- point(x, y);
- break;
-
- case LINES:
- if ((vertexCount % 2) == 0) {
- line(vertices[vertexCount-2][X],
- vertices[vertexCount-2][Y], x, y);
- }
- break;
-
- case TRIANGLES:
- if ((vertexCount % 3) == 0) {
- triangle(vertices[vertexCount - 3][X],
- vertices[vertexCount - 3][Y],
- vertices[vertexCount - 2][X],
- vertices[vertexCount - 2][Y],
- x, y);
- }
- break;
-
- case TRIANGLE_STRIP:
- if (vertexCount >= 3) {
- triangle(vertices[vertexCount - 2][X],
- vertices[vertexCount - 2][Y],
- vertices[vertexCount - 1][X],
- vertices[vertexCount - 1][Y],
- vertices[vertexCount - 3][X],
- vertices[vertexCount - 3][Y]);
- }
- break;
-
- case TRIANGLE_FAN:
- if (vertexCount >= 3) {
- // This is an unfortunate implementation because the stroke for an
- // adjacent triangle will be repeated. However, if the stroke is not
- // redrawn, it will replace the adjacent line (when it lines up
- // perfectly) or show a faint line (when off by a small amount).
- // The alternative would be to wait, then draw the shape as a
- // polygon fill, followed by a series of vertices. But that's a
- // poor method when used with PDF, DXF, or other recording objects,
- // since discrete triangles would likely be preferred.
- triangle(vertices[0][X],
- vertices[0][Y],
- vertices[vertexCount - 2][X],
- vertices[vertexCount - 2][Y],
- x, y);
- }
- break;
-
- case QUAD:
- case QUADS:
- if ((vertexCount % 4) == 0) {
- quad(vertices[vertexCount - 4][X],
- vertices[vertexCount - 4][Y],
- vertices[vertexCount - 3][X],
- vertices[vertexCount - 3][Y],
- vertices[vertexCount - 2][X],
- vertices[vertexCount - 2][Y],
- x, y);
- }
- break;
-
- case QUAD_STRIP:
- // 0---2---4
- // | | |
- // 1---3---5
- if ((vertexCount >= 4) && ((vertexCount % 2) == 0)) {
- quad(vertices[vertexCount - 4][X],
- vertices[vertexCount - 4][Y],
- vertices[vertexCount - 2][X],
- vertices[vertexCount - 2][Y],
- x, y,
- vertices[vertexCount - 3][X],
- vertices[vertexCount - 3][Y]);
- }
- break;
-
- case POLYGON:
- if (workPath.getNumCommands() == 0 || breakShape) {
- workPath.moveTo(x, y);
- breakShape = false;
- } else {
- workPath.lineTo(x, y);
- }
- break;
- }
- }
-
-
- @Override
- public void vertex(float x, float y, float z) {
- showDepthWarningXYZ("vertex");
- }
-
-
- @Override
- public void vertex(float[] v) {
- vertex(v[X], v[Y]);
- }
-
-
- @Override
- public void vertex(float x, float y, float u, float v) {
- showVariationWarning("vertex(x, y, u, v)");
- }
-
-
- @Override
- public void vertex(float x, float y, float z, float u, float v) {
- showDepthWarningXYZ("vertex");
- }
-
-
- @Override
- public void beginContour() {
- if (openContour) {
- PGraphics.showWarning("Already called beginContour()");
- return;
- }
-
- // draw contours to auxiliary path so main path can be closed later
- Path2D contourPath = auxPath;
- auxPath = workPath;
- workPath = contourPath;
-
- if (contourPath.getNumCommands() > 0) { // first contour does not break
- breakShape = true;
- }
-
- openContour = true;
- }
-
-
- @Override
- public void endContour() {
- if (!openContour) {
- PGraphics.showWarning("Need to call beginContour() first");
- return;
- }
-
- if (workPath.getNumCommands() > 0) workPath.closePath();
-
- Path2D temp = workPath;
- workPath = auxPath;
- auxPath = temp;
-
- openContour = false;
- }
-
-
- @Override
- public void endShape(int mode) {
- if (openContour) { // correct automagically, notify user
- endContour();
- PGraphics.showWarning("Missing endContour() before endShape()");
- }
- if (workPath.getNumCommands() > 0) {
- if (shape == POLYGON) {
- if (mode == CLOSE) {
- workPath.closePath();
- }
- if (auxPath.getNumCommands() > 0) {
- workPath.append(auxPath, false);
- }
- drawShape(workPath);
- }
- }
- shape = 0;
- if (adjustedForThinLines) {
- adjustedForThinLines = false;
- translate(-0.5f, -0.5f);
- }
- loaded = false;
- }
-
-
- private void drawShape(Shape s) {
- context.beginPath();
- PathIterator pi = s.getPathIterator(null);
- while (!pi.isDone()) {
- int piType = pi.currentSegment(pathCoordsBuffer);
- switch (piType) {
- case PathIterator.SEG_MOVETO:
- context.moveTo(pathCoordsBuffer[0], pathCoordsBuffer[1]);
- break;
- case PathIterator.SEG_LINETO:
- context.lineTo(pathCoordsBuffer[0], pathCoordsBuffer[1]);
- break;
- case PathIterator.SEG_QUADTO:
- context.quadraticCurveTo(pathCoordsBuffer[0], pathCoordsBuffer[1],
- pathCoordsBuffer[2], pathCoordsBuffer[3]);
- break;
- case PathIterator.SEG_CUBICTO:
- context.bezierCurveTo(pathCoordsBuffer[0], pathCoordsBuffer[1],
- pathCoordsBuffer[2], pathCoordsBuffer[3],
- pathCoordsBuffer[4], pathCoordsBuffer[5]);
- break;
- case PathIterator.SEG_CLOSE:
- context.closePath();
- break;
- default:
- showWarning("Unknown segment type " + piType);
- }
- pi.next();
- }
- if (fill) context.fill();
- if (stroke) context.stroke();
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // CLIPPING
-
-
- @Override
- protected void clipImpl(float x1, float y1, float x2, float y2) {
- //g2.setClip(new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1));
- showTodoWarning("clip()", 3274);
- }
-
-
- @Override
- public void noClip() {
- //g2.setClip(null);
- showTodoWarning("noClip()", 3274);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BLEND
-
-
- @Override
- protected void blendModeImpl() {
- BlendMode mode = BlendMode.SRC_OVER;
- switch (blendMode) {
- case REPLACE: showWarning("blendMode(REPLACE) is not supported"); break;
- case BLEND: break; // this is SRC_OVER, the default
- case ADD: mode = BlendMode.ADD; break; // everyone's favorite
- case SUBTRACT: showWarning("blendMode(SUBTRACT) is not supported"); break;
- case LIGHTEST: mode = BlendMode.LIGHTEN; break;
- case DARKEST: mode = BlendMode.DARKEN; break;
- case DIFFERENCE: mode = BlendMode.DIFFERENCE; break;
- case EXCLUSION: mode = BlendMode.EXCLUSION; break;
- case MULTIPLY: mode = BlendMode.MULTIPLY; break;
- case SCREEN: mode = BlendMode.SCREEN; break;
- case OVERLAY: mode = BlendMode.OVERLAY; break;
- case HARD_LIGHT: mode = BlendMode.HARD_LIGHT; break;
- case SOFT_LIGHT: mode = BlendMode.SOFT_LIGHT; break;
- case DODGE: mode = BlendMode.COLOR_DODGE; break;
- case BURN: mode = BlendMode.COLOR_BURN; break;
- }
- context.setGlobalBlendMode(mode);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BEZIER VERTICES
-
-
- @Override
- protected void bezierVertexCheck() {
- if (shape == 0 || shape != POLYGON) {
- throw new RuntimeException("beginShape() or beginShape(POLYGON) " +
- "must be used before bezierVertex() or quadraticVertex()");
- }
- if (workPath.getNumCommands() == 0) {
- throw new RuntimeException("vertex() must be used at least once " +
- "before bezierVertex() or quadraticVertex()");
- }
- }
-
- @Override
- public void bezierVertex(float x1, float y1,
- float x2, float y2,
- float x3, float y3) {
- bezierVertexCheck();
- workPath.curveTo(x1, y1, x2, y2, x3, y3);
- }
-
-
- @Override
- public void bezierVertex(float x2, float y2, float z2,
- float x3, float y3, float z3,
- float x4, float y4, float z4) {
- showDepthWarningXYZ("bezierVertex");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // QUADRATIC BEZIER VERTICES
-
-
- @Override
- public void quadraticVertex(float ctrlX, float ctrlY,
- float endX, float endY) {
- bezierVertexCheck();
- workPath.quadTo(ctrlX, ctrlY, endX, endY);
- }
-
-
- @Override
- public void quadraticVertex(float x2, float y2, float z2,
- float x4, float y4, float z4) {
- showDepthWarningXYZ("quadVertex");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // CURVE VERTICES
-
-
- @Override
- protected void curveVertexSegment(float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- float x4, float y4) {
- if (curveCoordX == null) {
- curveCoordX = new float[4];
- curveCoordY = new float[4];
- curveDrawX = new float[4];
- curveDrawY = new float[4];
- }
-
- curveCoordX[0] = x1;
- curveCoordY[0] = y1;
-
- curveCoordX[1] = x2;
- curveCoordY[1] = y2;
-
- curveCoordX[2] = x3;
- curveCoordY[2] = y3;
-
- curveCoordX[3] = x4;
- curveCoordY[3] = y4;
-
- curveToBezierMatrix.mult(curveCoordX, curveDrawX);
- curveToBezierMatrix.mult(curveCoordY, curveDrawY);
-
- // since the paths are continuous,
- // only the first point needs the actual moveto
- if (workPath.getNumCommands() == 0) {
- workPath.moveTo(curveDrawX[0], curveDrawY[0]);
- breakShape = false;
- }
-
- workPath.curveTo(curveDrawX[1], curveDrawY[1],
- curveDrawX[2], curveDrawY[2],
- curveDrawX[3], curveDrawY[3]);
- }
-
-
- @Override
- public void curveVertex(float x, float y, float z) {
- showDepthWarningXYZ("curveVertex");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // RENDERER
-
- @Override
- public void flush() {
- flushPixels();
- }
-
-
- protected void flushPixels() {
- boolean hasPixels = modified && pixels != null;
- if (hasPixels) {
- // If the user has been manipulating individual pixels,
- // the changes need to be copied to the screen before
- // drawing any new geometry.
- int mx1 = getModifiedX1();
- int mx2 = getModifiedX2();
- int my1 = getModifiedY1();
- int my2 = getModifiedY2();
- int mw = mx2 - mx1;
- int mh = my2 - my1;
-
- if (pixelDensity == 1) {
- PixelWriter pw = context.getPixelWriter();
- pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels,
- mx1 + my1 * pixelWidth, pixelWidth);
- } else {
- // The only way to push all the pixels is to draw a scaled-down image
- if (snapshotImage == null ||
- snapshotImage.getWidth() != pixelWidth ||
- snapshotImage.getHeight() != pixelHeight) {
- snapshotImage = new WritableImage(pixelWidth, pixelHeight);
- }
-
- PixelWriter pw = snapshotImage.getPixelWriter();
- pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels,
- mx1 + my1 * pixelWidth, pixelWidth);
- context.save();
- resetMatrix();
- context.scale(1d / pixelDensity, 1d / pixelDensity);
- context.drawImage(snapshotImage, mx1, my1, mw, mh, mx1, my1, mw, mh);
- context.restore();
- }
- }
-
- modified = false;
- }
-
-
- protected void beforeContextDraw() {
- flushPixels();
- loaded = false;
- }
-
-
- //////////////////////////////////////////////////////////////
-
- // POINT, LINE, TRIANGLE, QUAD
-
-
- @Override
- public void point(float x, float y) {
- if (stroke) {
-// if (strokeWeight > 1) {
- line(x, y, x + EPSILON, y + EPSILON);
-// } else {
-// set((int) screenX(x, y), (int) screenY(x, y), strokeColor);
-// }
- }
- }
-
-
- @Override
- public void line(float x1, float y1, float x2, float y2) {
- beforeContextDraw();
- if (drawingThinLines()) {
- x1 += 0.5f;
- x2 += 0.5f;
- y1 += 0.5f;
- y2 += 0.5f;
- }
- context.strokeLine(x1, y1, x2, y2);
- }
-
-
- @Override
- public void triangle(float x1, float y1, float x2, float y2,
- float x3, float y3) {
- beforeContextDraw();
- if (drawingThinLines()) {
- x1 += 0.5f;
- x2 += 0.5f;
- x3 += 0.5f;
- y1 += 0.5f;
- y2 += 0.5f;
- y3 += 0.5f;
- }
- context.beginPath();
- context.moveTo(x1, y1);
- context.lineTo(x2, y2);
- context.lineTo(x3, y3);
- context.closePath();
- if (fill) context.fill();
- if (stroke) context.stroke();
- }
-
-
- @Override
- public void quad(float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4) {
- beforeContextDraw();
- if (drawingThinLines()) {
- x1 += 0.5f;
- x2 += 0.5f;
- x3 += 0.5f;
- x4 += 0.5f;
- y1 += 0.5f;
- y2 += 0.5f;
- y3 += 0.5f;
- y4 += 0.5f;
- }
- context.beginPath();
- context.moveTo(x1, y1);
- context.lineTo(x2, y2);
- context.lineTo(x3, y3);
- context.lineTo(x4, y4);
- context.closePath();
- if (fill) context.fill();
- if (stroke) context.stroke();
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // RECT
-
-
- //public void rectMode(int mode)
-
-
- //public void rect(float a, float b, float c, float d)
-
-
- @Override
- protected void rectImpl(float x1, float y1, float x2, float y2) {
- beforeContextDraw();
- if (drawingThinLines()) {
- x1 += 0.5f;
- x2 += 0.5f;
- y1 += 0.5f;
- y2 += 0.5f;
- }
- if (fill) context.fillRect(x1, y1, x2 - x1, y2 - y1);
- if (stroke) context.strokeRect(x1, y1, x2 - x1, y2 - y1);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // ELLIPSE
-
-
- //public void ellipseMode(int mode)
-
-
- //public void ellipse(float a, float b, float c, float d)
-
-
- @Override
- protected void ellipseImpl(float x, float y, float w, float h) {
- beforeContextDraw();
- if (drawingThinLines()) {
- x += 0.5f;
- y += 0.5f;
- }
- if (fill) context.fillOval(x, y, w, h);
- if (stroke) context.strokeOval(x, y, w, h);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // ARC
-
-
- //public void arc(float a, float b, float c, float d,
- // float start, float stop)
-
-
- @Override
- protected void arcImpl(float x, float y, float w, float h,
- float start, float stop, int mode) {
- beforeContextDraw();
-
- if (drawingThinLines()) {
- x += 0.5f;
- y += 0.5f;
- }
-
- // 0 to 90 in java would be 0 to -90 for p5 renderer
- // but that won't work, so -90 to 0?
- start = -start;
- stop = -stop;
-
- float sweep = stop - start;
-
- // The defaults, before 2.0b7, were to stroke as Arc2D.OPEN, and then fill
- // using Arc2D.PIE. That's a little wonky, but it's here for compatibility.
- ArcType fillMode = ArcType.ROUND; // Arc2D.PIE
- ArcType strokeMode = ArcType.OPEN;
-
- if (mode == OPEN) {
- fillMode = ArcType.OPEN;
-
- } else if (mode == PIE) {
- strokeMode = ArcType.ROUND; // PIE
-
- } else if (mode == CHORD) {
- fillMode = ArcType.CHORD;
- strokeMode = ArcType.CHORD;
- }
-
- if (fill) {
- context.fillArc(x, y, w, h, PApplet.degrees(start), PApplet.degrees(sweep), fillMode);
- }
- if (stroke) {
- context.strokeArc(x, y, w, h, PApplet.degrees(start), PApplet.degrees(sweep), strokeMode);
- }
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BOX
-
-
- //public void box(float size)
-
-
- @Override
- public void box(float w, float h, float d) {
- showMethodWarning("box");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SPHERE
-
-
- //public void sphereDetail(int res)
-
-
- //public void sphereDetail(int ures, int vres)
-
-
- @Override
- public void sphere(float r) {
- showMethodWarning("sphere");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BEZIER
-
-
- //public float bezierPoint(float a, float b, float c, float d, float t)
-
-
- //public float bezierTangent(float a, float b, float c, float d, float t)
-
-
- //protected void bezierInitCheck()
-
-
- //protected void bezierInit()
-
-
- /** Ignored (not needed) by this renderer. */
- @Override
- public void bezierDetail(int detail) { }
-
-
- //public void bezier(float x1, float y1,
- // float x2, float y2,
- // float x3, float y3,
- // float x4, float y4)
-
-
- //public void bezier(float x1, float y1, float z1,
- // float x2, float y2, float z2,
- // float x3, float y3, float z3,
- // float x4, float y4, float z4)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // CURVE
-
-
- //public float curvePoint(float a, float b, float c, float d, float t)
-
-
- //public float curveTangent(float a, float b, float c, float d, float t)
-
-
- /** Ignored (not needed) by this renderer. */
- @Override
- public void curveDetail(int detail) { }
-
-
- //public void curveTightness(float tightness)
-
-
- //protected void curveInitCheck()
-
-
- //protected void curveInit()
-
-
- //public void curve(float x1, float y1,
- // float x2, float y2,
- // float x3, float y3,
- // float x4, float y4)
-
-
- //public void curve(float x1, float y1, float z1,
- // float x2, float y2, float z2,
- // float x3, float y3, float z3,
- // float x4, float y4, float z4)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SMOOTH
-
-
-// @Override
-// public void smooth() {
-// smooth = true;
-//
-// if (quality == 0) {
-// quality = 4; // change back to bicubic
-// }
-// }
-
-
-// @Override
-// public void smooth(int quality) {
-//// this.quality = quality;
-//// if (quality == 0) {
-//// noSmooth();
-//// } else {
-//// smooth();
-//// }
-// showMissingWarning("smooth");
-// }
-//
-//
-// @Override
-// public void noSmooth() {
-// showMissingWarning("noSmooth");
-// }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // IMAGE
-
-
- //public void imageMode(int mode)
-
-
- //public void image(PImage image, float x, float y)
-
-
- //public void image(PImage image, float x, float y, float c, float d)
-
-
- //public void image(PImage image,
- // float a, float b, float c, float d,
- // int u1, int v1, int u2, int v2)
-
-
- /**
- * Handle renderer-specific image drawing.
- */
- @Override
- protected void imageImpl(PImage who,
- float x1, float y1, float x2, float y2,
- int u1, int v1, int u2, int v2) {
- // Image not ready yet, or an error
- if (who.width <= 0 || who.height <= 0) return;
-
- ImageCache cash = (ImageCache) getCache(who);
-
- // Nuke the cache if the image was resized
- if (cash != null) {
- if (who.pixelWidth != cash.image.getWidth() ||
- who.pixelHeight != cash.image.getHeight()) {
- cash = null;
- }
- }
-
- if (cash == null) {
- //System.out.println("making new image cache");
- cash = new ImageCache(); //who);
- setCache(who, cash);
- who.updatePixels(); // mark the whole thing for update
- who.setModified();
- }
-
- // If image previously was tinted, or the color changed
- // or the image was tinted, and tint is now disabled
- if ((tint && !cash.tinted) ||
- (tint && (cash.tintedColor != tintColor)) ||
- (!tint && cash.tinted)) {
- // For tint change, mark all pixels as needing update.
- who.updatePixels();
- }
-
- if (who.isModified()) {
- if (who.pixels == null) {
- // This might be a PGraphics that hasn't been drawn to yet.
- // Can't just bail because the cache has been created above.
- // https://github.com/processing/processing/issues/2208
- who.pixels = new int[who.pixelWidth * who.pixelHeight];
- }
- cash.update(who, tint, tintColor);
- who.setModified(false);
- }
-
- u1 *= who.pixelDensity;
- v1 *= who.pixelDensity;
- u2 *= who.pixelDensity;
- v2 *= who.pixelDensity;
-
- context.drawImage(((ImageCache) getCache(who)).image,
- u1, v1, u2-u1, v2-v1,
- x1, y1, x2-x1, y2-y1);
- }
-
-
- static class ImageCache {
- boolean tinted;
- int tintedColor;
- int[] tintedTemp; // one row of tinted pixels
- //BufferedImage image;
- WritableImage image;
-
- /**
- * Update the pixels of the cache image. Already determined that the tint
- * has changed, or the pixels have changed, so should just go through
- * with the update without further checks.
- */
- public void update(PImage source, boolean tint, int tintColor) {
- //int bufferType = BufferedImage.TYPE_INT_ARGB;
- int targetType = ARGB;
- boolean opaque = (tintColor & 0xFF000000) == 0xFF000000;
- if (source.format == RGB) {
- if (!tint || opaque) {
- //bufferType = BufferedImage.TYPE_INT_RGB;
- targetType = RGB;
- }
- }
-// boolean wrongType = (image != null) && (image.getType() != bufferType);
-// if ((image == null) || wrongType) {
-// image = new BufferedImage(source.width, source.height, bufferType);
-// }
- // Must always use an ARGB image, otherwise will write zeros
- // in the alpha channel when drawn to the screen.
- // https://github.com/processing/processing/issues/2030
-// if (image == null) {
-// image = new BufferedImage(source.width, source.height,
-// BufferedImage.TYPE_INT_ARGB);
-// }
- if (image == null) {
- image = new WritableImage(source.pixelWidth, source.pixelHeight);
- }
-
- //WritableRaster wr = image.getRaster();
- PixelWriter pw = image.getPixelWriter();
- if (tint) {
- if (tintedTemp == null || tintedTemp.length != source.pixelWidth) {
- tintedTemp = new int[source.pixelWidth];
- }
- int a2 = (tintColor >> 24) & 0xff;
-// System.out.println("tint color is " + a2);
-// System.out.println("source.pixels[0] alpha is " + (source.pixels[0] >>> 24));
- int r2 = (tintColor >> 16) & 0xff;
- int g2 = (tintColor >> 8) & 0xff;
- int b2 = (tintColor) & 0xff;
-
- //if (bufferType == BufferedImage.TYPE_INT_RGB) {
- if (targetType == RGB) {
- // The target image is opaque, meaning that the source image has no
- // alpha (is not ARGB), and the tint has no alpha.
- int index = 0;
- for (int y = 0; y < source.pixelHeight; y++) {
- for (int x = 0; x < source.pixelWidth; x++) {
- int argb1 = source.pixels[index++];
- int r1 = (argb1 >> 16) & 0xff;
- int g1 = (argb1 >> 8) & 0xff;
- int b1 = (argb1) & 0xff;
-
- // Prior to 2.1, the alpha channel was commented out here,
- // but can't remember why (just thought unnecessary b/c of RGB?)
- // https://github.com/processing/processing/issues/2030
- tintedTemp[x] = 0xFF000000 |
- (((r2 * r1) & 0xff00) << 8) |
- ((g2 * g1) & 0xff00) |
- (((b2 * b1) & 0xff00) >> 8);
- }
- //wr.setDataElements(0, y, source.width, 1, tintedTemp);
- pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth);
- }
- // could this be any slower?
-// float[] scales = { tintR, tintG, tintB };
-// float[] offsets = new float[3];
-// RescaleOp op = new RescaleOp(scales, offsets, null);
-// op.filter(image, image);
-
- } else { // targetType == ARGB
- if (source.format == RGB &&
- (tintColor & 0xffffff) == 0xffffff) {
- int hi = tintColor & 0xff000000;
- int index = 0;
- for (int y = 0; y < source.pixelHeight; y++) {
- for (int x = 0; x < source.pixelWidth; x++) {
- tintedTemp[x] = hi | (source.pixels[index++] & 0xFFFFFF);
- }
- //wr.setDataElements(0, y, source.width, 1, tintedTemp);
- pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth);
- }
- } else {
- int index = 0;
- for (int y = 0; y < source.pixelHeight; y++) {
- if (source.format == RGB) {
- int alpha = tintColor & 0xFF000000;
- for (int x = 0; x < source.pixelWidth; x++) {
- int argb1 = source.pixels[index++];
- int r1 = (argb1 >> 16) & 0xff;
- int g1 = (argb1 >> 8) & 0xff;
- int b1 = (argb1) & 0xff;
- tintedTemp[x] = alpha |
- (((r2 * r1) & 0xff00) << 8) |
- ((g2 * g1) & 0xff00) |
- (((b2 * b1) & 0xff00) >> 8);
- }
- } else if (source.format == ARGB) {
- for (int x = 0; x < source.pixelWidth; x++) {
- int argb1 = source.pixels[index++];
- int a1 = (argb1 >> 24) & 0xff;
- int r1 = (argb1 >> 16) & 0xff;
- int g1 = (argb1 >> 8) & 0xff;
- int b1 = (argb1) & 0xff;
- tintedTemp[x] =
- (((a2 * a1) & 0xff00) << 16) |
- (((r2 * r1) & 0xff00) << 8) |
- ((g2 * g1) & 0xff00) |
- (((b2 * b1) & 0xff00) >> 8);
- }
- } else if (source.format == ALPHA) {
- int lower = tintColor & 0xFFFFFF;
- for (int x = 0; x < source.pixelWidth; x++) {
- int a1 = source.pixels[index++];
- tintedTemp[x] =
- (((a2 * a1) & 0xff00) << 16) | lower;
- }
- }
- //wr.setDataElements(0, y, source.width, 1, tintedTemp);
- pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth);
- }
- }
- // Not sure why ARGB images take the scales in this order...
-// float[] scales = { tintR, tintG, tintB, tintA };
-// float[] offsets = new float[4];
-// RescaleOp op = new RescaleOp(scales, offsets, null);
-// op.filter(image, image);
- }
- } else { // !tint
- if (targetType == RGB && (source.pixels[0] >> 24 == 0)) {
- // If it's an RGB image and the high bits aren't set, need to set
- // the high bits to opaque because we're drawing ARGB images.
- source.filter(OPAQUE);
- // Opting to just manipulate the image here, since it shouldn't
- // affect anything else (and alpha(get(x, y)) should return 0xff).
- // Wel also make no guarantees about the values of the pixels array
- // in a PImage and how the high bits will be set.
- }
- // If no tint, just shove the pixels on in there verbatim
- //wr.setDataElements(0, 0, source.width, source.height, source.pixels);
- //System.out.println("moving the big one");
- pw.setPixels(0, 0, source.pixelWidth, source.pixelHeight,
- argbFormat, source.pixels, 0, source.pixelWidth);
- }
- this.tinted = tint;
- this.tintedColor = tintColor;
-
-// GraphicsConfiguration gc = parent.getGraphicsConfiguration();
-// compat = gc.createCompatibleImage(image.getWidth(),
-// image.getHeight(),
-// Transparency.TRANSLUCENT);
-//
-// Graphics2D g = compat.createGraphics();
-// g.drawImage(image, 0, 0, null);
-// g.dispose();
- }
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SHAPE
-
-
- //public void shapeMode(int mode)
-
-
- //public void shape(PShape shape)
-
-
- //public void shape(PShape shape, float x, float y)
-
-
- //public void shape(PShape shape, float x, float y, float c, float d)
-
-
- //////////////////////////////////////////////////////////////
-
- // SHAPE I/O
-
-
- @Override
- public PShape loadShape(String filename) {
- return loadShape(filename, null);
- }
-
-
- @Override
- public PShape loadShape(String filename, String options) {
- String extension = PApplet.getExtension(filename);
- if (extension.equals("svg") || extension.equals("svgz")) {
- return new PShapeSVG(parent.loadXML(filename));
- }
- PGraphics.showWarning("Unsupported format: " + filename);
- return null;
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // TEXT ATTRIBUTES
-
-
- protected FontCache fontCache = new FontCache();
-
- // Is initialized when defaultFontOrDeath() is called
- // and mirrors PGraphics.textFont field
- protected FontInfo textFontInfo;
-
-
- @Override
- protected PFont createFont(String name, float size,
- boolean smooth, char[] charset) {
- PFont font = super.createFont(name, size, smooth, charset);
- if (font.isStream()) {
- fontCache.nameToFilename.put(font.getName(), name);
- }
- return font;
- }
-
-
- @Override
- protected void defaultFontOrDeath(String method, float size) {
- super.defaultFontOrDeath(method, size);
- handleTextFont(textFont, size);
- }
-
-
- @Override
- protected boolean textModeCheck(int mode) {
- return mode == MODEL;
- }
-
-
- @Override
- public float textAscent() {
- if (textFont == null) {
- defaultFontOrDeath("textAscent");
- }
- if (textFontInfo.font == null) {
- return super.textAscent();
- }
- return textFontInfo.ascent;
- }
-
-
- @Override
- public float textDescent() {
- if (textFont == null) {
- defaultFontOrDeath("textDescent");
- }
- if (textFontInfo.font == null) {
- return super.textDescent();
- }
- return textFontInfo.descent;
- }
-
-
- static final class FontInfo {
- // TODO: this should be based on memory consumption
- // this should be enough e.g. for all grays and alpha combos
- static final int MAX_CACHED_COLORS_PER_FONT = 1 << 16;
-
- // used only when there is native font
- Font font;
- float ascent;
- float descent;
-
- // used only when there is no native font
- // maps 32-bit color to the arrays of tinted glyph images
- Map tintCache;
- }
-
-
- static final class FontCache {
- static final int MAX_CACHE_SIZE = 512;
-
- // keeps track of filenames of fonts loaded from ttf and otf files
- Map nameToFilename = new HashMap<>();
-
- // keeps track of fonts which should be rendered as pictures
- // so we don't go through native font search process every time
- final HashSet nonNativeNames = new HashSet<>();
-
- // keeps all created fonts for reuse up to MAX_CACHE_SIZE limit
- // when the limit is reached, the least recently used font is removed
- // TODO: this should be based on memory consumption
- final LinkedHashMap cache =
- new LinkedHashMap<>(16, 0.75f, true) {
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > MAX_CACHE_SIZE;
- }
- };
-
- // key for retrieving fonts from cache; don't use for insertion,
- // every font has to have its own new Key instance
- final Key retrievingKey = new Key();
-
- // text node used for measuring sizes of text
- final Text measuringText = new Text();
-
- FontInfo get(String name, float size) {
- if (nonNativeNames.contains(name)) {
- // Don't have native font, using glyph images.
- // Size is set to zero, because all sizes of this font
- // should share one FontInfo with one tintCache.
- size = 0;
- }
- retrievingKey.name = name;
- retrievingKey.size = size;
- return cache.get(retrievingKey);
- }
-
- void put(String name, float size, FontInfo fontInfo) {
- if (fontInfo.font == null) {
- // Don't have native font, using glyph images.
- // Size is set to zero, because all sizes of this font
- // should share one FontInfo with one tintCache.
- nonNativeNames.add(name);
- size = 0;
- }
- Key key = new Key();
- key.name = name;
- key.size = size;
- cache.put(key, fontInfo);
- }
-
- FontInfo createFontInfo(Font font) {
- FontInfo result = new FontInfo();
- result.font = font;
- if (font != null) {
- // measure ascent and descent
- measuringText.setFont(result.font);
- measuringText.setText(" ");
- float lineHeight = (float) measuringText.getLayoutBounds().getHeight();
- result.ascent = (float) measuringText.getBaselineOffset();
- result.descent = lineHeight - result.ascent;
- }
- return result;
- }
-
- static final class Key {
- String name;
- float size;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Key that = (Key) o;
- if (Float.compare(that.size, size) != 0) return false;
- return name.equals(that.name);
- }
-
- @Override
- public int hashCode() {
- int result = name.hashCode();
- result = 31 * result + (size != +0.0f ? Float.floatToIntBits(size) : 0);
- return result;
- }
- }
- }
-
-
- ///////////////////////////////////////////////////////////////
-
- // TEXT
-
- // None of the variations of text() are overridden from PGraphics.
-
-
-
- //////////////////////////////////////////////////////////////
-
- // TEXT IMPL
-
-
- @Override
- protected void textFontImpl(PFont which, float size) {
- handleTextFont(which, size);
- handleTextSize(size);
- }
-
-
- @Override
- protected void textSizeImpl(float size) {
- handleTextFont(textFont, size);
- handleTextSize(size);
- }
-
-
- /**
- * FX specific. When setting font or size, new font has to
- * be created. Both textFontImpl and textSizeImpl call this one.
- * @param which font to be set, not null
- * @param size size to be set, greater than zero
- */
- protected void handleTextFont(PFont which, float size) {
- textFont = which;
-
- String fontName = which.getName();
- String fontPsName = which.getPostScriptName();
-
- textFontInfo = fontCache.get(fontName, size);
- if (textFontInfo == null) {
- Font font = null;
-
- if (which.isStream()) {
- // Load from ttf or otf file
- String filename = fontCache.nameToFilename.get(fontName);
- font = Font.loadFont(parent.createInput(filename), size);
- }
-
- if (font == null) {
- // Look up font name
- font = new Font(fontName, size);
- if (!fontName.equalsIgnoreCase(font.getName())) {
- // Look up font postscript name
- font = new Font(fontPsName, size);
- if (!fontPsName.equalsIgnoreCase(font.getName())) {
- font = null; // Done with it
- }
- }
- }
-
- if (font == null && which.getNative() != null) {
- // Ain't got nothing, but AWT has something, so glyph images are not
- // going to be used for this font; go with the default font then
- font = new Font(size);
- }
-
- textFontInfo = fontCache.createFontInfo(font);
- fontCache.put(fontName, size, textFontInfo);
- }
-
- context.setFont(textFontInfo.font);
- }
-
-
- @Override
- protected void textLineImpl(char[] buffer, int start, int stop, float x, float y) {
- if (textFontInfo.font == null) {
- super.textLineImpl(buffer, start, stop, x, y);
- } else {
- context.fillText(new String(buffer, start, stop - start), x, y);
- }
- }
-
-
- protected PImage getTintedGlyphImage(PFont.Glyph glyph, int tintColor) {
- if (textFontInfo.tintCache == null) {
- textFontInfo.tintCache = new LinkedHashMap<>(16, 0.75f, true) {
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > FontInfo.MAX_CACHED_COLORS_PER_FONT;
- }
- };
- }
- PImage[] tintedGlyphs = textFontInfo.tintCache.get(tintColor);
- int index = glyph.index;
- if (tintedGlyphs == null || tintedGlyphs.length <= index) {
- PImage[] newArray = new PImage[textFont.getGlyphCount()];
- if (tintedGlyphs != null) {
- System.arraycopy(tintedGlyphs, 0, newArray, 0, tintedGlyphs.length);
- }
- tintedGlyphs = newArray;
- textFontInfo.tintCache.put(tintColor, tintedGlyphs);
- }
- PImage tintedGlyph = tintedGlyphs[index];
- if (tintedGlyph == null) {
- tintedGlyph = glyph.image.copy();
- tintedGlyphs[index] = tintedGlyph;
- }
- return tintedGlyph;
- }
-
-
- @Override
- protected void textCharImpl(char ch, float x, float y) { //, float z) {
- PFont.Glyph glyph = textFont.getGlyph(ch);
- if (glyph != null) {
- if (textMode == MODEL) {
- float bitmapSize = textFont.getSize();
- float high = glyph.height / bitmapSize;
- float wide = glyph.width / bitmapSize;
- float leftExtent = glyph.leftExtent / bitmapSize;
- float topExtent = glyph.topExtent / bitmapSize;
-
- float x1 = x + leftExtent * textSize;
- float y1 = y - topExtent * textSize;
- float x2 = x1 + wide * textSize;
- float y2 = y1 + high * textSize;
-
- PImage glyphImage = (fillColor == 0xFFFFFFFF) ?
- glyph.image : getTintedGlyphImage(glyph, fillColor);
-
- textCharModelImpl(glyphImage,
- x1, y1, x2, y2,
- glyph.width, glyph.height);
- }
- } else if (ch != ' ' && ch != 127) {
- showWarning("No glyph found for the " + ch +
- " (\\u" + PApplet.hex(ch, 4) + ") character");
- }
- }
-
-
- @Override
- protected float textWidthImpl(char[] buffer, int start, int stop) {
- if (textFont == null) {
- defaultFontOrDeath("textWidth");
- }
-
- if (textFontInfo.font == null) {
- return super.textWidthImpl(buffer, start, stop);
- }
-
- fontCache.measuringText.setFont(textFontInfo.font);
- fontCache.measuringText.setText(new String(buffer, start, stop - start));
- return (float) fontCache.measuringText.getLayoutBounds().getWidth();
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // MATRIX STACK
-
-
- @Override
- public void pushMatrix() {
- if (transformCount == transformStack.length) {
- throw new RuntimeException("pushMatrix() cannot use push more than " +
- transformStack.length + " times");
- }
- transformStack[transformCount] = context.getTransform(transformStack[transformCount]);
- transformCount++;
- }
-
-
- @Override
- public void popMatrix() {
- if (transformCount == 0) {
- throw new RuntimeException("missing a pushMatrix() " +
- "to go with that popMatrix()");
- }
- transformCount--;
- context.setTransform(transformStack[transformCount]);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // MATRIX TRANSFORMS
-
-
- @Override
- public void translate(float tx, float ty) {
- context.translate(tx, ty);
- }
-
-
- //public void translate(float tx, float ty, float tz)
-
-
- @Override
- public void rotate(float angle) {
- context.rotate(PApplet.degrees(angle));
- }
-
-
- @Override
- public void rotateX(float angle) {
- showDepthWarning("rotateX");
- }
-
-
- @Override
- public void rotateY(float angle) {
- showDepthWarning("rotateY");
- }
-
-
- @Override
- public void rotateZ(float angle) {
- showDepthWarning("rotateZ");
- }
-
-
- @Override
- public void rotate(float angle, float vx, float vy, float vz) {
- showVariationWarning("rotate");
- }
-
-
- @Override
- public void scale(float s) {
- context.scale(s, s);
- }
-
-
- @Override
- public void scale(float sx, float sy) {
- context.scale(sx, sy);
- }
-
-
- @Override
- public void scale(float sx, float sy, float sz) {
- showDepthWarningXYZ("scale");
- }
-
-
- @Override
- public void shearX(float angle) {
- Affine temp = new Affine();
- temp.appendShear(Math.tan(angle), 0);
- context.transform(temp);
- }
-
-
- @Override
- public void shearY(float angle) {
- Affine temp = new Affine();
- temp.appendShear(0, Math.tan(angle));
- context.transform(temp);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // MATRIX MORE
-
-
- @Override
- public void resetMatrix() {
- context.setTransform(new Affine());
- }
-
-
- //public void applyMatrix(PMatrix2D source)
-
-
- @Override
- public void applyMatrix(float n00, float n01, float n02,
- float n10, float n11, float n12) {
- context.transform(n00, n10, n01, n11, n02, n12);
- }
-
-
- //public void applyMatrix(PMatrix3D source)
-
-
- @Override
- public void applyMatrix(float n00, float n01, float n02, float n03,
- float n10, float n11, float n12, float n13,
- float n20, float n21, float n22, float n23,
- float n30, float n31, float n32, float n33) {
- showVariationWarning("applyMatrix");
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // MATRIX GET/SET
-
-
- @Override
- public PMatrix getMatrix() {
- return getMatrix((PMatrix2D) null);
- }
-
-
- @Override
- public PMatrix2D getMatrix(PMatrix2D target) {
- if (target == null) {
- target = new PMatrix2D();
- }
- //double[] transform = new double[6];
- // TODO This is not tested; apparently Affine is a full 3x4
- Affine t = context.getTransform(); //.getMatrix(transform);
-// target.set((float) transform[0], (float) transform[2], (float) transform[4],
-// (float) transform[1], (float) transform[3], (float) transform[5]);
- target.set((float) t.getMxx(), (float) t.getMxy(), (float) t.getTx(),
- (float) t.getMyx(), (float) t.getMyy(), (float) t.getTy());
- return target;
- }
-
-
- @Override
- public PMatrix3D getMatrix(PMatrix3D target) {
- showVariationWarning("getMatrix");
- return target;
- }
-
-
- //public void setMatrix(PMatrix source)
-
-
- @Override
- public void setMatrix(PMatrix2D source) {
- context.setTransform(source.m00, source.m10,
- source.m01, source.m11,
- source.m02, source.m12);
- }
-
-
- @Override
- public void setMatrix(PMatrix3D source) {
- showVariationWarning("setMatrix");
- }
-
-
- @Override
- public void printMatrix() {
- getMatrix((PMatrix2D) null).print();
- }
-
-
-
-// //////////////////////////////////////////////////////////////
-//
-// // CAMERA and PROJECTION
-//
-// // Inherit the plaintive warnings from PGraphics
-//
-//
-// //public void beginCamera()
-// //public void endCamera()
-// //public void camera()
-// //public void camera(float eyeX, float eyeY, float eyeZ,
-// // float centerX, float centerY, float centerZ,
-// // float upX, float upY, float upZ)
-// //public void printCamera()
-//
-// //public void ortho()
-// //public void ortho(float left, float right,
-// // float bottom, float top,
-// // float near, float far)
-// //public void perspective()
-// //public void perspective(float fov, float aspect, float near, float far)
-// //public void frustum(float left, float right,
-// // float bottom, float top,
-// // float near, float far)
-// //public void printProjection()
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SCREEN and MODEL transforms
-
-
- @Override
- public float screenX(float x, float y) {
- return (float) context.getTransform().transform(x, y).getX();
- }
-
-
- @Override
- public float screenY(float x, float y) {
- return (float) context.getTransform().transform(x, y).getY();
- }
-
-
- @Override
- public float screenX(float x, float y, float z) {
- showDepthWarningXYZ("screenX");
- return 0;
- }
-
-
- @Override
- public float screenY(float x, float y, float z) {
- showDepthWarningXYZ("screenY");
- return 0;
- }
-
-
- @Override
- public float screenZ(float x, float y, float z) {
- showDepthWarningXYZ("screenZ");
- return 0;
- }
-
-
- //public float modelX(float x, float y, float z)
-
-
- //public float modelY(float x, float y, float z)
-
-
- //public float modelZ(float x, float y, float z)
-
-
-
-// //////////////////////////////////////////////////////////////
-//
-// // STYLE
-//
-// // pushStyle(), popStyle(), style() and getStyle() inherited.
-
-
-
- //////////////////////////////////////////////////////////////
-
- // STROKE CAP/JOIN/WEIGHT
-
-
- @Override
- public void strokeCap(int cap) {
- super.strokeCap(cap);
- if (strokeCap == ROUND) {
- context.setLineCap(StrokeLineCap.ROUND);
- } else if (strokeCap == PROJECT) {
- context.setLineCap(StrokeLineCap.SQUARE);
- } else {
- context.setLineCap(StrokeLineCap.BUTT);
- }
- }
-
-
- @Override
- public void strokeJoin(int join) {
- super.strokeJoin(join);
- if (strokeJoin == MITER) {
- context.setLineJoin(StrokeLineJoin.MITER);
- } else if (strokeJoin == ROUND) {
- context.setLineJoin(StrokeLineJoin.ROUND);
- } else {
- context.setLineJoin(StrokeLineJoin.BEVEL);
- }
- }
-
-
- @Override
- public void strokeWeight(float weight) {
- super.strokeWeight(weight);
- context.setLineWidth(weight);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // STROKE
-
- // noStroke() and stroke() inherited from PGraphics.
-
-
- @Override
- protected void strokeFromCalc() {
- super.strokeFromCalc();
- context.setStroke(new Color(strokeR, strokeG, strokeB, strokeA));
- }
-
-
- protected boolean drawingThinLines() {
- // align strokes to pixel centers when drawing thin lines
- return stroke && strokeWeight == 1;
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // TINT
-
- // noTint() and tint() inherited from PGraphics.
-
-
-
- //////////////////////////////////////////////////////////////
-
- // FILL
-
- // noFill() and fill() inherited from PGraphics.
-
-
- @Override
- protected void fillFromCalc() {
- super.fillFromCalc();
- context.setFill(new Color(fillR, fillG, fillB, fillA));
- }
-
-
-
-// //////////////////////////////////////////////////////////////
-//
-// // MATERIAL PROPERTIES
-//
-//
-// //public void ambient(int rgb)
-// //public void ambient(float gray)
-// //public void ambient(float x, float y, float z)
-// //protected void ambientFromCalc()
-// //public void specular(int rgb)
-// //public void specular(float gray)
-// //public void specular(float x, float y, float z)
-// //protected void specularFromCalc()
-// //public void shininess(float shine)
-// //public void emissive(int rgb)
-// //public void emissive(float gray)
-// //public void emissive(float x, float y, float z )
-// //protected void emissiveFromCalc()
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // LIGHTS
-//
-//
-// //public void lights()
-// //public void noLights()
-// //public void ambientLight(float red, float green, float blue)
-// //public void ambientLight(float red, float green, float blue,
-// // float x, float y, float z)
-// //public void directionalLight(float red, float green, float blue,
-// // float nx, float ny, float nz)
-// //public void pointLight(float red, float green, float blue,
-// // float x, float y, float z)
-// //public void spotLight(float red, float green, float blue,
-// // float x, float y, float z,
-// // float nx, float ny, float nz,
-// // float angle, float concentration)
-// //public void lightFalloff(float constant, float linear, float quadratic)
-// //public void lightSpecular(float x, float y, float z)
-// //protected void lightPosition(int num, float x, float y, float z)
-// //protected void lightDirection(int num, float x, float y, float z)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BACKGROUND
-
-
- @Override
- public void backgroundImpl() {
-
- // if pixels are modified, we don't flush them (just mark them flushed)
- // because they would be immediately overwritten by the background anyway
- modified = false;
- loaded = false;
-
- // Save drawing context (transform, fill, blend mode, etc.)
- context.save();
-
- // Reset transform to identity
- context.setTransform(new Affine());
-
- // This only takes into account cases where this is the primary surface.
- // Not sure what we do with offscreen anyway.
- context.setFill(new Color(backgroundR, backgroundG, backgroundB, backgroundA));
- context.setGlobalBlendMode(BlendMode.SRC_OVER);
- context.fillRect(0, 0, width, height);
-
- // Restore drawing context (transform, fill, blend mode, etc.)
- context.restore();
- }
-
-
-
-// //////////////////////////////////////////////////////////////
-//
-// // COLOR MODE
-//
-// // All colorMode() variations are inherited from PGraphics.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // COLOR CALC
-//
-// // colorCalc() and colorCalcARGB() inherited from PGraphics.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // COLOR DATATYPE STUFFING
-//
-// // final color() variations inherited.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // COLOR DATATYPE EXTRACTION
-//
-// // final methods alpha, red, green, blue,
-// // hue, saturation, and brightness all inherited.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // COLOR DATATYPE INTERPOLATION
-//
-// // both lerpColor variants inherited.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // BEGIN/END RAW
-//
-//
-// @Override
-// public void beginRaw(PGraphics recorderRaw) {
-// showMethodWarning("beginRaw");
-// }
-//
-//
-// @Override
-// public void endRaw() {
-// showMethodWarning("endRaw");
-// }
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // WARNINGS and EXCEPTIONS
-//
-// // showWarning and showException inherited.
-//
-//
-//
-// //////////////////////////////////////////////////////////////
-//
-// // RENDERER SUPPORT QUERIES
-//
-//
-// //public boolean displayable() // true
-//
-//
-// //public boolean is2D() // true
-//
-//
-// //public boolean is3D() // false
-
-
-
- //////////////////////////////////////////////////////////////
-
- // PIMAGE METHODS
-
-
- @Override
- public void loadPixels() {
- if ((pixels == null) || (pixels.length != pixelWidth * pixelHeight)) {
- pixels = new int[pixelWidth * pixelHeight];
- loaded = false;
- }
-
- if (!loaded) {
- if (snapshotImage == null ||
- snapshotImage.getWidth() != pixelWidth ||
- snapshotImage.getHeight() != pixelHeight) {
- snapshotImage = new WritableImage(pixelWidth, pixelHeight);
- }
-
- SnapshotParameters sp = null;
- if (pixelDensity != 1) {
- sp = new SnapshotParameters();
- sp.setTransform(Transform.scale(pixelDensity, pixelDensity));
- }
- snapshotImage = ((PSurfaceFX) surface).canvas.snapshot(sp, snapshotImage);
- PixelReader pr = snapshotImage.getPixelReader();
- pr.getPixels(0, 0, pixelWidth, pixelHeight, argbFormat, pixels, 0, pixelWidth);
-
- loaded = true;
- modified = false;
- }
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // GET/SET PIXELS
-
-
- @Override
- public int get(int x, int y) {
- loadPixels();
- return super.get(x, y);
- }
-
-
- @Override
- protected void getImpl(int sourceX, int sourceY,
- int sourceWidth, int sourceHeight,
- PImage target, int targetX, int targetY) {
- loadPixels();
- super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight,
- target, targetX, targetY);
- }
-
-
- @Override
- public void set(int x, int y, int argb) {
- loadPixels();
- super.set(x, y, argb);
- }
-
-
- @Override
- protected void setImpl(PImage sourceImage,
- int sourceX, int sourceY,
- int sourceWidth, int sourceHeight,
- int targetX, int targetY) {
- sourceImage.loadPixels();
-
- int sourceOffset = sourceX + sourceImage.pixelWidth * sourceY;
-
- PixelWriter pw = context.getPixelWriter();
- pw.setPixels(targetX, targetY, sourceWidth, sourceHeight,
- argbFormat,
- sourceImage.pixels,
- sourceOffset,
- sourceImage.pixelWidth);
-
- // Let's keep them loaded
- if (loaded) {
- int sourceStride = sourceImage.pixelWidth;
- int targetStride = pixelWidth;
- int targetOffset = targetX + targetY * targetStride;
- for (int i = 0; i < sourceHeight; i++) {
- System.arraycopy(sourceImage.pixels, sourceOffset + i * sourceStride,
- pixels, targetOffset + i * targetStride, sourceWidth);
- }
- }
- }
-
-
- //////////////////////////////////////////////////////////////
-
- // MASK
-
-
- static final String MASK_WARNING =
- "mask() cannot be used on the main drawing surface";
-
-
- @Override
- public void mask(PImage alpha) {
- showWarning(MASK_WARNING);
- }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // FILTER
-
- // Because the PImage versions call loadPixels() and
- // updatePixels(), no need to override anything here.
-
-
- //public void filter(int kind)
-
-
- //public void filter(int kind, float param)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // COPY
-
-
-// @Override
-// public void copy(int sx, int sy, int sw, int sh,
-// int dx, int dy, int dw, int dh) {
-// if ((sw != dw) || (sh != dh)) {
-// g2.drawImage(image, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
-//
-// } else {
-// dx = dx - sx; // java2d's "dx" is the delta, not dest
-// dy = dy - sy;
-// g2.copyArea(sx, sy, sw, sh, dx, dy);
-// }
-// }
-
-
-// @Override
-// public void copy(PImage src,
-// int sx, int sy, int sw, int sh,
-// int dx, int dy, int dw, int dh) {
-// g2.drawImage((Image) src.getNative(),
-// dx, dy, dx + dw, dy + dh,
-// sx, sy, sx + sw, sy + sh, null);
-// }
-
-
-
- //////////////////////////////////////////////////////////////
-
- // BLEND
-
-
- //static public int blendColor(int c1, int c2, int mode)
-
-
- //public void blend(int sx, int sy, int sw, int sh,
- // int dx, int dy, int dw, int dh, int mode)
-
-
- //public void blend(PImage src,
- // int sx, int sy, int sw, int sh,
- // int dx, int dy, int dw, int dh, int mode)
-
-
-
- //////////////////////////////////////////////////////////////
-
- // SAVE
-
-
- //public void save(String filename)
-
-
-
- //////////////////////////////////////////////////////////////
-
- /**
- * Display a warning that the specified method is simply unavailable.
- */
- static public void showTodoWarning(String method, int issue) {
- showWarning(method + "() is not yet available: " +
- "https://github.com/processing/processing/issues/" + issue);
- }
-}
diff --git a/java/libraries/javafx/src/processing/javafx/PSurfaceFX.java b/java/libraries/javafx/src/processing/javafx/PSurfaceFX.java
deleted file mode 100644
index 470ae71bc..000000000
--- a/java/libraries/javafx/src/processing/javafx/PSurfaceFX.java
+++ /dev/null
@@ -1,1090 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2015 The Processing Foundation
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, version 2.1.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-*/
-
-package processing.javafx;
-
-import com.sun.glass.ui.Screen;
-
-import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.Rectangle;
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.SynchronousQueue;
-
-import javafx.animation.Animation;
-import javafx.animation.KeyFrame;
-import javafx.animation.Timeline;
-import javafx.application.Application;
-import javafx.application.Platform;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.event.EventType;
-import javafx.scene.Cursor;
-import javafx.scene.ImageCursor;
-import javafx.scene.Scene;
-import javafx.scene.SceneAntialiasing;
-import javafx.scene.canvas.Canvas;
-import javafx.scene.image.Image;
-import javafx.scene.image.PixelFormat;
-import javafx.scene.image.WritableImage;
-import javafx.scene.input.KeyCode;
-import javafx.scene.input.KeyEvent;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.input.ScrollEvent;
-import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
-import javafx.stage.StageStyle;
-import javafx.stage.WindowEvent;
-import javafx.util.Duration;
-import processing.awt.ShimAWT;
-import processing.core.*;
-
-
-public class PSurfaceFX implements PSurface {
- PApplet sketch;
-
- PGraphicsFX2D fx;
- Stage stage;
- Canvas canvas;
-
- final Animation animation;
- float frameRate = 60;
-
- private SynchronousQueue drawExceptionQueue = new SynchronousQueue<>();
-
- public PSurfaceFX(PGraphicsFX2D graphics) {
- fx = graphics;
- canvas = new ResizableCanvas();
-
- // set up main drawing loop
- KeyFrame keyFrame = new KeyFrame(Duration.millis(1000),
- new EventHandler() {
- public void handle(ActionEvent event) {
- long startNanoTime = System.nanoTime();
- try {
- sketch.handleDraw();
- } catch (Throwable e) {
- // Let exception handler thread crash with our exception
- drawExceptionQueue.offer(e);
- // Stop animating right now so nothing runs afterwards
- // and crash frame can be for example traced by println()
- animation.stop();
- return;
- }
- long drawNanos = System.nanoTime() - startNanoTime;
-
- if (sketch.exitCalled()) {
- // using Platform.runLater() didn't work
-// Platform.runLater(new Runnable() {
-// public void run() {
- // instead of System.exit(), safely shut down JavaFX this way
- Platform.exit();
-// }
-// });
- }
- if (sketch.frameCount > 5) {
- animation.setRate(-PApplet.min(1e9f / drawNanos, frameRate));
- }
- }
- });
- animation = new Timeline(keyFrame);
- animation.setCycleCount(Animation.INDEFINITE);
-
- // key frame has duration of 1 second, so the rate of the animation
- // should be set to frames per second
-
- // setting rate to negative so that event fires at the start of
- // the key frame and first frame is drawn immediately
- animation.setRate(-frameRate);
- }
-
-
- public Object getNative() {
- return canvas;
- }
-
-
- class ResizableCanvas extends Canvas {
-
- public ResizableCanvas() {
- widthProperty().addListener(new ChangeListener() {
- @Override
- public void changed(ObservableValue extends Number> value,
- Number oldWidth, Number newWidth) {
-// sketch.width = newWidth.intValue();
- sketch.setSize(newWidth.intValue(), sketch.height);
-// draw();
- fx.setSize(sketch.width, sketch.height);
- }
- });
- heightProperty().addListener(new ChangeListener() {
- @Override
- public void changed(ObservableValue extends Number> value,
- Number oldHeight, Number newHeight) {
-// sketch.height = newHeight.intValue();
- sketch.setSize(sketch.width, newHeight.intValue());
-// draw();
- fx.setSize(sketch.width, sketch.height);
- }
- });
-
- //addEventHandler(eventType, eventHandler);
-
- EventHandler mouseHandler = new EventHandler<>() {
- public void handle(MouseEvent e) {
- fxMouseEvent(e);
- }
- };
-
- setOnMousePressed(mouseHandler);
- setOnMouseReleased(mouseHandler);
- setOnMouseClicked(mouseHandler);
- setOnMouseEntered(mouseHandler);
- setOnMouseExited(mouseHandler);
-
- setOnMouseDragged(mouseHandler);
- setOnMouseMoved(mouseHandler);
-
- setOnScroll(new EventHandler() {
- public void handle(ScrollEvent e) {
- fxScrollEvent(e);
- }
- });
-
- EventHandler keyHandler = new EventHandler<>() {
- public void handle(KeyEvent e) {
- fxKeyEvent(e);
- }
- };
-
- setOnKeyPressed(keyHandler);
- setOnKeyReleased(keyHandler);
- setOnKeyTyped(keyHandler);
-
- setFocusTraversable(false); // prevent tab from de-focusing
-
- focusedProperty().addListener(new ChangeListener() {
- public void changed(ObservableValue extends Boolean> value,
- Boolean oldValue, Boolean newValue) {
- if (newValue.booleanValue()) {
- sketch.focused = true;
- sketch.focusGained();
- } else {
- sketch.focused = false;
- sketch.focusLost();
- }
- }
- });
- }
-
- public Stage getStage() {
- return stage;
- }
-
- @Override
- public boolean isResizable() {
- return true;
- }
-
- @Override
- public double prefWidth(double height) {
- return getWidth();
- }
-
- @Override
- public double prefHeight(double width) {
- return getHeight();
- }
- }
-
-
- // TODO rewrite before 4.0 release
- public PImage loadImage(String path, Object... args) {
- return ShimAWT.loadImage(sketch, path, args);
- }
-
-
- @Override
- public void selectInput(String prompt, String callbackMethod,
- File file, Object callbackObject) {
- ShimAWT.selectInput(prompt, callbackMethod, file, callbackObject);
- }
-
-
- @Override
- public void selectOutput(String prompt, String callbackMethod,
- File file, Object callbackObject) {
- ShimAWT.selectOutput(prompt, callbackMethod, file, callbackObject);
- }
-
-
- @Override
- public void selectFolder(String prompt, String callbackMethod,
- File file, Object callbackObject) {
- ShimAWT.selectFolder(prompt, callbackMethod, file, callbackObject);
- }
-
-
- public void initOffscreen(PApplet sketch) {
- }
-
-
- static public class PApplicationFX extends Application {
- static public PSurfaceFX surface;
-// static String title; // title set at launch
-// static boolean resizable; // set at launch
-
- public PApplicationFX() { }
-
- @Override
- public void start(final Stage stage) {
-// if (title != null) {
-// stage.setTitle(title);
-// }
-
- PApplet sketch = surface.sketch;
-
- // See JEP 263
- float renderScale = Screen.getMainScreen().getRecommendedOutputScaleX();
- if (PApplet.platform == PConstants.MACOS) {
- for (Screen s : Screen.getScreens()) {
- renderScale = Math.max(renderScale, s.getRecommendedOutputScaleX());
- }
- }
- if (sketch.pixelDensity == 2 && renderScale < 2) {
- sketch.pixelDensity = 1;
- sketch.g.pixelDensity = 1;
- System.err.println("pixelDensity(2) is not available for this display");
- }
-
- // Use AWT display code, because FX orders screens in different way
- GraphicsDevice displayDevice = null;
-
- GraphicsEnvironment environment =
- GraphicsEnvironment.getLocalGraphicsEnvironment();
-
- int displayNum = sketch.sketchDisplay();
- if (displayNum > 0) { // if -1, use the default device
- GraphicsDevice[] devices = environment.getScreenDevices();
- if (displayNum <= devices.length) {
- displayDevice = devices[displayNum - 1];
- } else {
- System.err.format("Display %d does not exist, " +
- "using the default display instead.%n", displayNum);
- for (int i = 0; i < devices.length; i++) {
- System.err.format("Display %d is %s%n", (i+1), devices[i]);
- }
- }
- }
- if (displayDevice == null) {
- displayDevice = environment.getDefaultScreenDevice();
- }
-
- boolean fullScreen = sketch.sketchFullScreen();
- boolean spanDisplays = sketch.sketchDisplay() == PConstants.SPAN;
-
- Rectangle primaryScreenRect = displayDevice.getDefaultConfiguration().getBounds();
- Rectangle screenRect = primaryScreenRect;
- if (fullScreen || spanDisplays) {
- double minX = screenRect.getMinX();
- double maxX = screenRect.getMaxX();
- double minY = screenRect.getMinY();
- double maxY = screenRect.getMaxY();
- if (spanDisplays) {
- for (GraphicsDevice s : environment.getScreenDevices()) {
- Rectangle bounds = s.getDefaultConfiguration().getBounds();
- minX = Math.min(minX, bounds.getMinX());
- maxX = Math.max(maxX, bounds.getMaxX());
- minY = Math.min(minY, bounds.getMinY());
- maxY = Math.max(maxY, bounds.getMaxY());
- }
- }
- screenRect = new Rectangle((int) minX, (int) minY,
- (int) (maxX - minX), (int) (maxY - minY));
- }
-
- // Set the displayWidth/Height variables inside PApplet, so that they're
- // usable and can even be returned by the sketchWidth()/Height() methods.
- sketch.displayWidth = (int) screenRect.getWidth();
- sketch.displayHeight = (int) screenRect.getHeight();
-
- int sketchWidth = sketch.sketchWidth();
- int sketchHeight = sketch.sketchHeight();
-
- if (fullScreen || spanDisplays) {
- sketchWidth = (int) screenRect.getWidth();
- sketchHeight = (int) screenRect.getHeight();
-
- stage.initStyle(StageStyle.UNDECORATED);
- stage.setX(screenRect.getMinX());
- stage.setY(screenRect.getMinY());
- stage.setWidth(screenRect.getWidth());
- stage.setHeight(screenRect.getHeight());
- }
-
- Canvas canvas = surface.canvas;
- surface.fx.context = canvas.getGraphicsContext2D();
- StackPane stackPane = new StackPane();
- stackPane.getChildren().add(canvas);
- canvas.widthProperty().bind(stackPane.widthProperty());
- canvas.heightProperty().bind(stackPane.heightProperty());
-
- int width = sketchWidth;
- int height = sketchHeight;
- int smooth = sketch.sketchSmooth();
-
- // Workaround for https://bugs.openjdk.java.net/browse/JDK-8136495
- // https://github.com/processing/processing/issues/3823
- if ((PApplet.platform == PConstants.MACOS ||
- PApplet.platform == PConstants.LINUX) &&
- PApplet.javaVersionName.compareTo("1.8.0_60") >= 0 &&
- PApplet.javaVersionName.compareTo("1.8.0_72") < 0) {
- System.err.println("smooth() disabled for JavaFX with this Java version due to Oracle bug");
- System.err.println("https://github.com/processing/processing/issues/3795");
- smooth = 0;
- }
-
- SceneAntialiasing sceneAntialiasing = (smooth == 0) ?
- SceneAntialiasing.DISABLED : SceneAntialiasing.BALANCED;
-
- stage.setScene(new Scene(stackPane, width, height, false, sceneAntialiasing));
-
- // initFrame in different thread is waiting for
- // the stage, assign it only when it is all set up
- surface.stage = stage;
- }
-
- @Override
- public void stop() throws Exception {
- surface.sketch.dispose();
- }
- }
-
-
- //public Frame initFrame(PApplet sketch, java.awt.Color backgroundColor,
- public void initFrame(PApplet sketch) {/*, int backgroundColor,
- int deviceIndex, boolean fullScreen,
- boolean spanDisplays) {*/
- this.sketch = sketch;
- PApplicationFX.surface = this;
- //Frame frame = new DummyFrame();
- new Thread(new Runnable() {
- public void run() {
- Application.launch(PApplicationFX.class);
- }
- }).start();
-
- // wait for stage to be initialized on its own thread before continuing
- while (stage == null) {
- try {
- //System.out.println("waiting for launch");
- Thread.sleep(5);
- } catch (InterruptedException e) { }
- }
-
- startExceptionHandlerThread();
-
- setProcessingIcon(stage);
- }
-
-
- private void startExceptionHandlerThread() {
- Thread exceptionHandlerThread = new Thread(() -> {
- Throwable drawException;
- try {
- drawException = drawExceptionQueue.take();
- } catch (InterruptedException e) {
- return;
- }
- // Adapted from PSurfaceJOGL
- if (drawException != null) {
- if (drawException instanceof ThreadDeath) {
-// System.out.println("caught ThreadDeath");
-// throw (ThreadDeath)cause;
- } else if (drawException instanceof RuntimeException) {
- throw (RuntimeException) drawException;
- } else if (drawException instanceof UnsatisfiedLinkError) {
- throw new UnsatisfiedLinkError(drawException.getMessage());
- } else {
- throw new RuntimeException(drawException);
- }
- }
- });
- exceptionHandlerThread.setDaemon(true);
- exceptionHandlerThread.setName("Processing-FX-ExceptionHandler");
- exceptionHandlerThread.start();
- }
-
-
- /** Set the window (and dock, or whatever necessary) title. */
- public void setTitle(String title) {
-// PApplicationFX.title = title; // store this in case the stage still null
-// if (stage != null) {
- stage.setTitle(title);
-// }
- }
-
-
- /** Show or hide the window. */
- @Override
- public void setVisible(final boolean visible) {
- Platform.runLater(new Runnable() {
- public void run() {
- if (visible) {
- stage.show();
- canvas.requestFocus();
- } else {
- stage.hide();
- }
- }
- });
- }
-
-
- /** Set true if we want to resize things (default is not resizable) */
- public void setResizable(boolean resizable) {
-// PApplicationFX.resizable = resizable;
-// if (stage != null) {
- stage.setResizable(resizable);
-// }
- }
-
-
- public void setIcon(PImage icon) {
- int w = icon.pixelWidth;
- int h = icon.pixelHeight;
- WritableImage im = new WritableImage(w, h);
- im.getPixelWriter().setPixels(0, 0, w, h,
- PixelFormat.getIntArgbInstance(),
- icon.pixels,
- 0, w);
-
- Stage stage = (Stage) canvas.getScene().getWindow();
- stage.getIcons().clear();
- stage.getIcons().add(im);
- }
-
-
- List iconImages;
-
- protected void setProcessingIcon(Stage stage) {
- // Adapted from PSurfaceAWT
- // Note: FX chooses wrong icon size, should be fixed in Java 9, see:
- // https://bugs.openjdk.java.net/browse/JDK-8091186
- // Removing smaller sizes helps a bit, but big ones are downsized
- try {
- if (iconImages == null) {
- iconImages = new ArrayList<>();
- final int[] sizes = { 48, 64, 128, 256, 512 };
-
- for (int sz : sizes) {
- URL url = PApplet.class.getResource("/icon/icon-" + sz + ".png");
- Image image = new Image(url.toString());
- iconImages.add(image);
- }
- }
- List icons = stage.getIcons();
- icons.clear();
- icons.addAll(iconImages);
- } catch (Exception e) { } // harmless; keep this to ourselves
- }
-
-
- @Override
- public void setAlwaysOnTop(boolean always) {
- stage.setAlwaysOnTop(always);
- }
-
-
- /*
- @Override
- public void placeWindow(int[] location) {
- //setFrameSize();
-
- if (location != null) {
- // a specific location was received from the Runner
- // (applet has been run more than once, user placed window)
- stage.setX(location[0]);
- stage.setY(location[1]);
-
- } else { // just center on screen
- // Can't use frame.setLocationRelativeTo(null) because it sends the
- // frame to the main display, which undermines the --display setting.
-// frame.setLocation(screenRect.x + (screenRect.width - sketchWidth) / 2,
-// screenRect.y + (screenRect.height - sketchHeight) / 2);
- }
- if (stage.getY() < 0) {
- // Windows actually allows you to place frames where they can't be
- // closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508
- //frame.setLocation(frameLoc.x, 30);
- stage.setY(30);
- }
-
- //setCanvasSize();
-
- // TODO add window closing behavior
-// frame.addWindowListener(new WindowAdapter() {
-// @Override
-// public void windowClosing(WindowEvent e) {
-// System.exit(0);
-// }
-// });
-
- // TODO handle frame resizing events
-// setupFrameResizeListener();
-
- if (sketch.getGraphics().displayable()) {
- setVisible(true);
- }
- }
- */
-
-
- @Override
- public void placeWindow(int[] location, int[] editorLocation) {
- if (sketch.sketchFullScreen()) {
- PApplet.hideMenuBar();
- return;
- }
-
- int wide = sketch.width; // stage.getWidth() is NaN here
- //int high = sketch.height; // stage.getHeight()
-
- if (location != null) {
- // a specific location was received from the Runner
- // (applet has been run more than once, user placed window)
- stage.setX(location[0]);
- stage.setY(location[1]);
-
- } else if (editorLocation != null) {
- int locationX = editorLocation[0] - 20;
- int locationY = editorLocation[1];
-
- if (locationX - wide > 10) {
- // if it fits to the left of the window
- stage.setX(locationX - wide);
- stage.setY(locationY);
-
- } else { // doesn't fit
- stage.centerOnScreen();
- }
- } else { // just center on screen
- stage.centerOnScreen();
- }
- }
-
-
- // http://download.java.net/jdk8/jfxdocs/javafx/stage/Stage.html#setFullScreenExitHint-java.lang.String-
- // http://download.java.net/jdk8/jfxdocs/javafx/stage/Stage.html#setFullScreenExitKeyCombination-javafx.scene.input.KeyCombination-
- public void placePresent(int stopColor) {
- // TODO Auto-generated method stub
- PApplet.hideMenuBar();
- }
-
-
- @Override
- public void setupExternalMessages() {
- stage.xProperty().addListener(new ChangeListener() {
- @Override
- public void changed(ObservableValue extends Number> value,
- Number oldX, Number newX) {
- sketch.frameMoved(newX.intValue(), stage.yProperty().intValue());
- }
- });
-
- stage.yProperty().addListener(new ChangeListener() {
- @Override
- public void changed(ObservableValue extends Number> value,
- Number oldY, Number newY) {
- sketch.frameMoved(stage.xProperty().intValue(), newY.intValue());
- }
- });
-
- stage.setOnCloseRequest(new EventHandler() {
- public void handle(WindowEvent we) {
- sketch.exit();
- }
- });
- }
-
-
- public void setLocation(int x, int y) {
- stage.setX(x);
- stage.setY(y);
- }
-
-
- public void setSize(int wide, int high) {
- // When the surface is set to resizable via surface.setResizable(true),
- // a crash may occur if the user sets the window to size zero.
- // https://github.com/processing/processing/issues/5052
- if (high <= 0) {
- high = 1;
- }
- if (wide <= 0) {
- wide = 1;
- }
-
- //System.out.format("%s.setSize(%d, %d)%n", getClass().getSimpleName(), width, height);
- Scene scene = stage.getScene();
- double decorH = stage.getWidth() - scene.getWidth();
- double decorV = stage.getHeight() - scene.getHeight();
- stage.setWidth(wide + decorH);
- stage.setHeight(high + decorV);
- fx.setSize(wide, high);
- }
-
-
-// public Component getComponent() {
-// return null;
-// }
-
-
- public void setSmooth(int level) {
- // TODO Auto-generated method stub
-
- }
-
-
- public void setFrameRate(float fps) {
- // setting rate to negative so that event fires at the start of
- // the key frame and first frame is drawn immediately
- if (fps > 0) {
- frameRate = fps;
- animation.setRate(-frameRate);
- }
- }
-
-
-// @Override
-// public void requestFocus() {
-// canvas.requestFocus();
-// }
-
- Cursor lastCursor = Cursor.DEFAULT;
-
- public void setCursor(int kind) {
- Cursor c;
- switch (kind) {
- case PConstants.ARROW: c = Cursor.DEFAULT; break;
- case PConstants.CROSS: c = Cursor.CROSSHAIR; break;
- case PConstants.HAND: c = Cursor.HAND; break;
- case PConstants.MOVE: c = Cursor.MOVE; break;
- case PConstants.TEXT: c = Cursor.TEXT; break;
- case PConstants.WAIT: c = Cursor.WAIT; break;
- default: c = Cursor.DEFAULT; break;
- }
- lastCursor = c;
- canvas.getScene().setCursor(c);
- }
-
-
- public void setCursor(PImage image, int hotspotX, int hotspotY) {
- int w = image.pixelWidth;
- int h = image.pixelHeight;
- WritableImage im = new WritableImage(w, h);
- im.getPixelWriter().setPixels(0, 0, w, h,
- PixelFormat.getIntArgbInstance(),
- image.pixels,
- 0, w);
- ImageCursor c = new ImageCursor(im, hotspotX, hotspotY);
- lastCursor = c;
- canvas.getScene().setCursor(c);
- }
-
-
- public void showCursor() {
- canvas.getScene().setCursor(lastCursor);
- }
-
-
- public void hideCursor() {
- canvas.getScene().setCursor(Cursor.NONE);
- }
-
-
- public boolean openLink(String url) {
- return ShimAWT.openLink(url);
- }
-
-
- public void startThread() {
- animation.play();
- }
-
-
- public void pauseThread() {
- animation.pause();
- }
-
-
- public void resumeThread() {
- animation.play();
- }
-
-
- public boolean stopThread() {
- animation.stop();
- return true;
- }
-
-
- public boolean isStopped() {
- return animation.getStatus() == Animation.Status.STOPPED;
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /*
- protected void addListeners() {
-
- canvas.addMouseListener(new MouseListener() {
-
- public void mousePressed(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
-
- public void mouseReleased(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
-
- public void mouseClicked(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
-
- public void mouseEntered(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
-
- public void mouseExited(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
- });
-
- canvas.addMouseMotionListener(new MouseMotionListener() {
-
- public void mouseDragged(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
-
- public void mouseMoved(java.awt.event.MouseEvent e) {
- nativeMouseEvent(e);
- }
- });
-
- canvas.addMouseWheelListener(new MouseWheelListener() {
-
- public void mouseWheelMoved(MouseWheelEvent e) {
- nativeMouseEvent(e);
- }
- });
-
- canvas.addKeyListener(new KeyListener() {
-
- public void keyPressed(java.awt.event.KeyEvent e) {
- nativeKeyEvent(e);
- }
-
-
- public void keyReleased(java.awt.event.KeyEvent e) {
- nativeKeyEvent(e);
- }
-
-
- public void keyTyped(java.awt.event.KeyEvent e) {
- nativeKeyEvent(e);
- }
- });
-
- canvas.addFocusListener(new FocusListener() {
-
- public void focusGained(FocusEvent e) {
- sketch.focused = true;
- sketch.focusGained();
- }
-
- public void focusLost(FocusEvent e) {
- sketch.focused = false;
- sketch.focusLost();
- }
- });
- }
- */
-
-
- static Map, Integer> mouseMap =
- new HashMap<>();
- static {
- mouseMap.put(MouseEvent.MOUSE_PRESSED, processing.event.MouseEvent.PRESS);
- mouseMap.put(MouseEvent.MOUSE_RELEASED, processing.event.MouseEvent.RELEASE);
- mouseMap.put(MouseEvent.MOUSE_CLICKED, processing.event.MouseEvent.CLICK);
- mouseMap.put(MouseEvent.MOUSE_DRAGGED, processing.event.MouseEvent.DRAG);
- mouseMap.put(MouseEvent.MOUSE_MOVED, processing.event.MouseEvent.MOVE);
- mouseMap.put(MouseEvent.MOUSE_ENTERED, processing.event.MouseEvent.ENTER);
- mouseMap.put(MouseEvent.MOUSE_EXITED, processing.event.MouseEvent.EXIT);
- }
-
- protected void fxMouseEvent(MouseEvent fxEvent) {
- // the 'amount' is the number of button clicks for a click event,
- // or the number of steps/clicks on the wheel for a mouse wheel event.
- int count = fxEvent.getClickCount();
-
- int action = mouseMap.get(fxEvent.getEventType());
-
- int modifiers = 0;
- if (fxEvent.isShiftDown()) {
- modifiers |= processing.event.Event.SHIFT;
- }
- if (fxEvent.isControlDown()) {
- modifiers |= processing.event.Event.CTRL;
- }
- if (fxEvent.isMetaDown()) {
- modifiers |= processing.event.Event.META;
- }
- if (fxEvent.isAltDown()) {
- modifiers |= processing.event.Event.ALT;
- }
-
- int button = 0;
- switch (fxEvent.getButton()) {
- case PRIMARY:
- button = PConstants.LEFT;
- break;
- case SECONDARY:
- button = PConstants.RIGHT;
- break;
- case MIDDLE:
- button = PConstants.CENTER;
- break;
- case NONE:
- case BACK:
- case FORWARD:
- // not currently handled
- break;
- }
-
- //long when = nativeEvent.getWhen(); // from AWT
- long when = System.currentTimeMillis();
- int x = (int) fxEvent.getX(); // getSceneX()?
- int y = (int) fxEvent.getY();
-
- sketch.postEvent(new processing.event.MouseEvent(fxEvent, when,
- action, modifiers,
- x, y, button, count));
- }
-
- // https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/ScrollEvent.html
- protected void fxScrollEvent(ScrollEvent fxEvent) {
- // the number of steps/clicks on the wheel for a mouse wheel event.
- int count = (int) -(fxEvent.getDeltaY() / fxEvent.getMultiplierY());
-
- int action = processing.event.MouseEvent.WHEEL;
-
- int modifiers = 0;
- if (fxEvent.isShiftDown()) {
- modifiers |= processing.event.Event.SHIFT;
- }
- if (fxEvent.isControlDown()) {
- modifiers |= processing.event.Event.CTRL;
- }
- if (fxEvent.isMetaDown()) {
- modifiers |= processing.event.Event.META;
- }
- if (fxEvent.isAltDown()) {
- modifiers |= processing.event.Event.ALT;
- }
-
- // FX does not supply button info
- int button = 0;
-
- long when = System.currentTimeMillis();
- int x = (int) fxEvent.getX(); // getSceneX()?
- int y = (int) fxEvent.getY();
-
- sketch.postEvent(new processing.event.MouseEvent(fxEvent, when,
- action, modifiers,
- x, y, button, count));
- }
-
-
- protected void fxKeyEvent(javafx.scene.input.KeyEvent fxEvent) {
- int action = 0;
- EventType extends KeyEvent> et = fxEvent.getEventType();
- if (et == KeyEvent.KEY_PRESSED) {
- action = processing.event.KeyEvent.PRESS;
- } else if (et == KeyEvent.KEY_RELEASED) {
- action = processing.event.KeyEvent.RELEASE;
- } else if (et == KeyEvent.KEY_TYPED) {
- action = processing.event.KeyEvent.TYPE;
- }
-
- int modifiers = 0;
- if (fxEvent.isShiftDown()) {
- modifiers |= processing.event.Event.SHIFT;
- }
- if (fxEvent.isControlDown()) {
- modifiers |= processing.event.Event.CTRL;
- }
- if (fxEvent.isMetaDown()) {
- modifiers |= processing.event.Event.META;
- }
- if (fxEvent.isAltDown()) {
- modifiers |= processing.event.Event.ALT;
- }
-
- long when = System.currentTimeMillis();
-
- char keyChar = getKeyChar(fxEvent);
- int keyCode = getKeyCode(fxEvent);
- sketch.postEvent(new processing.event.KeyEvent(fxEvent, when,
- action, modifiers,
- keyChar, keyCode));
- }
-
-
- private int getKeyCode(KeyEvent fxEvent) {
- if (fxEvent.getEventType() == KeyEvent.KEY_TYPED) {
- return 0;
- }
-
- KeyCode kc = fxEvent.getCode();
- switch (kc) {
- case ALT_GRAPH:
- return PConstants.ALT;
- default:
- break;
- }
- return kc.getCode();
- }
-
-
- private char getKeyChar(KeyEvent fxEvent) {
- KeyCode kc = fxEvent.getCode();
-
- // Overriding chars for some
- // KEY_PRESSED and KEY_RELEASED events
- switch (kc) {
- case UP:
- case KP_UP:
- case DOWN:
- case KP_DOWN:
- case LEFT:
- case KP_LEFT:
- case RIGHT:
- case KP_RIGHT:
- case ALT:
- case ALT_GRAPH:
- case CONTROL:
- case SHIFT:
- case CAPS:
- case META:
- case WINDOWS:
- case CONTEXT_MENU:
- case HOME:
- case PAGE_UP:
- case PAGE_DOWN:
- case END:
- case PAUSE:
- case PRINTSCREEN:
- case INSERT:
- case NUM_LOCK:
- case SCROLL_LOCK:
- case F1:
- case F2:
- case F3:
- case F4:
- case F5:
- case F6:
- case F7:
- case F8:
- case F9:
- case F10:
- case F11:
- case F12:
- return PConstants.CODED;
- case ENTER:
- return '\n';
- case DIVIDE:
- return '/';
- case MULTIPLY:
- return '*';
- case SUBTRACT:
- return '-';
- case ADD:
- return '+';
- case NUMPAD0:
- return '0';
- case NUMPAD1:
- return '1';
- case NUMPAD2:
- return '2';
- case NUMPAD3:
- return '3';
- case NUMPAD4:
- return '4';
- case NUMPAD5:
- return '5';
- case NUMPAD6:
- return '6';
- case NUMPAD7:
- return '7';
- case NUMPAD8:
- return '8';
- case NUMPAD9:
- return '9';
- case DECIMAL:
- // KEY_TYPED does not go through here and will produce
- // dot or comma based on the keyboard layout.
- // For KEY_PRESSED and KEY_RELEASED, let's just go with
- // the dot. Users can detect the key by its keyCode.
- return '.';
- case UNDEFINED:
- // KEY_TYPED has KeyCode: UNDEFINED
- // and falls through here
- break;
- default:
- break;
- }
-
- // Just go with what FX gives us for the rest of
- // KEY_PRESSED and KEY_RELEASED and all of KEY_TYPED
- String ch;
- if (fxEvent.getEventType() == KeyEvent.KEY_TYPED) {
- ch = fxEvent.getCharacter();
- } else {
- ch = kc.getChar();
- }
-
- if (ch.length() < 1) return PConstants.CODED;
- if (ch.startsWith("\r")) return '\n'; // normalize enter key
- return ch.charAt(0);
- }
-}