diff --git a/core/src/processing/awt/PGraphicsJava2D.java b/core/src/processing/awt/PGraphicsJava2D.java index 4788de092..96f29d35b 100644 --- a/core/src/processing/awt/PGraphicsJava2D.java +++ b/core/src/processing/awt/PGraphicsJava2D.java @@ -409,8 +409,6 @@ public class PGraphicsJava2D extends PGraphics { checkSettings(); resetMatrix(); // reset model matrix vertexCount = 0; - - g2.scale(pixelDensity, pixelDensity); } @@ -1573,8 +1571,8 @@ public class PGraphicsJava2D extends PGraphics { // Nuke the cache if the image was resized if (cash != null) { - if (who.width != cash.image.getWidth() || - who.height != cash.image.getHeight()) { + if (who.pixelWidth != cash.image.getWidth() || + who.pixelHeight != cash.image.getHeight()) { cash = null; } } @@ -1601,12 +1599,17 @@ public class PGraphicsJava2D extends PGraphics { // 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.width * who.height]; + 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; + g2.drawImage(((ImageCache) getCache(who)).image, (int) x1, (int) y1, (int) x2, (int) y2, u1, v1, u2, v2, null); @@ -1674,14 +1677,14 @@ public class PGraphicsJava2D extends PGraphics { // 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, + image = new BufferedImage(source.pixelWidth, source.pixelHeight, BufferedImage.TYPE_INT_ARGB); } WritableRaster wr = image.getRaster(); if (tint) { - if (tintedTemp == null || tintedTemp.length != source.width) { - tintedTemp = new int[source.width]; + if (tintedTemp == null || tintedTemp.length != source.pixelWidth) { + tintedTemp = new int[source.pixelHeight]; } int a2 = (tintColor >> 24) & 0xff; // System.out.println("tint color is " + a2); @@ -1695,8 +1698,8 @@ public class PGraphicsJava2D extends PGraphics { // 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.height; y++) { - for (int x = 0; x < source.width; x++) { + 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; @@ -1710,7 +1713,7 @@ public class PGraphicsJava2D extends PGraphics { ((g2 * g1) & 0xff00) | (((b2 * b1) & 0xff00) >> 8); } - wr.setDataElements(0, y, source.width, 1, tintedTemp); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } // could this be any slower? // float[] scales = { tintR, tintG, tintB }; @@ -1724,18 +1727,18 @@ public class PGraphicsJava2D extends PGraphics { (tintColor & 0xffffff) == 0xffffff) { int hi = tintColor & 0xff000000; int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + 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); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } } else { int index = 0; - for (int y = 0; y < source.height; y++) { + for (int y = 0; y < source.pixelHeight; y++) { if (source.format == RGB) { int alpha = tintColor & 0xFF000000; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1746,7 +1749,7 @@ public class PGraphicsJava2D extends PGraphics { (((b2 * b1) & 0xff00) >> 8); } } else if (source.format == ARGB) { - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int a1 = (argb1 >> 24) & 0xff; int r1 = (argb1 >> 16) & 0xff; @@ -1760,13 +1763,13 @@ public class PGraphicsJava2D extends PGraphics { } } else if (source.format == ALPHA) { int lower = tintColor & 0xFFFFFF; - for (int x = 0; x < source.width; x++) { + 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); + wr.setDataElements(0, y, source.pixelWidth, 1, tintedTemp); } } // Not sure why ARGB images take the scales in this order... @@ -1786,7 +1789,7 @@ public class PGraphicsJava2D extends PGraphics { // 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); + wr.setDataElements(0, 0, source.pixelWidth, source.pixelHeight, source.pixels); } this.tinted = tint; this.tintedColor = tintColor; @@ -2232,6 +2235,7 @@ public class PGraphicsJava2D extends PGraphics { @Override public void resetMatrix() { g2.setTransform(new AffineTransform()); + g2.scale(pixelDensity, pixelDensity); } @@ -2793,7 +2797,7 @@ public class PGraphicsJava2D extends PGraphics { if (pixels != null) { getRaster().setDataElements(0, 0, pixelWidth, pixelHeight, pixels); } - modified = true; + modified = false; } @@ -2836,12 +2840,6 @@ public class PGraphicsJava2D extends PGraphics { //public PImage get(int x, int y, int w, int h) - @Override - public PImage get() { - return get(0, 0, width, height); - } - - @Override protected void getImpl(int sourceX, int sourceY, int sourceWidth, int sourceHeight, @@ -2852,7 +2850,7 @@ public class PGraphicsJava2D extends PGraphics { // ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); WritableRaster raster = getRaster(); - if (sourceWidth == target.width && sourceHeight == target.height) { + if (sourceWidth == target.pixelWidth && sourceHeight == target.pixelHeight) { raster.getDataElements(sourceX, sourceY, sourceWidth, sourceHeight, target.pixels); // https://github.com/processing/processing/issues/2030 if (raster.getNumBands() == 3) { @@ -2866,7 +2864,7 @@ public class PGraphicsJava2D extends PGraphics { // Copy the temporary output pixels over to the outgoing image int sourceOffset = 0; - int targetOffset = targetY*target.width + targetX; + int targetOffset = targetY*target.pixelWidth + targetX; for (int y = 0; y < sourceHeight; y++) { if (raster.getNumBands() == 3) { for (int i = 0; i < sourceWidth; i++) { @@ -2878,7 +2876,7 @@ public class PGraphicsJava2D extends PGraphics { System.arraycopy(temp, sourceOffset, target.pixels, targetOffset, sourceWidth); } sourceOffset += sourceWidth; - targetOffset += target.width; + targetOffset += target.pixelWidth; } } } @@ -2886,7 +2884,7 @@ public class PGraphicsJava2D extends PGraphics { @Override public void set(int x, int y, int argb) { - if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return; + if ((x < 0) || (y < 0) || (x >= pixelWidth) || (y >= pixelHeight)) return; // ((BufferedImage) image).setRGB(x, y, argb); getset[0] = argb; // WritableRaster raster = ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); @@ -2907,18 +2905,18 @@ public class PGraphicsJava2D extends PGraphics { // ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster(); if ((sourceX == 0) && (sourceY == 0) && - (sourceWidth == sourceImage.width) && - (sourceHeight == sourceImage.height)) { + (sourceWidth == sourceImage.pixelWidth) && + (sourceHeight == sourceImage.pixelHeight)) { // System.out.format("%d %d %dx%d %d%n", targetX, targetY, // sourceImage.width, sourceImage.height, // sourceImage.pixels.length); raster.setDataElements(targetX, targetY, - sourceImage.width, sourceImage.height, + sourceImage.pixelWidth, sourceImage.pixelHeight, sourceImage.pixels); } else { // TODO optimize, incredibly inefficient to reallocate this much memory PImage temp = sourceImage.get(sourceX, sourceY, sourceWidth, sourceHeight); - raster.setDataElements(targetX, targetY, temp.width, temp.height, temp.pixels); + raster.setDataElements(targetX, targetY, temp.pixelWidth, temp.pixelHeight, temp.pixels); } } diff --git a/core/src/processing/awt/PSurfaceAWT.java b/core/src/processing/awt/PSurfaceAWT.java index cd4649436..27c7b8e6b 100644 --- a/core/src/processing/awt/PSurfaceAWT.java +++ b/core/src/processing/awt/PSurfaceAWT.java @@ -90,6 +90,8 @@ public class PSurfaceAWT extends PSurfaceNone { int sketchWidth; int sketchHeight; + int windowScaleFactor; + public PSurfaceAWT(PGraphics graphics) { //this.graphics = graphics; @@ -224,7 +226,7 @@ public class PSurfaceAWT extends PSurfaceNone { if (!oldSize.equals(newSize)) { // System.out.println("validate() render old=" + oldSize + " -> new=" + newSize); oldSize = newSize; - sketch.setSize(newSize.width, newSize.height); + sketch.setSize(newSize.width / windowScaleFactor, newSize.height / windowScaleFactor); // try { render(); // } catch (IllegalStateException ise) { @@ -423,8 +425,11 @@ public class PSurfaceAWT extends PSurfaceNone { sketch.displayWidth = screenRect.width; sketch.displayHeight = screenRect.height; - sketchWidth = sketch.sketchWidth(); - sketchHeight = sketch.sketchHeight(); + windowScaleFactor = PApplet.platform == PConstants.MACOSX ? + 1 : sketch.pixelDensity; + + sketchWidth = sketch.sketchWidth() * windowScaleFactor; + sketchHeight = sketch.sketchHeight() * windowScaleFactor; boolean fullScreen = sketch.sketchFullScreen(); // Removing the section below because sometimes people want to do the @@ -481,7 +486,7 @@ public class PSurfaceAWT extends PSurfaceNone { // http://dev.processing.org/bugs/show_bug.cgi?id=908 frame.add(canvas); - setSize(sketchWidth, sketchHeight); + setSize(sketchWidth / windowScaleFactor, sketchHeight / windowScaleFactor); /* if (fullScreen) { @@ -954,8 +959,8 @@ public class PSurfaceAWT extends PSurfaceNone { return; // unchanged, don't rebuild everything } - sketchWidth = wide; - sketchHeight = high; + sketchWidth = wide * windowScaleFactor; + sketchHeight = high * windowScaleFactor; // canvas.setSize(wide, high); // frame.setSize(wide, high); @@ -1142,8 +1147,9 @@ public class PSurfaceAWT extends PSurfaceNone { // overall size of the window. Perhaps JFrame sets its coord // system so that (0, 0) is always the upper-left of the content // area. Which seems nice, but breaks any f*ing AWT-based code. - setSize(windowSize.width - currentInsets.left - currentInsets.right, - windowSize.height - currentInsets.top - currentInsets.bottom); + int w = windowSize.width - currentInsets.left - currentInsets.right; + int h = windowSize.height - currentInsets.top - currentInsets.bottom; + setSize(w / windowScaleFactor, h / windowScaleFactor); // correct the location when inset size changes setLocation(x - currentInsets.left, y - currentInsets.top); @@ -1312,7 +1318,8 @@ public class PSurfaceAWT extends PSurfaceNone { sketch.postEvent(new MouseEvent(nativeEvent, nativeEvent.getWhen(), peAction, peModifiers, - nativeEvent.getX(), nativeEvent.getY(), + nativeEvent.getX() / windowScaleFactor, + nativeEvent.getY() / windowScaleFactor, peButton, peCount)); } diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 0cc144d98..54a930388 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -790,6 +790,8 @@ public class PApplet implements PConstants { */ static public final String ARGS_SKETCH_FOLDER = "--sketch-path"; + static public final String ARGS_DENSITY = "--density"; + /** * When run externally to a PdeEditor, * this is sent by the sketch when it quits. @@ -909,6 +911,9 @@ public class PApplet implements PConstants { // Unlike the others above, needs to be public to support // the pixelWidth and pixelHeight fields. public int pixelDensity = 1; + int suggestedDensity = -1; + + boolean present; String outputPath; OutputStream outputStream; @@ -1128,23 +1133,23 @@ public class PApplet implements PConstants { * @see PApplet#size(int,int) */ public int displayDensity() { - if (display == SPAN) { - // walk through all displays, use lowest common denominator - for (int i = 0; i < displayDevices.length; i++) { - if (displayDensity(i) != 2) { - return 1; - } - } - // If nobody's density is 1 (or != 2, to be exact) then everyone is 2 - return 2; + if (display != SPAN && (fullScreen || present)) { + return displayDensity(display); } - return displayDensity(display); + // walk through all displays, use 2 if any display is 2 + for (int i = 0; i < displayDevices.length; i++) { + if (displayDensity(i+1) == 2) { + return 2; + } + } + // If nobody's density is 2 then everyone is 1 + return 1; } /** * @param display the display number to check */ - static public int displayDensity(int display) { + public int displayDensity(int display) { if (PApplet.platform == PConstants.MACOSX) { // This should probably be reset each time there's a display change. // A 5-minute search didn't turn up any such event in the Java 7 API. @@ -1187,6 +1192,15 @@ public class PApplet implements PConstants { } } catch (Exception ignore) { } } + } else if (PApplet.platform == PConstants.WINDOWS || + PApplet.platform == PConstants.LINUX) { + if (suggestedDensity == -1) { + // TODO: detect and return DPI scaling using JNA; Windows has + // a system-wide value, not sure how it works on Linux + return 1; + } else if (suggestedDensity == 1 || suggestedDensity == 2) { + return suggestedDensity; + } } return 1; } @@ -1204,9 +1218,11 @@ public class PApplet implements PConstants { if (density != 1 && density != 2) { throw new RuntimeException("pixelDensity() can only be 1 or 2"); } - if (density == 2 && displayDensity() == 1) { + if (!FX2D.equals(renderer) && density == 2 && displayDensity() == 1) { + // FX has its own check in PSurfaceFX // Don't throw exception because the sketch should still work - throw new RuntimeException("pixelDensity(2) is not available for this display"); + System.err.println("pixelDensity(2) is not available for this display"); + this.pixelDensity = 1; } else { this.pixelDensity = density; } @@ -10390,6 +10406,7 @@ public class PApplet implements PConstants { // boolean fullScreen = false; boolean present = false; // boolean spanDisplays = false; + int density = -1; String param = null, value = null; String folder = calcSketchPath(); @@ -10432,6 +10449,15 @@ public class PApplet implements PConstants { } else if (param.equals(ARGS_LOCATION)) { location = parseInt(split(value, ',')); + + } else if (param.equals(ARGS_DENSITY)) { + density = parseInt(value, -1); + if (density == -1) { + System.err.println("Could not parse " + value + " for " + ARGS_DENSITY); + } else if (density != 1 && density != 2) { + density = -1; + System.err.println(ARGS_DENSITY + " should be 1 or 2"); + } } } else { @@ -10500,6 +10526,12 @@ public class PApplet implements PConstants { // (and most likely, from the PDE's preference setting). sketch.display = displayNum; + // Set the suggested density that is coming from command line + // (most likely set from the PDE based on a system DPI scaling) + sketch.suggestedDensity = density; + + sketch.present = present; + // For 3.0.1, moved this above handleSettings() so that loadImage() can be // used inside settings(). Sets a terrible precedent, but the alternative // of not being able to size a sketch to an image is driving people loopy. diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 02b9919c7..a4425e1d8 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -3879,6 +3879,11 @@ public class PGraphics extends PImage implements PConstants { // fillA = 1; // } + u1 *= img.pixelDensity; + u2 *= img.pixelDensity; + v1 *= img.pixelDensity; + v2 *= img.pixelDensity; + beginShape(QUADS); texture(img); vertex(x1, y1, u1, v1); @@ -7347,7 +7352,7 @@ public class PGraphics extends PImage implements PConstants { * @param image PImage to set as background (must be same size as the sketch window) */ public void background(PImage image) { - if ((image.width != width) || (image.height != height)) { + if ((image.pixelWidth != pixelWidth) || (image.pixelHeight != pixelHeight)) { throw new RuntimeException(ERROR_BACKGROUND_IMAGE_SIZE); } if ((image.format != RGB) && (image.format != ARGB)) { diff --git a/core/src/processing/javafx/PGraphicsFX2D.java b/core/src/processing/javafx/PGraphicsFX2D.java index 52425e3c7..157540fed 100644 --- a/core/src/processing/javafx/PGraphicsFX2D.java +++ b/core/src/processing/javafx/PGraphicsFX2D.java @@ -645,9 +645,27 @@ public class PGraphicsFX2D extends PGraphics { int mw = mx2 - mx1; int mh = my2 - my1; - PixelWriter pw = context.getPixelWriter(); - pw.setPixels(mx1, my1, mw, mh, argbFormat, pixels, - mx1 + my1 * pixelWidth, pixelWidth); + 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; @@ -1013,8 +1031,8 @@ public class PGraphicsFX2D extends PGraphics { // Nuke the cache if the image was resized if (cash != null) { - if (who.width != cash.image.getWidth() || - who.height != cash.image.getHeight()) { + if (who.pixelWidth != cash.image.getWidth() || + who.pixelHeight != cash.image.getHeight()) { cash = null; } } @@ -1041,12 +1059,17 @@ public class PGraphicsFX2D extends PGraphics { // 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.width * who.height]; + 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); @@ -1087,14 +1110,14 @@ public class PGraphicsFX2D extends PGraphics { // BufferedImage.TYPE_INT_ARGB); // } if (image == null) { - image = new WritableImage(source.width, source.height); + image = new WritableImage(source.pixelWidth, source.pixelHeight); } //WritableRaster wr = image.getRaster(); PixelWriter pw = image.getPixelWriter(); if (tint) { - if (tintedTemp == null || tintedTemp.length != source.width) { - tintedTemp = new int[source.width]; + if (tintedTemp == null || tintedTemp.length != source.pixelWidth) { + tintedTemp = new int[source.pixelWidth]; } int a2 = (tintColor >> 24) & 0xff; // System.out.println("tint color is " + a2); @@ -1108,8 +1131,8 @@ public class PGraphicsFX2D extends PGraphics { // 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.height; y++) { - for (int x = 0; x < source.width; x++) { + 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; @@ -1124,7 +1147,7 @@ public class PGraphicsFX2D extends PGraphics { (((b2 * b1) & 0xff00) >> 8); } //wr.setDataElements(0, y, source.width, 1, tintedTemp); - pw.setPixels(0, y, source.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth); } // could this be any slower? // float[] scales = { tintR, tintG, tintB }; @@ -1138,19 +1161,19 @@ public class PGraphicsFX2D extends PGraphics { (tintColor & 0xffffff) == 0xffffff) { int hi = tintColor & 0xff000000; int index = 0; - for (int y = 0; y < source.height; y++) { - for (int x = 0; x < source.width; x++) { + 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.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelHeight); } } else { int index = 0; - for (int y = 0; y < source.height; y++) { + for (int y = 0; y < source.pixelHeight; y++) { if (source.format == RGB) { int alpha = tintColor & 0xFF000000; - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int r1 = (argb1 >> 16) & 0xff; int g1 = (argb1 >> 8) & 0xff; @@ -1161,7 +1184,7 @@ public class PGraphicsFX2D extends PGraphics { (((b2 * b1) & 0xff00) >> 8); } } else if (source.format == ARGB) { - for (int x = 0; x < source.width; x++) { + for (int x = 0; x < source.pixelWidth; x++) { int argb1 = source.pixels[index++]; int a1 = (argb1 >> 24) & 0xff; int r1 = (argb1 >> 16) & 0xff; @@ -1175,14 +1198,14 @@ public class PGraphicsFX2D extends PGraphics { } } else if (source.format == ALPHA) { int lower = tintColor & 0xFFFFFF; - for (int x = 0; x < source.width; x++) { + 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.width, 1, argbFormat, tintedTemp, 0, source.width); + pw.setPixels(0, y, source.pixelWidth, 1, argbFormat, tintedTemp, 0, source.pixelWidth); } } // Not sure why ARGB images take the scales in this order... @@ -1204,8 +1227,8 @@ public class PGraphicsFX2D extends PGraphics { // 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.width, source.height, - argbFormat, source.pixels, 0, source.width); + pw.setPixels(0, 0, source.pixelWidth, source.pixelHeight, + argbFormat, source.pixels, 0, source.pixelWidth); } this.tinted = tint; this.tintedColor = tintColor; @@ -2133,8 +2156,9 @@ public class PGraphicsFX2D extends PGraphics { snapshotImage = new WritableImage(pixelWidth, pixelHeight); } - SnapshotParameters sp = new SnapshotParameters(); + SnapshotParameters sp = null; if (pixelDensity != 1) { + sp = new SnapshotParameters(); sp.setTransform(Transform.scale(pixelDensity, pixelDensity)); } snapshotImage = ((PSurfaceFX) surface).canvas.snapshot(sp, snapshotImage); diff --git a/core/src/processing/javafx/PSurfaceFX.java b/core/src/processing/javafx/PSurfaceFX.java index 8239c8f5b..14938445d 100644 --- a/core/src/processing/javafx/PSurfaceFX.java +++ b/core/src/processing/javafx/PSurfaceFX.java @@ -22,6 +22,8 @@ package processing.javafx; +import com.sun.glass.ui.Screen; + import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; @@ -244,6 +246,19 @@ public class PSurfaceFX implements PSurface { PApplet sketch = surface.sketch; + float renderScale = Screen.getMainScreen().getRenderScale(); + if (PApplet.platform == PConstants.MACOSX) { + for (Screen s : Screen.getScreens()) { + renderScale = Math.max(renderScale, s.getRenderScale()); + } + } + float uiScale = Screen.getMainScreen().getUIScale(); + 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; @@ -286,17 +301,8 @@ public class PSurfaceFX implements PSurface { maxY = Math.max(maxY, bounds.getMaxY()); } } - if (minY < 0) { - // FX can't handle this - System.err.format("FX can't place window at negative Y coordinate " + - "[x=%d, y=%d]. Please make sure that your secondary " + - "display does not extend above the main display.", - (int) minX, (int) minY); - screenRect = primaryScreenRect; - } else { - screenRect = new Rectangle((int) minX, (int) minY, - (int) (maxX - minX), (int) (maxY - minY)); - } + screenRect = new Rectangle((int) minX, (int) minY, + (int) (maxX - minX), (int) (maxY - minY)); } // Set the displayWidth/Height variables inside PApplet, so that they're @@ -308,14 +314,14 @@ public class PSurfaceFX implements PSurface { int sketchHeight = sketch.sketchHeight(); if (fullScreen || spanDisplays) { - sketchWidth = (int) screenRect.getWidth(); - sketchHeight = (int) screenRect.getHeight(); + sketchWidth = (int) (screenRect.getWidth() / uiScale); + sketchHeight = (int) (screenRect.getHeight() / uiScale); stage.initStyle(StageStyle.UNDECORATED); - stage.setX(screenRect.getMinX()); - stage.setY(screenRect.getMinY()); - stage.setWidth(screenRect.getWidth()); - stage.setHeight(screenRect.getHeight()); + stage.setX(screenRect.getMinX() / uiScale); + stage.setY(screenRect.getMinY() / uiScale); + stage.setWidth(screenRect.getWidth() / uiScale); + stage.setHeight(screenRect.getHeight() / uiScale); } Canvas canvas = surface.canvas; @@ -540,12 +546,9 @@ public class PSurfaceFX implements PSurface { public void placeWindow(int[] location, int[] editorLocation) { if (sketch.sketchFullScreen()) { PApplet.hideMenuBar(); + return; } - //Dimension window = setFrameSize(); -// int contentW = Math.max(sketchWidth, MIN_WINDOW_WIDTH); -// int contentH = Math.max(sketchHeight, MIN_WINDOW_HEIGHT); -// System.out.println("stage size is " + stage.getWidth() + " " + stage.getHeight()); int wide = sketch.width; // stage.getWidth() is NaN here int high = sketch.height; // stage.getHeight() @@ -565,42 +568,10 @@ public class PSurfaceFX implements PSurface { stage.setY(locationY); } else { // doesn't fit -// // if it fits inside the editor window, -// // offset slightly from upper lefthand corner -// // so that it's plunked inside the text area -// locationX = editorLocation[0] + 66; -// locationY = editorLocation[1] + 66; -// -// if ((locationX + stage.getWidth() > sketch.displayWidth - 33) || -// (locationY + stage.getHeight() > sketch.displayHeight - 33)) { -// // otherwise center on screen -// locationX = (int) ((sketch.displayWidth - wide) / 2); -// locationY = (int) ((sketch.displayHeight - high) / 2); -// } - locationX = (sketch.displayWidth - wide) / 2; - locationY = (sketch.displayHeight - high) / 2; - stage.setX(locationX); - stage.setY(locationY); + stage.centerOnScreen(); } } else { // just center on screen - //setFrameCentered(); - } - 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); - } - - //canvas.setBounds((contentW - sketchWidth)/2, - // (contentH - sketchHeight)/2, - // sketchWidth, sketchHeight); - - // handle frame resizing events - //setupFrameResizeListener(); - - if (sketch.getGraphics().displayable()) { - setVisible(true); + stage.centerOnScreen(); } } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index eeebcc9cc..9ecf2fadc 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -637,6 +637,9 @@ public class PGraphicsOpenGL extends PGraphics { height = iheight; updatePixelSize(); + texture = null; + ptexture = null; + // init perspective projection based on new dimensions defCameraFOV = 60 * DEG_TO_RAD; // at least for now defCameraX = width / 2.0f; @@ -692,6 +695,10 @@ public class PGraphicsOpenGL extends PGraphics { float f = pgl.getPixelScale(); pixelWidth = (int)(width * f); pixelHeight = (int)(height * f); + if (primaryGraphics) { + parent.pixelWidth = pixelWidth; + parent.pixelHeight = pixelHeight; + } } @@ -2140,8 +2147,8 @@ public class PGraphicsOpenGL extends PGraphics { } if (textured && textureMode == IMAGE) { - u /= textureImage.width; - v /= textureImage.height; + u /= textureImage.pixelWidth; + v /= textureImage.pixelHeight; } inGeo.addVertex(x, y, z, @@ -5417,30 +5424,29 @@ public class PGraphicsOpenGL extends PGraphics { protected void drawPixels(int x, int y, int w, int h) { - int f = (int)pgl.getPixelScale(); - int len = f * w * f * h; + int len = w * h; if (nativePixels == null || nativePixels.length < len) { nativePixels = new int[len]; nativePixelBuffer = PGL.allocateIntBuffer(nativePixels); } try { - if (0 < x || 0 < y || w < width || h < height) { + if (0 < x || 0 < y || w < pixelWidth || h < pixelHeight) { // The pixels to be copied to the texture need to be consecutive, and // they are not in the pixels array, so putting each row one after // another in nativePixels. - int offset0 = f * (y * width + x); + int offset0 = y * pixelWidth + x; int offset1 = 0; - for (int yc = f * y; yc < f * (y + h); yc++) { - System.arraycopy(pixels, offset0, nativePixels, offset1, f * w); - offset0 += f * width; - offset1 += f * w; + for (int yc = y; yc < y + h; yc++) { + System.arraycopy(pixels, offset0, nativePixels, offset1, w); + offset0 += pixelWidth; + offset1 += w; } } else { PApplet.arrayCopy(pixels, 0, nativePixels, 0, len); } - PGL.javaToNativeARGB(nativePixels, f * w, f * h); + PGL.javaToNativeARGB(nativePixels, w, h); } catch (ArrayIndexOutOfBoundsException e) { } PGL.putIntArray(nativePixelBuffer, nativePixels); @@ -5464,10 +5470,10 @@ public class PGraphicsOpenGL extends PGraphics { // (off)screen buffer. // First, copy the pixels to the texture. We don't need to invert the // pixel copy because the texture will be drawn inverted. - int tw = PApplet.min(texture.glWidth - f * x, f * w); - int th = PApplet.min(texture.glHeight - f * y, f * h); + int tw = PApplet.min(texture.glWidth - x, w); + int th = PApplet.min(texture.glHeight - y, h); pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName, - f * x, f * y, tw, th, nativePixelBuffer); + x, y, tw, th, nativePixelBuffer); beginPixelsOp(OP_WRITE); drawTexture(x, y, w, h); endPixelsOp(); @@ -5476,7 +5482,7 @@ public class PGraphicsOpenGL extends PGraphics { // currently drawing to. Because the texture is invertex along Y, we // need to reflect that in the vertical arguments. pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName, - f * x, f * (height - (y + h)), f * w, f * h, nativePixelBuffer); + x, pixelHeight - (y + h), w, h, nativePixelBuffer); } } @@ -5549,10 +5555,10 @@ public class PGraphicsOpenGL extends PGraphics { @Override protected void processImageBeforeAsyncSave(PImage image) { if (image.format == AsyncPixelReader.OPENGL_NATIVE) { - PGL.nativeToJavaARGB(image.pixels, image.width, image.height); + PGL.nativeToJavaARGB(image.pixels, image.pixelWidth, image.pixelHeight); image.format = ARGB; } else if (image.format == AsyncPixelReader.OPENGL_NATIVE_OPAQUE) { - PGL.nativeToJavaRGB(image.pixels, image.width, image.height); + PGL.nativeToJavaRGB(image.pixels, image.pixelWidth, image.pixelHeight); image.format = RGB; } } @@ -5960,9 +5966,9 @@ public class PGraphicsOpenGL extends PGraphics { pgl.disable(PGL.BLEND); pgl.drawTexture(texture.glTarget, texture.glName, texture.glWidth, texture.glHeight, - 0, 0, width, height, + 0, 0, pixelWidth, pixelHeight, 1, x, y, x + w, y + h, - x, height - (y + h), x + w, height - y); + x, pixelHeight - (y + h), x + w, pixelHeight - y); pgl.enable(PGL.BLEND); } } @@ -5997,7 +6003,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void mask(PImage alpha) { updatePixelSize(); - if (alpha.width != pixelWidth || alpha.height != pixelHeight) { + if (alpha.pixelWidth != pixelWidth || alpha.pixelHeight != pixelHeight) { throw new RuntimeException("The PImage used with mask() must be " + "the same size as the applet."); } @@ -6358,8 +6364,8 @@ public class PGraphicsOpenGL extends PGraphics { if (tex == null) return null; if (img.isModified()) { - if (img.width != tex.width || img.height != tex.height) { - tex.init(img.width, img.height); + if (img.pixelWidth != tex.width || img.pixelHeight != tex.height) { + tex.init(img.pixelWidth, img.pixelHeight); } updateTexture(img, tex); } @@ -6485,8 +6491,8 @@ public class PGraphicsOpenGL extends PGraphics { // avoid initializing the pixels array. PImage img = new PImage(); img.parent = parent; - img.width = tex.width; - img.height = tex.height; + img.width = img.pixelWidth = tex.width; + img.height = img.pixelHeight = tex.height; img.format = ARGB; setCache(img, tex); return img; diff --git a/core/src/processing/opengl/PSurfaceJOGL.java b/core/src/processing/opengl/PSurfaceJOGL.java index 75c792281..4bdbe7441 100644 --- a/core/src/processing/opengl/PSurfaceJOGL.java +++ b/core/src/processing/opengl/PSurfaceJOGL.java @@ -94,8 +94,6 @@ public class PSurfaceJOGL implements PSurface { protected PApplet sketch; protected PGraphics graphics; - protected int sketchX; - protected int sketchY; protected int sketchWidth0; protected int sketchHeight0; protected int sketchWidth; @@ -103,13 +101,14 @@ public class PSurfaceJOGL implements PSurface { protected Display display; protected Screen screen; - protected List monitors; - protected MonitorDevice displayDevice; + protected Rectangle displayRect; protected Throwable drawException; private final Object drawExceptionMutex = new Object(); protected NewtCanvasAWT canvas; + protected int windowScaleFactor; + protected float[] currentPixelScale = {0, 0}; protected boolean external = false; @@ -151,103 +150,35 @@ public class PSurfaceJOGL implements PSurface { protected void initDisplay() { - Display tmpDisplay = NewtFactory.createDisplay(null); - tmpDisplay.addReference(); - Screen tmpScreen = NewtFactory.createScreen(tmpDisplay, 0); - tmpScreen.addReference(); + display = NewtFactory.createDisplay(null); + display.addReference(); + screen = NewtFactory.createScreen(display, 0); + screen.addReference(); - monitors = new ArrayList(); GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] awtDevices = environment.getScreenDevices(); - List newtDevices = tmpScreen.getMonitorDevices(); - // AWT and NEWT name devices in different ways, depending on the platform, - // and also appear to order them in different ways. The following code - // tries to address the differences. - if (PApplet.platform == PConstants.LINUX) { - for (GraphicsDevice device: awtDevices) { - String did = device.getIDstring(); - String[] parts = did.split("\\."); - String id1 = ""; - if (1 < parts.length) { - id1 = parts[1].trim(); - } - MonitorDevice monitor = null; - int id0 = newtDevices.size() > 0 ? newtDevices.get(0).getId() : 0; - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId() - id0); - if (id1.equals(mid)) { - monitor = mon; - break; - } - } - if (monitor != null) { - monitors.add(monitor); - } - } - } else if (PApplet.platform == PConstants.WINDOWS) { - // NEWT display id is == (adapterId << 8 | monitorId), - // should be in the same order as AWT - monitors.addAll(newtDevices); - } else { // MAC OSX and others - for (GraphicsDevice device: awtDevices) { - String did = device.getIDstring(); - String[] parts = did.split("Display"); - String id1 = ""; - if (1 < parts.length) { - id1 = parts[1].trim(); - } - MonitorDevice monitor = null; - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId()); - if (id1.equals(mid)) { - monitor = mon; - break; - } - } - if (monitor == null) { - // Didn't find a matching monitor, try using less stringent id check - for (int i = 0; i < newtDevices.size(); i++) { - MonitorDevice mon = newtDevices.get(i); - String mid = String.valueOf(mon.getId()); - if (-1 < did.indexOf(mid)) { - monitor = mon; - break; - } - } - } - if (monitor != null) { - monitors.add(monitor); - } - } - } - - displayDevice = null; + GraphicsDevice awtDisplayDevice = null; int displayNum = sketch.sketchDisplay(); if (displayNum > 0) { // if -1, use the default device - if (displayNum <= monitors.size()) { - displayDevice = monitors.get(displayNum - 1); + if (displayNum <= awtDevices.length) { + awtDisplayDevice = awtDevices[displayNum-1]; } else { System.err.format("Display %d does not exist, " + "using the default display instead.%n", displayNum); - for (int i = 0; i < monitors.size(); i++) { - System.err.format("Display %d is %s%n", i+1, monitors.get(i)); + for (int i = 0; i < awtDevices.length; i++) { + System.err.format("Display %d is %s%n", i+1, awtDevices[i]); } } - } else if (0 < monitors.size()) { - displayDevice = monitors.get(0); + } else if (0 < awtDevices.length) { + awtDisplayDevice = awtDevices[0]; } - if (displayDevice != null) { - screen = displayDevice.getScreen(); - display = screen.getDisplay(); - } else { - screen = tmpScreen; - display = tmpDisplay; - displayDevice = screen.getPrimaryMonitor(); + if (awtDisplayDevice == null) { + awtDisplayDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); } + + displayRect = awtDisplayDevice.getDefaultConfiguration().getBounds(); } @@ -330,13 +261,15 @@ public class PSurfaceJOGL implements PSurface { // window = GLWindow.create(displayDevice.getScreen(), pgl.getCaps()); // } + windowScaleFactor = PApplet.platform == PConstants.MACOSX ? + 1 : sketch.pixelDensity; boolean spanDisplays = sketch.sketchDisplay() == PConstants.SPAN; screenRect = spanDisplays ? - new Rectangle(0, 0, screen.getWidth(), screen.getHeight()) : - new Rectangle(0, 0, - displayDevice.getViewportInWindowUnits().getWidth(), - displayDevice.getViewportInWindowUnits().getHeight()); + new Rectangle(screen.getX(), screen.getY(), screen.getWidth(), screen.getHeight()) : + new Rectangle((int) displayRect.getX(), (int) displayRect.getY(), + (int) displayRect.getWidth(), + (int) displayRect.getHeight()); // Set the displayWidth/Height variables inside PApplet, so that they're // usable and can even be returned by the sketchWidth()/Height() methods. @@ -385,12 +318,14 @@ public class PSurfaceJOGL implements PSurface { */ if (fullScreen || spanDisplays) { - sketchWidth = screenRect.width; - sketchHeight = screenRect.height; + sketchWidth = screenRect.width / windowScaleFactor; + sketchHeight = screenRect.height / windowScaleFactor; } + sketch.setSize(sketchWidth, sketchHeight); + float[] reqSurfacePixelScale; - if (graphics.is2X()) { + if (graphics.is2X() && PApplet.platform == PConstants.MACOSX) { // Retina reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; @@ -400,19 +335,17 @@ public class PSurfaceJOGL implements PSurface { ScalableSurface.IDENTITY_PIXELSCALE }; } window.setSurfaceScale(reqSurfacePixelScale); - window.setSize(sketchWidth, sketchHeight); + window.setSize(sketchWidth * windowScaleFactor, sketchHeight * windowScaleFactor); window.setResizable(false); setSize(sketchWidth, sketchHeight); - sketchX = displayDevice.getViewportInWindowUnits().getX(); - sketchY = displayDevice.getViewportInWindowUnits().getY(); if (fullScreen) { PApplet.hideMenuBar(); - window.setTopLevelPosition(sketchX, sketchY); if (spanDisplays) { - window.setFullscreen(monitors); + window.setFullscreen(screen.getMonitorDevices()); } else { - List display = Collections.singletonList(displayDevice); - window.setFullscreen(display); + window.setUndecorated(true); + window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY()); + window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight()); } } } @@ -688,6 +621,11 @@ public class PSurfaceJOGL implements PSurface { @Override public void placeWindow(int[] location, int[] editorLocation) { + + if (sketch.sketchFullScreen()) { + return; + } + int x = window.getX() - window.getInsets().getLeftWidth(); int y = window.getY() - window.getInsets().getTopHeight(); int w = window.getWidth() + window.getInsets().getTotalWidth(); @@ -728,10 +666,8 @@ public class PSurfaceJOGL implements PSurface { } 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. - int sketchX = displayDevice.getViewportInWindowUnits().getX(); - int sketchY = displayDevice.getViewportInWindowUnits().getY(); - window.setTopLevelPosition(sketchX + screenRect.x + (screenRect.width - sketchWidth) / 2, - sketchY + screenRect.y + (screenRect.height - sketchHeight) / 2); + window.setTopLevelPosition(screenRect.x + (screenRect.width - sketchWidth) / 2, + screenRect.y + (screenRect.height - sketchHeight) / 2); } Point frameLoc = new Point(x, y); @@ -744,13 +680,14 @@ public class PSurfaceJOGL implements PSurface { public void placePresent(int stopColor) { - pgl.initPresentMode(0.5f * (screenRect.width - sketchWidth), - 0.5f * (screenRect.height - sketchHeight), stopColor); - window.setSize(screenRect.width, screenRect.height); + float scale = getPixelScale(); + pgl.initPresentMode(0.5f * (screenRect.width/scale - sketchWidth), + 0.5f * (screenRect.height/scale - sketchHeight), stopColor); PApplet.hideMenuBar(); - window.setTopLevelPosition(sketchX + screenRect.x, - sketchY + screenRect.y); - window.setFullscreen(true); + + window.setUndecorated(true); + window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY()); + window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight()); } @@ -813,29 +750,39 @@ public class PSurfaceJOGL implements PSurface { public void setSize(final int width, final int height) { - if (width == sketch.width && height == sketch.height) { - return; - } + if (pgl.presentMode()) return; - if (!pgl.presentMode()) { - sketch.setSize(width, height); - sketchWidth = width; - sketchHeight = height; - graphics.setSize(width, height); - window.setSize(width, height); + boolean changed = sketch.width != width || sketch.height != height; + + sketchWidth = width; + sketchHeight = height; + + sketch.setSize(width, height); + graphics.setSize(width, height); + + if (changed) { + window.setSize(width * windowScaleFactor, height * windowScaleFactor); } } public float getPixelScale() { - if (graphics.is2X()) { - // Even if the graphics are retina, the user might have moved the window - // into a non-retina monitor, so we need to check - window.getCurrentSurfaceScale(currentPixelScale); - return currentPixelScale[0]; - } else { + if (graphics.pixelDensity == 1) { return 1; } + + if (PApplet.platform == PConstants.MACOSX) { + return getCurrentPixelScale(); + } + + return 2; + } + + private float getCurrentPixelScale() { + // Even if the graphics are retina, the user might have moved the window + // into a non-retina monitor, so we need to check + window.getCurrentSurfaceScale(currentPixelScale); + return currentPixelScale[0]; } @@ -938,32 +885,11 @@ public class PSurfaceJOGL implements PSurface { } public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) { -// int c = graphics.backgroundColor; -// pgl.clearColor(((c >> 16) & 0xff) / 255f, -// ((c >> 8) & 0xff) / 255f, -// ((c >> 0) & 0xff) / 255f, -// ((c >> 24) & 0xff) / 255f); -// pgl.clear(PGL.COLOR_BUFFER_BIT); pgl.resetFBOLayer(); -// final float[] valReqSurfacePixelScale = window.getRequestedSurfaceScale(new float[2]); - window.getCurrentSurfaceScale(currentPixelScale); -// final float[] nativeSurfacePixelScale = window.getMaximumSurfaceScale(new float[2]); -// System.err.println("[set PixelScale post]: "+ -// valReqSurfacePixelScale[0]+"x"+valReqSurfacePixelScale[1]+" (val) -> "+ -// hasSurfacePixelScale[0]+"x"+hasSurfacePixelScale[1]+" (has), "+ -// nativeSurfacePixelScale[0]+"x"+nativeSurfacePixelScale[1]+" (native)"); - - - - -// System.out.println("reshape: " + w + ", " + h); pgl.getGL(drawable); -// if (!graphics.is2X() && 1 < hasSurfacePixelScale[0]) { -// setSize(w/2, h/2); -// } else { -// setSize(w, h); -// } - setSize((int)(w/currentPixelScale[0]), (int)(h/currentPixelScale[1])); + float scale = PApplet.platform == PConstants.MACOSX ? + getCurrentPixelScale() : getPixelScale(); + setSize((int) (w / scale), (int) (h / scale)); } } @@ -1111,9 +1037,14 @@ public class PSurfaceJOGL implements PSurface { peCount = nativeEvent.getClickCount(); } - window.getCurrentSurfaceScale(currentPixelScale); - int sx = (int)(nativeEvent.getX()/currentPixelScale[0]); - int sy = (int)(nativeEvent.getY()/currentPixelScale[1]); + int scale; + if (PApplet.platform == PConstants.MACOSX) { + scale = (int) getCurrentPixelScale(); + } else { + scale = (int) getPixelScale(); + } + int sx = nativeEvent.getX() / scale; + int sy = nativeEvent.getY() / scale; int mx = sx; int my = sy; @@ -1121,7 +1052,7 @@ public class PSurfaceJOGL implements PSurface { mx -= (int)pgl.presentX; my -= (int)pgl.presentY; if (peAction == KeyEvent.RELEASE && - pgl.insideStopButton(sx, sy - screenRect.height)) { + pgl.insideStopButton(sx, sy - screenRect.height / windowScaleFactor)) { sketch.exit(); } if (mx < 0 || sketchWidth < mx || my < 0 || sketchHeight < my) { diff --git a/java/src/processing/mode/java/runner/Runner.java b/java/src/processing/mode/java/runner/Runner.java index 1223ee752..65058b881 100644 --- a/java/src/processing/mode/java/runner/Runner.java +++ b/java/src/processing/mode/java/runner/Runner.java @@ -24,6 +24,7 @@ package processing.mode.java.runner; import processing.app.*; import processing.app.exec.StreamRedirectThread; +import processing.app.ui.Toolkit; import processing.core.*; import processing.data.StringList; import processing.mode.java.JavaBuild; @@ -466,6 +467,10 @@ public class Runner implements MessageConsumer { // removed for 3.0a6 because it would break the args passed to sketches. params.append(PApplet.ARGS_SKETCH_FOLDER + "=" + build.getSketchPath()); + if (Toolkit.zoom(100) >= 200) { // Use 100 to bypass possible rounding in zoom() + params.append(PApplet.ARGS_DENSITY + "=2"); + } + params.append(build.getSketchClassName()); } // Add command-line arguments to be given to the sketch itself