From c37e9dc81ee73c8a11191e5314dd8a6c42d8794b Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 15 May 2015 16:00:35 -0400 Subject: [PATCH] rework non-visible surface handling, fix size() parser --- core/src/processing/core/PApplet.java | 37 +++-- core/src/processing/core/PConstants.java | 4 +- core/src/processing/core/PSurfaceNone.java | 7 +- core/todo.txt | 8 +- .../pdf/src/processing/pdf/PGraphicsPDF.java | 29 ++-- .../mode/java/preproc/PdePreprocessor.java | 135 ++++++++++++------ 6 files changed, 144 insertions(+), 76 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 0b2913ce5..4ff557f50 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -44,6 +44,7 @@ import java.awt.image.BufferedImage; + // used by loadImage() functions import javax.imageio.ImageIO; import javax.swing.ImageIcon; @@ -1489,6 +1490,7 @@ public class PApplet implements PConstants { size(w, h, sketchRenderer(), null); } + /** * @param renderer Either P2D, P3D, or PDF */ @@ -1496,16 +1498,26 @@ public class PApplet implements PConstants { size(w, h, renderer, null); } -/** - * @nowebref - */ + + /** + * @nowebref + */ public void size(final int w, final int h, String renderer, String path) { if (!renderer.equals(sketchRenderer())) { - System.err.println("Because you're not running from the PDE, add this to your code:"); - System.err.println("public String sketchRenderer() {"); - System.err.println(" return \"" + renderer + "\";"); - System.err.println("}"); - throw new RuntimeException("The sketchRenderer() method is not implemented."); + if (external) { + // The PDE should have parsed it, but something still went wrong + final String msg = + String.format("Something bad happened when calling " + + "size(%d, %d, %s, %s)", w, h, renderer, path); + throw new RuntimeException(msg); + + } else { + System.err.println("Because you're not running from the PDE, add this to your code:"); + System.err.println("public String sketchRenderer() {"); + System.err.println(" return \"" + renderer + "\";"); + System.err.println("}"); + throw new RuntimeException("The sketchRenderer() method is not implemented."); + } } surface.setSize(w, h); g.setPath(path); // finally, a path @@ -1700,6 +1712,7 @@ public class PApplet implements PConstants { pg.setParent(this); pg.setPrimary(primary); + System.out.println("path is " + path); if (path != null) { pg.setPath(path); } @@ -1770,7 +1783,8 @@ public class PApplet implements PConstants { /** Create default renderer, likely to be resized, but needed for surface init. */ protected PGraphics createPrimaryGraphics() { - return makeGraphics(sketchWidth(), sketchHeight(), sketchRenderer(), null, true); + return makeGraphics(sketchWidth(), sketchHeight(), + sketchRenderer(), sketchOutputPath(), true); } @@ -9643,9 +9657,8 @@ public class PApplet implements PConstants { surface.initFrame(this, backgroundColor, displayIndex, present, spanDisplays); surface.setTitle(getClass().getName()); //frame.setTitle(getClass().getName()); -// } else { -// // TODO necessary? -// surface.initOffscreen(this); + } else { + surface.initOffscreen(this); // for PDF, PSurfaceNone, and friends } init(); diff --git a/core/src/processing/core/PConstants.java b/core/src/processing/core/PConstants.java index 7de0e1754..05570b049 100644 --- a/core/src/processing/core/PConstants.java +++ b/core/src/processing/core/PConstants.java @@ -27,8 +27,6 @@ package processing.core; import java.awt.Cursor; import java.awt.event.KeyEvent; -import processing.data.StringList; - /** * Numbers shared throughout processing.core. @@ -48,6 +46,7 @@ public interface PConstants { // renderers known to processing.core + /* // List of renderers used inside PdePreprocessor static final StringList rendererList = new StringList(new String[] { "JAVA2D", "JAVA2D_2X", @@ -56,6 +55,7 @@ public interface PConstants { "LWJGL.P2D", "LWJGL.P3D", // hmm "PDF" // no DXF because that's only for beginRaw() }); + */ static final String JAVA2D = "processing.core.PGraphicsJava2D"; static final String JAVA2D_2X = "processing.core.PGraphicsJava2D2X"; diff --git a/core/src/processing/core/PSurfaceNone.java b/core/src/processing/core/PSurfaceNone.java index 2969f3cc8..66fe993a1 100644 --- a/core/src/processing/core/PSurfaceNone.java +++ b/core/src/processing/core/PSurfaceNone.java @@ -46,7 +46,7 @@ public class PSurfaceNone implements PSurface { @Override public void initOffscreen(PApplet sketch) { - // TODO Auto-generated method stub + this.sketch = sketch; } @@ -57,8 +57,9 @@ public class PSurfaceNone implements PSurface { @Override public void initFrame(PApplet sketch, int backgroundColor, - int deviceIndex, boolean fullScreen, - boolean spanDisplays) { + int deviceIndex, boolean fullScreen, + boolean spanDisplays) { + this.sketch = sketch; } diff --git a/core/todo.txt b/core/todo.txt index 5dac73328..70c485d9d 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -38,13 +38,17 @@ _ implement frameRate() _ implement external messages (moving the window) opengl +X deal with some performance issues +X https://github.com/processing/processing/issues/3210 +X Can't run sketches with offscreen PGraphics +X https://github.com/processing/processing/issues/3259 +_ Merge glw code into the OpenGL library +_ https://github.com/processing/processing/issues/3284 _ why is createShape() implemented 4x (for P2D, P3D, and 2x versions)? _ shouldn't be static, run it from the renderer, that's point of createXxx() _ when did setPath() sneak into PShape? API is nothing like anything else _ public createShape() method that takes another shape as param? _ should just be the constructor doing this, or copy() -_ drawing 100k lines is slow (example from Reas) -_ figure out what the bottleneck is here high priority diff --git a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java index 7fc3f11f5..12381260b 100644 --- a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java +++ b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java @@ -118,12 +118,14 @@ public class PGraphicsPDF extends PGraphicsJava2D { if (document == null) { document = new Document(new Rectangle(width, height)); + boolean missingPath = false; try { if (file != null) { //BufferedOutputStream output = new BufferedOutputStream(stream, 16384); output = new BufferedOutputStream(new FileOutputStream(file), 16384); } else if (output == null) { + missingPath = true; throw new RuntimeException("PGraphicsPDF requires a path " + "for the location of the output file."); } @@ -132,25 +134,26 @@ public class PGraphicsPDF extends PGraphicsJava2D { content = writer.getDirectContent(); // template = content.createTemplate(width, height); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Problem saving the PDF file."); + } catch (RuntimeException re) { + if (missingPath) { + throw re; // don't re-package our own error + } else { + throw new RuntimeException("Problem saving the PDF file.", re); + } + + } catch (FileNotFoundException fnfe) { + throw new RuntimeException("Can't save the PDF file to " + path, fnfe); + + } catch (DocumentException de) { + throw new RuntimeException("Error inside the PDF library.", de); } -// System.out.println("beginDraw fonts " + (System.currentTimeMillis() - t)); -// g2 = content.createGraphics(width, height, getMapper()); -// if (textMode == SHAPE) { g2 = content.createGraphicsShapes(width, height); -// } else if (textMode == MODEL) { -// g2 = content.createGraphics(width, height, getMapper()); -// } -// g2 = createGraphics(); -// g2 = template.createGraphics(width, height, mapper); } -// System.out.println("beginDraw " + (System.currentTimeMillis() - t0)); // super in Java2D now creates an image buffer, don't do that -// super.beginDraw(); + //super.beginDraw(); + checkSettings(); resetMatrix(); // reset model matrix vertexCount = 0; diff --git a/java/src/processing/mode/java/preproc/PdePreprocessor.java b/java/src/processing/mode/java/preproc/PdePreprocessor.java index a51208197..742fde183 100644 --- a/java/src/processing/mode/java/preproc/PdePreprocessor.java +++ b/java/src/processing/mode/java/preproc/PdePreprocessor.java @@ -4,7 +4,7 @@ PdePreprocessor - wrapper for default ANTLR-generated parser Part of the Processing project - http://processing.org - Copyright (c) 2004-12 Ben Fry and Casey Reas + Copyright (c) 2004-15 Ben Fry and Casey Reas Copyright (c) 2001-04 Massachusetts Institute of Technology ANTLR-generated parser and several supporting classes written @@ -36,7 +36,7 @@ import processing.app.Base; import processing.app.Preferences; import processing.app.SketchException; import processing.core.PApplet; -import processing.core.PConstants; +import processing.data.StringList; import processing.mode.java.preproc.PdeLexer; import processing.mode.java.preproc.PdeRecognizer; import processing.mode.java.preproc.PdeTokenTypes; @@ -167,12 +167,13 @@ public class PdePreprocessor { * in the sketch, which is the case especially for anyone who is cutting * and pasting from the reference. */ - public static final String SIZE_REGEX = - "(?:^|\\s|;)size\\s*\\(\\s*([^\\s,]+)\\s*,\\s*([^\\s,\\)]+)\\s*,?\\s*([^\\)]*)\\s*\\)\\s*\\;"; - //"(?:^|\\s|;)size\\s*\\(\\s*(\\S+)\\s*,\\s*([^\\s,\\)]+),?\\s*([^\\)]*)\\s*\\)\\s*\\;"; +// public static final String SIZE_REGEX = +// "(?:^|\\s|;)size\\s*\\(\\s*([^\\s,]+)\\s*,\\s*([^\\s,\\)]+)\\s*,?\\s*([^\\)]*)\\s*\\)\\s*\\;"; + static private final String SIZE_CONTENTS_REGEX = + "(?:^|\\s|;)size\\s*\\(([^\\)]+)\\)\\s*\\;"; - private static final Pattern PUBLIC_CLASS = + static private final Pattern PUBLIC_CLASS = Pattern.compile("(^|;)\\s*public\\s+class\\s+\\S+\\s+extends\\s+PApplet", Pattern.MULTILINE); // Can't only match any 'public class', needs to be a PApplet // http://code.google.com/p/processing/issues/detail?id=551 @@ -201,6 +202,7 @@ public class PdePreprocessor { public String[] initSketchSize(String code, boolean sizeWarning) throws SketchException { String[] info = parseSketchSize(code, sizeWarning); + PApplet.printArray(info); if (info != null) { sizeStatement = info[0]; sketchWidth = info[1]; @@ -211,6 +213,44 @@ public class PdePreprocessor { } + // break on commas, except those inside quotes, e.g.: + // size(300, 200, PDF, "output,weirdname.pdf"); + // no handling for escaped (\") quotes + static private StringList breakCommas(String contents) { + StringList outgoing = new StringList(); + + boolean insideQuote = false; + // The current word being read + StringBuilder current = new StringBuilder(); + char[] chars = contents.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (insideQuote) { + current.append(c); + if (c == '\"') { + insideQuote = false; + } + } else { + if (c == ',') { + if (current.length() != 0) { + outgoing.append(current.toString()); + current.setLength(0); + } + } else { + current.append(c); + if (c == '\"') { + insideQuote = true; + } + } + } + } + if (current.length() != 0) { + outgoing.append(current.toString()); + } + return outgoing; + } + + /** * Parse a chunk of code and extract the size() command and its contents. * @param code Usually the code from the main tab in the sketch @@ -225,15 +265,29 @@ public class PdePreprocessor { // String scrubbed = scrubComments(sketch.getCode(0).getProgram()); // String[] matches = PApplet.match(scrubbed, SIZE_REGEX); - String[] matches = PApplet.match(scrubComments(code), SIZE_REGEX); +// String[] matches = PApplet.match(scrubComments(code), SIZE_REGEX); + + // Get everything inside the parens for the size() method + String[] contents = PApplet.match(scrubComments(code), SIZE_CONTENTS_REGEX); + if (contents != null) { + //String[] matches = split on commas, but not commas inside quotes + + StringList args = breakCommas(contents[1]); + String width = args.get(0); + String height = args.get(1); + String renderer = (args.size() >= 3) ? args.get(2) : null; + String path = (args.size() >= 4) ? args.get(3) : null; - if (matches != null) { boolean badSize = false; - if (matches[1].equals("screenWidth") || - matches[1].equals("screenHeight") || - matches[2].equals("screenWidth") || - matches[2].equals("screenHeight")) { + // Trying to remember why we wanted to allow people to use displayWidth + // as the height or displayHeight as the width, but maybe it's for + // making a square sketch window? Not going to + + if (width.equals("screenWidth") || + width.equals("screenHeight") || + height.equals("screenHeight") || + height.equals("screenWidth")) { final String message = "The screenWidth and screenHeight variables\n" + "are named displayWidth and displayHeight\n" + @@ -242,14 +296,14 @@ public class PdePreprocessor { return null; } - if (!matches[1].equals("displayWidth") && - !matches[1].equals("displayHeight") && - PApplet.parseInt(matches[1], -1) == -1) { + if (!width.equals("displayWidth") && + !width.equals("displayHeight") && + PApplet.parseInt(width, -1) == -1) { badSize = true; } - if (!matches[2].equals("displayWidth") && - !matches[2].equals("displayHeight") && - PApplet.parseInt(matches[2], -1) == -1) { + if (!height.equals("displayWidth") && + !height.equals("displayHeight") && + PApplet.parseInt(height, -1) == -1) { badSize = true; } @@ -266,15 +320,24 @@ public class PdePreprocessor { } // Remove additional space 'round the renderer - matches[3] = matches[3].trim(); - - // if the renderer entry is empty, set it to null - if (matches[3].length() == 0) { - matches[3] = null; + if (renderer != null) { + renderer = renderer.trim(); + if (renderer.length() == 0) { // if empty, set null + renderer = null; + } } - return matches; + + // Same for the file name + if (path != null) { + path = path.trim(); + if (path.length() == 0) { + path = null; + } + } + return new String[] { contents[0], width, height, renderer, path }; } - return new String[] { null, null, null, null }; // not an error, just empty + // not an error, just no size() specified + return new String[] { null, null, null, null, null }; } @@ -888,25 +951,9 @@ public class PdePreprocessor { } if (sketchRenderer != null && !hasMethod("sketchRenderer")) { // Only include if it's a known renderer (otherwise it might be a variable) - if (PConstants.rendererList.hasValue(sketchRenderer)) { - /* - } - if (sketchRenderer.equals("P2D") || - sketchRenderer.equals("P2D_2X") || - sketchRenderer.equals("P3D") || - sketchRenderer.equals("P3D_3X") || - sketchRenderer.equals("OPENGL") || - sketchRenderer.equals("JAVA2D") || - sketchRenderer.equals("JAVA2D_2X") || - sketchRenderer.equals("E2D") || - sketchRenderer.equals("FX2D") || - sketchRenderer.equals("FX2D_2X") || - sketchRenderer.equals("PDF") || - sketchRenderer.equals("LWJGL.P2D") || - sketchRenderer.equals("LWJGL.P3D")) { - */ - out.println(indent + "public String sketchRenderer() { return " + sketchRenderer + "; }"); - } + //if (PConstants.rendererList.hasValue(sketchRenderer)) { + out.println(indent + "public String sketchRenderer() { return " + sketchRenderer + "; }"); + //} } if (!hasMethod("main")) {