diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs
index da7176c57..bd0342e50 100644
--- a/app/.settings/org.eclipse.jdt.core.prefs
+++ b/app/.settings/org.eclipse.jdt.core.prefs
@@ -5,9 +5,9 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/app/build.xml b/app/build.xml
old mode 100644
new mode 100755
index c8d8ef937..ad89dbf8c
--- a/app/build.xml
+++ b/app/build.xml
@@ -92,9 +92,12 @@
encoding="UTF-8"
includeAntRuntime="false"
classpath="../core/library/core.jar; lib/ant.jar; lib/ant-launcher.jar; lib/antlr.jar; lib/apple.jar; lib/jdt-core.jar; lib/jna.jar; lib/org-netbeans-swing-outline.jar;lib/com.ibm.icu_4.4.2.v20110823.jar;lib/jdi.jar;lib/jdimodel.jar;lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar"
- debug="on">
+ debug="on"
+ nowarn="true"
+ compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
+
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
old mode 100755
new mode 100644
index 1f192aa4b..50230531b
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -6,9 +6,9 @@
Copyright (c) 2004-13 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
- as published by the Free Software Foundation.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -45,10 +45,10 @@ import processing.core.*;
*/
public class Base {
// Added accessors for 0218 because the UpdateCheck class was not properly
- // updating the values, because javac was inlining the static final values.
- static private final int REVISION = 219;
+ // updating the values, due to javac inlining the static final values.
+ static private final int REVISION = 224;
/** This might be replaced by main() if there's a lib/version.txt file. */
- static private String VERSION_NAME = "0219"; //$NON-NLS-1$
+ static private String VERSION_NAME = "0224"; //$NON-NLS-1$
/** Set true if this a proper release rather than a numbered revision. */
// static private boolean RELEASE = false;
@@ -198,9 +198,19 @@ public class Base {
}
log("about to create base..."); //$NON-NLS-1$
- Base base = new Base(args);
- // Prevent more than one copy of the PDE from running.
- SingleInstance.startServer(base);
+ try {
+ Base base = new Base(args);
+ // Prevent more than one copy of the PDE from running.
+ SingleInstance.startServer(base);
+
+ } catch (Exception e) {
+ // Catch-all to hopefully pick up some of the weirdness we've been
+ // running into lately.
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ Base.showError("We're off on the wrong foot",
+ "An error occurred during startup.\n" + sw, e);
+ }
log("done creating base..."); //$NON-NLS-1$
}
}
@@ -220,11 +230,11 @@ public class Base {
try {
Class> platformClass = Class.forName("processing.app.Platform"); //$NON-NLS-1$
if (Base.isMacOS()) {
- platformClass = Class.forName("processing.app.macosx.Platform"); //$NON-NLS-1$
+ platformClass = Class.forName("processing.app.platform.MacPlatform"); //$NON-NLS-1$
} else if (Base.isWindows()) {
- platformClass = Class.forName("processing.app.windows.Platform"); //$NON-NLS-1$
+ platformClass = Class.forName("processing.app.platform.WindowsPlatform"); //$NON-NLS-1$
} else if (Base.isLinux()) {
- platformClass = Class.forName("processing.app.linux.Platform"); //$NON-NLS-1$
+ platformClass = Class.forName("processing.app.platform.LinuxPlatform"); //$NON-NLS-1$
}
platform = (Platform) platformClass.newInstance();
} catch (Exception e) {
@@ -324,7 +334,7 @@ public class Base {
}
- public Base(String[] args) {
+ public Base(String[] args) throws Exception {
// // Get the sketchbook path, and make sure it's set properly
// determineSketchbookFolder();
@@ -338,7 +348,7 @@ public class Base {
// removeDir(contrib.getFolder());
// }
// }
- ContributionManager.deleteFlagged();
+ ContributionManager.cleanup();
buildCoreModes();
rebuildContribModes();
@@ -354,7 +364,7 @@ public class Base {
} else {
for (Mode m : getModeList()) {
if (m.getIdentifier().equals(lastModeIdentifier)) {
- log("Setting next mode to " + lastModeIdentifier); //$NON-NLS-1$
+ logf("Setting next mode to {0}.", lastModeIdentifier); //$NON-NLS-1$
nextMode = m;
}
}
@@ -1028,6 +1038,7 @@ public class Base {
// Close the running window, avoid window boogers with multiple sketches
editor.internalCloseRunner();
+// System.out.println("editors size is " + editors.size());
if (editors.size() == 1) {
// For 0158, when closing the last window /and/ it was already an
// untitled sketch, just give up and let the user quit.
@@ -1067,6 +1078,7 @@ public class Base {
// This will store the sketch count as zero
editors.remove(editor);
+// System.out.println("editors size now " + editors.size());
// storeSketches();
// Save out the current prefs state
@@ -1384,7 +1396,7 @@ public class Base {
}
}
}
- return found; // actually ignored, but..
+ return found;
}
@@ -1580,18 +1592,29 @@ public class Base {
}
+ // Because the Oracle JDK is 64-bit only, we lose this ability, feature,
+ // edge case, headache.
+// /**
+// * Return whether sketches will run as 32- or 64-bits. On Linux and Windows,
+// * this is the bit depth of the machine, while on OS X it's determined by the
+// * setting from preferences, since both 32- and 64-bit are supported.
+// */
+// static public int getNativeBits() {
+// if (Base.isMacOS()) {
+// return Preferences.getInteger("run.options.bits"); //$NON-NLS-1$
+// }
+// return nativeBits;
+// }
+
/**
- * Return whether sketches will run as 32- or 64-bits. On Linux and Windows,
- * this is the bit depth of the machine, while on OS X it's determined by the
- * setting from preferences, since both 32- and 64-bit are supported.
+ * Return whether sketches will run as 32- or 64-bits based
+ * on the JVM that's in use.
*/
static public int getNativeBits() {
- if (Base.isMacOS()) {
- return Preferences.getInteger("run.options.bits"); //$NON-NLS-1$
- }
return nativeBits;
}
+
/*
static public String getPlatformName() {
String osname = System.getProperty("os.name");
@@ -1642,6 +1665,29 @@ public class Base {
}
+ static private Boolean usableOracleJava;
+
+ // Make sure this is Oracle Java 7u40 or later. This is temporary.
+ static public boolean isUsableOracleJava() {
+ if (usableOracleJava == null) {
+ usableOracleJava = false;
+
+ if (Base.isMacOS() &&
+ System.getProperty("java.vendor").contains("Oracle")) {
+ String version = System.getProperty("java.version"); // 1.7.0_40
+ String[] m = PApplet.match(version, "1.(\\d).*_(\\d+)");
+
+ if (m != null &&
+ PApplet.parseInt(m[1]) >= 7 &&
+ PApplet.parseInt(m[2]) >= 40) {
+ usableOracleJava = true;
+ }
+ }
+ }
+ return usableOracleJava;
+ }
+
+
/**
* returns true if running on windows.
*/
@@ -2047,7 +2093,7 @@ public class Base {
/**
* Non-fatal error message with optional stack trace side dish.
*/
- static public void showWarning(String title, String message, Exception e) {
+ static public void showWarning(String title, String message, Throwable e) {
if (title == null) title = "Warning";
if (commandLine) {
@@ -2066,7 +2112,7 @@ public class Base {
*/
static public void showWarningTiered(String title,
String primary, String secondary,
- Exception e) {
+ Throwable e) {
if (title == null) title = "Warning";
final String message = primary + "\n" + secondary;
@@ -2315,15 +2361,37 @@ public class Base {
String path = Base.class.getProtectionDomain().getCodeSource().getLocation().getPath();
// Path may have URL encoding, so remove it
String decodedPath = PApplet.urlDecode(path);
- // The .jar file will be in the lib folder
- File libFolder = new File(decodedPath).getParentFile();
- if (libFolder.getName().equals("lib")) {
- // The main Processing installation directory
- processingRoot = libFolder.getParentFile();
+
+ if (decodedPath.contains("/app/bin")) {
+ if (Base.isMacOS()) {
+ processingRoot =
+ new File(path, "../../build/macosx/work/Processing.app/Contents/Java");
+ } else if (Base.isWindows()) {
+ processingRoot = new File(path, "../../build/windows/work");
+ } else if (Base.isLinux()) {
+ processingRoot = new File(path, "../../build/linux/work");
+ }
} else {
- Base.log("Could not find lib in " +
- libFolder.getAbsolutePath() + ", switching to user.dir");
- processingRoot = new File(System.getProperty("user.dir"));
+ // The .jar file will be in the lib folder
+ File jarFolder = new File(decodedPath).getParentFile();
+ if (jarFolder.getName().equals("lib")) {
+ // The main Processing installation directory.
+ // This works for Windows, Linux, and Apple's Java 6 on OS X.
+ processingRoot = jarFolder.getParentFile();
+ } else if (Base.isMacOS()) {
+ // This works for Java 7 on OS X. The 'lib' folder is not part of the
+ // classpath on OS X, and adding it creates more problems than it's
+ // worth.
+ processingRoot = jarFolder;
+
+ }
+ if (processingRoot == null || !processingRoot.exists()) {
+ // Try working directory instead (user.dir, different from user.home)
+ System.err.println("Could not find lib folder via " +
+ jarFolder.getAbsolutePath() +
+ ", switching to user.dir");
+ processingRoot = new File(System.getProperty("user.dir"));
+ }
}
}
/*
@@ -2344,6 +2412,57 @@ public class Base {
}
+ static public File getJavaHome() {
+ if (isMacOS()) {
+ //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java";
+ File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jdk") && dir.isDirectory();
+ }
+ });
+ return new File(plugins[0], "Contents/Home/jre");
+ }
+ // On all other platforms, it's the 'java' folder adjacent to Processing
+ return getContentFile("java");
+ }
+
+
+ /** Get the path to the embedded Java executable. */
+ static public String getJavaPath() {
+ String javaPath = "bin/java" + (isWindows() ? ".exe" : "");
+ File javaFile = new File(getJavaHome(), javaPath);
+ try {
+ return javaFile.getCanonicalPath();
+ } catch (IOException e) {
+ return javaFile.getAbsolutePath();
+ }
+ /*
+ if (isMacOS()) {
+ //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java";
+ File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jdk") && dir.isDirectory();
+ }
+ });
+ //PApplet.printArray(plugins);
+ File javaBinary = new File(plugins[0], "Contents/Home/jre/bin/java");
+ //return getContentFile(plugins[0].getAbsolutePath() + "/Contents/Home/jre/bin/java").getAbsolutePath();
+ //return getContentFile("../PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java").getAbsolutePath();
+ return javaBinary.getAbsolutePath();
+
+ } else if (isLinux()) {
+ return getContentFile("java/bin/java").getAbsolutePath();
+
+ } else if (isWindows()) {
+ return getContentFile("java/bin/java.exe").getAbsolutePath();
+ }
+ System.err.println("No appropriate platform found. " +
+ "Hoping that Java is in the path.");
+ return Base.isWindows() ? "java.exe" : "java";
+ */
+ }
+
+
// /**
// * Get an image associated with the current color theme.
// * @deprecated
@@ -2429,12 +2548,21 @@ public class Base {
}
- static public void readSettings(String filename, String lines[],
+ /**
+ * Parse a String array that contains attribute/value pairs separated
+ * by = (the equals sign). The # (hash) symbol is used to denote comments.
+ * Comments can be anywhere on a line. Blank lines are ignored.
+ */
+ static public void readSettings(String filename, String[] lines,
HashMap settings) {
- for (int i = 0; i < lines.length; i++) {
- int hash = lines[i].indexOf('#');
- String line = (hash == -1) ?
- lines[i].trim() : lines[i].substring(0, hash).trim();
+ for (String line : lines) {
+ // Remove comments
+ int commentMarker = line.indexOf('#');
+ if (commentMarker != -1) {
+ line = line.substring(0, commentMarker);
+ }
+ // Remove extra whitespace
+ line = line.trim();
if (line.length() != 0) {
int equals = line.indexOf('=');
@@ -2472,6 +2600,7 @@ public class Base {
to = null;
targetFile.setLastModified(sourceFile.lastModified());
+ targetFile.setExecutable(sourceFile.canExecute());
}
@@ -2544,10 +2673,50 @@ public class Base {
}
+ static public void copyDirNative(File sourceDir,
+ File targetDir) throws IOException {
+ Process process = null;
+ if (Base.isMacOS() || Base.isLinux()) {
+ process = Runtime.getRuntime().exec(new String[] {
+ "cp", "-a", sourceDir.getAbsolutePath(), targetDir.getAbsolutePath()
+ });
+ } else {
+ // TODO implement version that uses XCOPY here on Windows
+ throw new RuntimeException("Not yet implemented on Windows");
+ }
+ try {
+ int result = process.waitFor();
+ if (result != 0) {
+ throw new IOException("Error while copying (result " + result + ")");
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Delete a file or directory in a platform-specific manner. Removes a File
+ * object (a file or directory) from the system by placing it in the Trash
+ * or Recycle Bin (if available) or simply deleting it (if not).
+ *
+ * When the file/folder is on another file system, it may simply be removed
+ * immediately, without additional warning. So only use this if you want to,
+ * you know, "delete" the subject in question.
+ *
+ * NOTE: Not yet tested nor ready for prime-time.
+ *
+ * @param file the victim (a directory or individual file)
+ * @return true if all ends well
+ * @throws IOException what went wrong
+ */
+ static public boolean platformDelete(File file) throws IOException {
+ return platform.deleteFile(file);
+ }
+
+
/**
* Remove all files in a directory and the directory itself.
- * TODO implement cross-platform "move to trash" instead of deleting,
- * since this is potentially scary if there's a bug.
*/
static public void removeDir(File dir) {
if (dir.exists()) {
@@ -2600,7 +2769,8 @@ public class Base {
if (files == null) return -1;
for (int i = 0; i < files.length; i++) {
- if (files[i].equals(".") || (files[i].equals("..")) ||
+ if (files[i].equals(".") ||
+ files[i].equals("..") ||
files[i].equals(".DS_Store")) continue;
File fella = new File(folder, files[i]);
if (fella.isDirectory()) {
@@ -2917,7 +3087,7 @@ public class Base {
}
- static public void log(String message, Exception e) {
+ static public void log(String message, Throwable e) {
if (DEBUG) {
System.out.println(message);
e.printStackTrace();
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index cfbe5931e..3463555e0 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -472,6 +472,14 @@ public abstract class Editor extends JFrame implements RunnerListener {
* with things in the Preferences window.
*/
protected void applyPreferences() {
+ // Update fonts and other items controllable from the prefs
+ textarea.getPainter().updateAppearance();
+ textarea.repaint();
+
+ console.updateAppearance();
+
+ // All of this code was specific to using an external editor.
+ /*
// // apply the setting for 'use external editor'
// boolean external = Preferences.getBoolean("editor.external");
// textarea.setEditable(!external);
@@ -494,7 +502,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
// }
// apply changes to the font size for the editor
- painter.setFont(Preferences.getFont("editor.font"));
+// painter.setFont(Preferences.getFont("editor.font"));
// in case tab expansion stuff has changed
// removing this, just checking prefs directly instead
@@ -505,6 +513,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
//sketchbook.rebuildMenus();
// For 0126, moved into Base, which will notify all editors.
//base.rebuildMenusAsync();
+ */
}
@@ -933,25 +942,92 @@ public abstract class Editor extends JFrame implements RunnerListener {
}
+// /**
+// * Attempt to init or run a Tool from the safety of a try/catch block that
+// * will report errors to the user.
+// * @param tool The Tool object to be inited or run
+// * @param item null to call init(), or the existing JMenuItem for run()
+// * @return
+// */
+// protected boolean safeTool(Tool tool, JMenuItem item) {
+// try {
+// if (item == null) {
+// tool.init(Editor.this);
+// } else {
+// tool.run();
+// }
+// return true;
+//
+// } catch (NoSuchMethodError nsme) {
+// System.out.println("tool is " + tool + " ");
+// statusError("\"" + tool.getMenuTitle() + "\" " +
+// "is not compatible with this version of Processing");
+// nsme.printStackTrace();
+//
+// } catch (Exception ex) {
+// statusError("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+// ex.printStackTrace();
+// }
+// if (item != null) {
+// item.setEnabled(false); // don't you try that again
+// }
+// return false;
+// }
+
+
+ void addToolItem(final Tool tool, HashMap toolItems) {
+ String title = tool.getMenuTitle();
+ final JMenuItem item = new JMenuItem(title);
+ item.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ try {
+ tool.run();
+
+ } catch (NoSuchMethodError nsme) {
+ statusError("\"" + tool.getMenuTitle() + "\" is not" +
+ "compatible with this version of Processing");
+ //nsme.printStackTrace();
+ Base.log("Incompatible tool found during tool.run()", nsme);
+ item.setEnabled(false);
+
+ } catch (Exception ex) {
+ statusError("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+ ex.printStackTrace();
+ item.setEnabled(false);
+ }
+ }
+ });
+ //menu.add(item);
+ toolItems.put(title, item);
+ }
+
+
protected void addTools(JMenu menu, ArrayList tools) {
HashMap toolItems = new HashMap();
for (final ToolContribution tool : tools) {
- String title = tool.getMenuTitle();
- JMenuItem item = new JMenuItem(title);
- item.addActionListener(new ActionListener() {
- boolean inited;
+ try {
+ tool.init(Editor.this);
+ // If init() fails, the item won't be added to the menu
+ addToolItem(tool, toolItems);
+
+ // With the exceptions, we can't call statusError because the window
+ // isn't completely set up yet. Also not gonna pop up a warning because
+ // people may still be running different versions of Processing.
+ // TODO Once the dust settles on 2.x, change this to Base.showError()
+ // and open the Tools folder instead of showing System.err.println().
+
+ } catch (NoSuchMethodError nsme) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
+ System.err.println("This method no longer exists: " + nsme.getMessage());
+ Base.log("Incompatible Tool found during tool.init()", nsme);
- public void actionPerformed(ActionEvent e) {
- if (!inited) {
- tool.init(Editor.this);
- inited = true;
- }
- EventQueue.invokeLater(tool);
- }
- });
- //menu.add(item);
- toolItems.put(title, item);
+ } catch (Exception ex) {
+ System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+ ex.printStackTrace();
+ }
}
ArrayList toolList = new ArrayList(toolItems.keySet());
@@ -984,7 +1060,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
- SwingUtilities.invokeLater(tool);
+ EventQueue.invokeLater(tool);
}
});
menu.add(item);
@@ -1009,9 +1085,6 @@ public abstract class Editor extends JFrame implements RunnerListener {
addToolMenuItem(menu, "processing.app.tools.Archiver");
if (Base.isMacOS()) {
- if (SerialFixer.isNeeded()) {
- addToolMenuItem(menu, "processing.app.tools.SerialFixer");
- }
addToolMenuItem(menu, "processing.app.tools.InstallCommander");
}
@@ -1409,6 +1482,8 @@ public abstract class Editor extends JFrame implements RunnerListener {
if (compoundEdit != null) {
compoundEdit.end();
undo.addEdit(compoundEdit);
+ caretUndoStack.push(textarea.getCaretPosition());
+ caretRedoStack.clear();
undoAction.updateUndoState();
redoAction.updateRedoState();
compoundEdit = null;
@@ -2008,6 +2083,9 @@ public abstract class Editor extends JFrame implements RunnerListener {
// As of Processing 1.0.10, this always happens immediately.
// http://dev.processing.org/bugs/show_bug.cgi?id=1456
+ // With Java 7u40 on OS X, need to bring the window forward.
+ toFront();
+
String prompt = "Save changes to " + sketch.getName() + "? ";
if (!Base.isMacOS()) {
@@ -2327,9 +2405,9 @@ public abstract class Editor extends JFrame implements RunnerListener {
}
if (pageFormat != null) {
//System.out.println("setting page format " + pageFormat);
- printerJob.setPrintable(textarea.getPainter(), pageFormat);
+ printerJob.setPrintable(textarea.getPrintable(), pageFormat);
} else {
- printerJob.setPrintable(textarea.getPainter());
+ printerJob.setPrintable(textarea.getPrintable());
}
// set the name of the job to the code name
printerJob.setJobName(sketch.getCurrentCode().getPrettyName());
diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java
index dd822c7d0..6ad9eb709 100644
--- a/app/src/processing/app/EditorConsole.java
+++ b/app/src/processing/app/EditorConsole.java
@@ -164,6 +164,20 @@ public class EditorConsole extends JScrollPane {
}
+ /**
+ * Update the font family and sizes based on the Preferences window.
+ */
+ protected void updateAppearance() {
+ String fontFamily = Preferences.get("editor.font.family");
+ int fontSize = Preferences.getInteger("console.font.size");
+ StyleConstants.setFontFamily(stdStyle, fontFamily);
+ StyleConstants.setFontSize(stdStyle, fontSize);
+ StyleConstants.setFontFamily(errStyle, fontFamily);
+ StyleConstants.setFontSize(errStyle, fontSize);
+ clear(); // otherwise we'll have mixed fonts
+ }
+
+
/**
* Change coloring, fonts, etc in response to a mode change.
*/
diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java
old mode 100755
new mode 100644
index 432a47179..334d0e91d
--- a/app/src/processing/app/EditorHeader.java
+++ b/app/src/processing/app/EditorHeader.java
@@ -55,7 +55,10 @@ public class EditorHeader extends JComponent {
// (total tab width will be this plus TEXT_MARGIN*2)
static final int NO_TEXT_WIDTH = 10;
- Color backgroundColor;
+ Color bgColor;
+ boolean hiding;
+ Color hideColor;
+
Color textColor[] = new Color[2];
Color tabColor[] = new Color[2];
Color modifiedColor;
@@ -194,7 +197,11 @@ public class EditorHeader extends JComponent {
tabArrow = Toolkit.getLibImage("tab-arrow" + suffix);
}
- backgroundColor = mode.getColor("header.bgcolor");
+ bgColor = mode.getColor("header.bgcolor");
+
+ hiding = Preferences.getBoolean("buttons.hide.image");
+ hideColor = mode.getColor("buttons.hide.color");
+
textColor[SELECTED] = mode.getColor("header.text.selected.color");
textColor[UNSELECTED] = mode.getColor("header.text.unselected.color");
font = mode.getFont("header.text.font");
@@ -252,31 +259,25 @@ public class EditorHeader extends JComponent {
if (Toolkit.highResDisplay()) {
// scale everything 2x, will be scaled down when drawn to the screen
g2.scale(2, 2);
+ if (Base.isUsableOracleJava()) {
+ // Oracle Java looks better with anti-aliasing turned on
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
} else {
- // don't anti-alias text in retina mode
+ // don't anti-alias text in retina mode w/ Apple Java
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
// set the background for the offscreen
- g.setColor(backgroundColor);
+ g.setColor(hiding ? hideColor : bgColor);
g.fillRect(0, 0, imageW, imageH);
-// EditorToolbar toolbar = editor.toolbar;
-// if (toolbar != null && toolbar.backgroundImage != null) {
-// g.drawImage(toolbar.backgroundImage,
-// 0, -toolbar.getHeight(),
-// EditorToolbar.BACKGROUND_WIDTH,
-// EditorToolbar.BACKGROUND_HEIGHT, null);
-// }
- //editor.getMode().drawBackground(g, EditorToolbar.BUTTON_HEIGHT);
- editor.getMode().drawBackground(g, Preferences.GRID_SIZE);
+ if (!hiding) {
+ editor.getMode().drawBackground(g, Preferences.GRID_SIZE);
+ }
-// int codeCount = sketch.getCodeCount();
-// if ((tabLeft == null) || (tabLeft.length < codeCount)) {
-// tabLeft = new int[codeCount];
-// tabRight = new int[codeCount];
-// }
if (tabs.length != sketch.getCodeCount()) {
tabs = new Tab[sketch.getCodeCount()];
for (int i = 0; i < tabs.length; i++) {
@@ -285,9 +286,6 @@ public class EditorHeader extends JComponent {
visitOrder = new Tab[sketch.getCodeCount() - 1];
}
-// menuRight = sizeW - 16;
-// menuLeft = menuRight - pieces[0][MENU].getWidth(this);
-// menuLeft = menuRight - 50; // FIXME!!
int leftover =
ARROW_GAP_WIDTH + ARROW_WIDTH + MARGIN_WIDTH; // + SCROLLBAR_WIDTH;
int tabMax = getWidth() - leftover;
@@ -536,16 +534,14 @@ public class EditorHeader extends JComponent {
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Sketch sketch = editor.getSketch();
- if (!sketch.isUntitled()) { // don't bother if untitled
- if (!Base.isMacOS() && // ok on OS X
- editor.base.editors.size() == 1 && // mmm! accessor
- sketch.getCurrentCodeIndex() == 0) {
+ if (!Base.isMacOS() && // ok on OS X
+ editor.base.editors.size() == 1 && // mmm! accessor
+ sketch.getCurrentCodeIndex() == 0) {
Base.showWarning("Yeah, no." ,
"You can't delete the last tab " +
"of the last open sketch.", null);
- } else {
- editor.getSketch().handleDeleteCode();
- }
+ } else {
+ editor.getSketch().handleDeleteCode();
}
}
});
diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java
index dc1a842fb..ff7a1bacd 100644
--- a/app/src/processing/app/EditorLineStatus.java
+++ b/app/src/processing/app/EditorLineStatus.java
@@ -23,6 +23,7 @@
package processing.app;
import java.awt.*;
+
import javax.swing.*;
@@ -87,6 +88,10 @@ public class EditorLineStatus extends JComponent {
public void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
g.setColor(background);
Dimension size = getSize();
g.fillRect(0, 0, size.width, size.height);
@@ -94,7 +99,8 @@ public class EditorLineStatus extends JComponent {
g.setFont(font);
g.setColor(foreground);
int baseline = (high + g.getFontMetrics().getAscent()) / 2;
- g.drawString(text, 6, baseline);
+ // With 7u40 (or Source Code Sans?) things seem to be edged up a bit
+ g.drawString(text, 6, baseline - 1);
}
diff --git a/app/src/processing/app/EditorState.java b/app/src/processing/app/EditorState.java
index a55491af1..f8cc950c2 100644
--- a/app/src/processing/app/EditorState.java
+++ b/app/src/processing/app/EditorState.java
@@ -21,6 +21,7 @@
package processing.app;
+import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
@@ -53,6 +54,7 @@ public class EditorState {
// int displayW, displayH;
// String deviceName; // not really useful b/c it's more about bounds anyway
Rectangle deviceBounds;
+ boolean isMaximized;
/**
@@ -173,6 +175,7 @@ public class EditorState {
synchronized (editors) {
final int OVER = 50;
Editor lastOpened = editors.get(editors.size() - 1);
+ isMaximized = (lastOpened.getExtendedState() == Frame.MAXIMIZED_BOTH);
editorBounds = lastOpened.getBounds();
editorBounds.x += OVER;
editorBounds.y += OVER;
@@ -180,8 +183,14 @@ public class EditorState {
if (!deviceBounds.contains(editorBounds)) {
// Warp the next window to a randomish location on screen.
- editorBounds.x = deviceBounds.x + (int) (Math.random() * (deviceBounds.width - defaultWidth));
- editorBounds.y = deviceBounds.y + (int) (Math.random() * (deviceBounds.height - defaultHeight));
+ editorBounds.x = deviceBounds.x +
+ (int) (Math.random() * (deviceBounds.width - defaultWidth));
+ editorBounds.y = deviceBounds.y +
+ (int) (Math.random() * (deviceBounds.height - defaultHeight));
+ }
+ if (isMaximized) {
+ editorBounds.width = defaultWidth;
+ editorBounds.height = defaultHeight;
}
}
}
@@ -204,6 +213,9 @@ public class EditorState {
if (dividerLocation != 0) {
editor.setDividerLocation(dividerLocation);
}
+ if (isMaximized) {
+ editor.setExtendedState(Frame.MAXIMIZED_BOTH);
+ }
}
diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java
index 361db92d9..4f006d580 100644
--- a/app/src/processing/app/EditorStatus.java
+++ b/app/src/processing/app/EditorStatus.java
@@ -25,6 +25,7 @@ package processing.app;
import java.awt.*;
import java.awt.event.*;
+
import javax.swing.*;
@@ -196,6 +197,11 @@ public class EditorStatus extends JPanel {
Graphics2D g2 = (Graphics2D) g;
if (Toolkit.highResDisplay()) {
g2.scale(2, 2);
+ if (Base.isUsableOracleJava()) {
+ // Oracle Java looks better with anti-aliasing turned on
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
} else {
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java
index 7981cb27e..8e19de102 100644
--- a/app/src/processing/app/EditorToolbar.java
+++ b/app/src/processing/app/EditorToolbar.java
@@ -56,7 +56,9 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList
Image offscreen;
int width, height;
- Color bgcolor;
+ Color bgColor;
+ boolean hiding;
+ Color hideColor;
protected Button rollover;
@@ -92,13 +94,16 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList
rollover = null;
mode = editor.getMode();
- bgcolor = mode.getColor("buttons.bgcolor");
+ bgColor = mode.getColor("buttons.bgcolor");
statusFont = mode.getFont("buttons.status.font");
statusColor = mode.getColor("buttons.status.color");
// modeTitle = mode.getTitle().toUpperCase();
modeTitle = mode.getTitle();
modeTextFont = mode.getFont("mode.button.font");
modeButtonColor = mode.getColor("mode.button.color");
+
+ hiding = Preferences.getBoolean("buttons.hide.image");
+ hideColor = mode.getColor("buttons.hide.color");
if (modeArrow == null) {
String suffix = Toolkit.highResDisplay() ? "-2x.png" : ".png";
@@ -206,18 +211,25 @@ public abstract class EditorToolbar extends JComponent implements MouseInputList
if (Toolkit.highResDisplay()) {
// scale everything 2x, will be scaled down when drawn to the screen
g2.scale(2, 2);
+ if (Base.isUsableOracleJava()) {
+ // Oracle Java looks better with anti-aliasing turned on
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
} else {
- // don't anti-alias text in retina mode
+ // don't anti-alias text in retina mode w/ Apple Java
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
- g.setColor(bgcolor); //getBackground());
+ g.setColor(hiding ? hideColor : bgColor);
g.fillRect(0, 0, width, height);
// if (backgroundImage != null) {
// g.drawImage(backgroundImage, 0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, null);
// }
- mode.drawBackground(g, 0);
+ if (!hiding) {
+ mode.drawBackground(g, 0);
+ }
// for (int i = 0; i < buttonCount; i++) {
// g.drawImage(stateImage[i], x1[i], y1, null);
diff --git a/app/src/processing/app/Library.java b/app/src/processing/app/Library.java
index 2520bea15..7b8adc556 100644
--- a/app/src/processing/app/Library.java
+++ b/app/src/processing/app/Library.java
@@ -15,9 +15,10 @@ public class Library extends LocalContribution {
protected File examplesFolder; // shortname/examples
protected File referenceFile; // shortname/reference/index.html
- /**
- * Subfolder for grouping libraries in a menu. Basic subfolder support
- * is provided so that basic organization can be done in the import menu.
+ /**
+ * Subfolder for grouping libraries in a menu. Basic subfolder support
+ * is provided so that some organization can be done in the import menu.
+ * (This is the replacement for the "library compilation" type.)
*/
protected String group;
@@ -83,12 +84,27 @@ public class Library extends LocalContribution {
};
+ static public Library load(File folder) {
+ try {
+ return new Library(folder);
+// } catch (IgnorableException ig) {
+// Base.log(ig.getMessage());
+ } catch (Error err) {
+ // Handles UnsupportedClassVersionError and others
+ err.printStackTrace();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return null;
+ }
+
+
public Library(File folder) {
this(folder, null);
}
- public Library(File folder, String groupName) {
+ private Library(File folder, String groupName) {
super(folder);
this.group = groupName;
@@ -196,7 +212,6 @@ public class Library extends LocalContribution {
// get the path for all .jar files in this code folder
packageList = Base.packageListFromClassPath(getClassPath());
-
}
@@ -420,14 +435,14 @@ public class Library extends LocalContribution {
}
};
-
+
static public ArrayList discover(File folder) {
ArrayList libraries = new ArrayList();
discover(folder, libraries);
return libraries;
}
-
+
static public void discover(File folder, ArrayList libraries) {
String[] list = folder.list(junkFolderFilter);
@@ -462,14 +477,14 @@ public class Library extends LocalContribution {
}
}
-
+
static protected ArrayList list(File folder) {
ArrayList libraries = new ArrayList();
list(folder, libraries);
return libraries;
}
-
+
static protected void list(File folder, ArrayList libraries) {
ArrayList librariesFolders = new ArrayList();
discover(folder, librariesFolders);
@@ -495,7 +510,7 @@ public class Library extends LocalContribution {
}
}
-
+
public ContributionType getType() {
return ContributionType.LIBRARY;
}
diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java
index f45a6523b..0efa9c72e 100644
--- a/app/src/processing/app/Mode.java
+++ b/app/src/processing/app/Mode.java
@@ -959,9 +959,10 @@ public abstract class Mode {
s = st.nextToken();
boolean bold = (s.indexOf("bold") != -1);
- boolean italic = (s.indexOf("italic") != -1);
+// boolean italic = (s.indexOf("italic") != -1);
- return new SyntaxStyle(color, italic, bold);
+// return new SyntaxStyle(color, italic, bold);
+ return new SyntaxStyle(color, bold);
}
diff --git a/app/src/processing/app/Platform.java b/app/src/processing/app/Platform.java
index 2cf380e66..5b16bd5ff 100644
--- a/app/src/processing/app/Platform.java
+++ b/app/src/processing/app/Platform.java
@@ -24,12 +24,14 @@ package processing.app;
import java.awt.Desktop;
import java.io.File;
+import java.io.IOException;
import java.net.URI;
import javax.swing.UIManager;
import com.sun.jna.Library;
import com.sun.jna.Native;
+import com.sun.jna.platform.FileUtils;
/**
@@ -142,6 +144,30 @@ public class Platform {
}
*/
}
+
+
+ /**
+ * Attempts to move to the Trash on OS X, or the Recycle Bin on Windows.
+ * Also tries to find a suitable Trash location on Linux.
+ * If not possible, just deletes the file or folder instead.
+ * @param file the folder or file to be removed/deleted
+ * @return true if the folder was successfully removed
+ * @throws IOException
+ */
+ final public boolean deleteFile(File file) throws IOException {
+ FileUtils fu = FileUtils.getInstance();
+ if (fu.hasTrash()) {
+ fu.moveToTrash(new File[] { file });
+ return true;
+
+ } else if (file.isDirectory()) {
+ Base.removeDir(file);
+ return true;
+
+ } else {
+ return file.delete();
+ }
+ }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java
index 348b678c1..8c5d6dcde 100644
--- a/app/src/processing/app/Preferences.java
+++ b/app/src/processing/app/Preferences.java
@@ -29,7 +29,6 @@ import java.util.*;
import javax.swing.*;
-import processing.app.syntax.*;
import processing.core.*;
@@ -50,18 +49,18 @@ import processing.core.*;
* being lectured by strangers who feel that it doesn't look like what they
* learned in CS class.
*
- * Would also be possible to change this to use the Java Preferences API.
- * Some useful articles
- * here and
- * here.
- * However, haven't implemented this yet for lack of time, but more
- * importantly, because it would entail writing to the registry (on Windows),
- * or an obscure file location (on Mac OS X) and make it far more difficult to
- * find the preferences to tweak them by hand (no! stay out of regedit!)
- * or to reset the preferences by simply deleting the preferences.txt file.
+ * We don't use the Java Preferences API because it would entail writing to
+ * the registry (on Windows), or an obscure file location (on Mac OS X) and
+ * make it far more difficult (impossible) to remove the preferences.txt to
+ * reset them (when they become corrupt), or to find the the file to make
+ * edits for numerous obscure preferences that are not part of the preferences
+ * window. If we added a generic editor (e.g. about:config in Mozilla) for
+ * such things, we could start using the Java Preferences API. But wow, that
+ * sounds like a lot of work. Not unlike writing this paragraph.
*/
public class Preferences {
+ static final Integer[] FONT_SIZES = { 10, 12, 14, 18, 24, 36, 48 };
// what to call the feller
static final String PREFS_FILE = "preferences.txt"; //$NON-NLS-1$
@@ -109,24 +108,28 @@ public class Preferences {
JTextField sketchbookLocationField;
JCheckBox editorAntialiasBox;
-// JCheckBox exportSeparateBox;
JCheckBox deletePreviousBox;
-// JCheckBox externalEditorBox;
+ JCheckBox whinyBox;
JCheckBox memoryOverrideBox;
JTextField memoryField;
JCheckBox checkUpdatesBox;
- JTextField fontSizeField;
+ //JTextField fontSizeField;
+ JComboBox fontSizeField;
+ JComboBox consoleSizeField;
JCheckBox inputMethodBox;
JCheckBox autoAssociateBox;
- JRadioButton bitsThirtyTwoButton;
- JRadioButton bitsSixtyFourButton;
+
+ //JRadioButton bitsThirtyTwoButton;
+ //JRadioButton bitsSixtyFourButton;
+
JComboBox displaySelectionBox;
-
int displayCount;
+
+ //Font[] monoFontList;
+ String[] monoFontFamilies;
+ JComboBox fontSelectionBox;
- // the calling editor, so updates can be applied
-
-// Editor editor;
+ /** Base object so that updates can be applied to the list of editors. */
Base base;
@@ -142,7 +145,9 @@ public class Preferences {
// start by loading the defaults, in case something
// important was deleted from the user prefs
try {
- load(Base.getLibStream("preferences.txt")); //$NON-NLS-1$
+ // Name changed for 2.1b2 to avoid problems with users modifying or
+ // replacing the file after doing a search for "preferences.txt".
+ load(Base.getLibStream("defaults.txt")); //$NON-NLS-1$
} catch (Exception e) {
Base.showError(null, "Could not read default settings.\n" +
"You'll need to reinstall Processing.", e);
@@ -218,7 +223,18 @@ public class Preferences {
// }
}
- PApplet.useNativeSelect = Preferences.getBoolean("chooser.files.native"); //$NON-NLS-1$
+ PApplet.useNativeSelect =
+ Preferences.getBoolean("chooser.files.native"); //$NON-NLS-1$
+
+ // Set http proxy for folks that require it.
+ // http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
+ String proxyHost = get("proxy.host");
+ String proxyPort = get("proxy.port");
+ if (proxyHost != null && proxyHost.trim().length() != 0 &&
+ proxyPort != null && proxyPort.trim().length() != 0) {
+ System.setProperty("http.proxyHost", proxyHost);
+ System.setProperty("http.proxyPort", proxyPort);
+ }
}
@@ -229,6 +245,11 @@ public class Preferences {
dialog = new JFrame("Preferences");
dialog.setResizable(false);
+// GroupLayout layout = new GroupLayout(getContentPane());
+// dialog.getContentPane().setLayout(layout);
+// layout.setAutoCreateGaps(true);
+// layout.setAutoCreateContainerGaps(true);
+
Container pain = dialog.getContentPane();
pain.setLayout(null);
@@ -285,22 +306,7 @@ public class Preferences {
top += vmax + GUI_BETWEEN;
- // Editor font size [ ]
-
- Container box = Box.createHorizontalBox();
- label = new JLabel("Editor font size: ");
- box.add(label);
- fontSizeField = new JTextField(4);
- box.add(fontSizeField);
- label = new JLabel(" (requires restart of Processing)");
- box.add(label);
- pain.add(box);
- d = box.getPreferredSize();
- box.setBounds(left, top, d.width, d.height);
- Font editorFont = Preferences.getFont("editor.font");
- fontSizeField.setText(String.valueOf(editorFont.getSize()));
- top += d.height + GUI_BETWEEN;
-
+ // Editor and console font [ Source Code Pro ]
// Nevermind on this for now.. Java doesn't seem to have a method for
// enumerating only the fixed-width (monospaced) fonts. To do this
@@ -309,20 +315,65 @@ public class Preferences {
// we'd call that font fixed width. That's all a very expensive set of
// operations, so it should also probably be cached between runs and
// updated in the background.
+
+ Container fontBox = Box.createHorizontalBox();
+ JLabel fontLabel = new JLabel("Editor and Console font ");
+ final String fontTip = "" +
+ "Select the font used in the Editor and the Console. " +
+ "Only monospaced (fixed-width) fonts may be used, " +
+ "though the list may be imperfect.";
+ fontLabel.setToolTipText(fontTip);
+ fontBox.add(fontLabel);
+ // get a wide name in there before getPreferredSize() is called
+ fontSelectionBox = new JComboBox(new Object[] { Toolkit.getMonoFontName() });
+ fontSelectionBox.setToolTipText(fontTip);
+// fontSelectionBox.addItem(Toolkit.getMonoFont(size, style));
+ //updateDisplayList();
+ fontSelectionBox.setEnabled(false); // don't enable until fonts are loaded
+ fontBox.add(fontSelectionBox);
+// fontBox.add(Box.createHorizontalGlue());
+ pain.add(fontBox);
+ d = fontBox.getPreferredSize();
+ fontBox.setBounds(left, top, d.width + 150, d.height);
+// fontBox.setBounds(left, top, dialog.getWidth() - left*2, d.height);
+ top += d.height + GUI_BETWEEN;
-// // Editor font
-//
-// GraphicsEnvironment ge =
-// GraphicsEnvironment.getLocalGraphicsEnvironment();
-// Font fonts[] = ge.getAllFonts();
-// ArrayList monoFonts = new ArrayList();
+
+ // Editor font size [ 12 ] Console font size [ 10 ]
+ Container box = Box.createHorizontalBox();
+
+ label = new JLabel("Editor font size: ");
+ box.add(label);
+ //fontSizeField = new JTextField(4);
+ fontSizeField = new JComboBox(FONT_SIZES);
+ fontSizeField.setEditable(true);
+ box.add(fontSizeField);
+// label = new JLabel(" (requires restart of Processing)");
+// box.add(label);
+ box.add(Box.createHorizontalStrut(GUI_BETWEEN));
+ label = new JLabel("Console font size: ");
+ box.add(label);
+ consoleSizeField = new JComboBox(FONT_SIZES);
+ consoleSizeField.setEditable(true);
+ box.add(consoleSizeField);
+
+ pain.add(box);
+ d = box.getPreferredSize();
+ box.setBounds(left, top, d.width, d.height);
+// Font editorFont = Preferences.getFont("editor.font");
+ //fontSizeField.setText(String.valueOf(editorFont.getSize()));
+// fontSizeField.setSelectedItem(editorFont.getSize());
+ fontSizeField.setSelectedItem(Preferences.getFont("editor.font.size"));
+ top += d.height + GUI_BETWEEN;
+
+
// [ ] Use smooth text in editor window
- editorAntialiasBox =
- new JCheckBox("Use smooth text in editor window " +
- "(requires restart of Processing)");
+ editorAntialiasBox = new JCheckBox("Use smooth text in editor window");
+// new JCheckBox("Use smooth text in editor window " +
+// "(requires restart of Processing)");
pain.add(editorAntialiasBox);
d = editorAntialiasBox.getPreferredSize();
// adding +10 because ubuntu + jre 1.5 truncating items
@@ -370,10 +421,10 @@ public class Preferences {
// top += d.height + GUI_BETWEEN;
- // [ ] Delete previous folder on export
+ // [ ] Delete previous application folder on export
deletePreviousBox =
- new JCheckBox("Delete previous folder on export");
+ new JCheckBox("Delete previous application folder on export");
pain.add(deletePreviousBox);
d = deletePreviousBox.getPreferredSize();
deletePreviousBox.setBounds(left, top, d.width + 10, d.height);
@@ -390,6 +441,16 @@ public class Preferences {
// right = Math.max(right, left + d.width);
// top += d.height + GUI_BETWEEN;
+
+ // [ ] Use external editor
+
+ whinyBox = new JCheckBox("Hide tab/toolbar background image (requires restart)");
+ pain.add(whinyBox);
+ d = whinyBox.getPreferredSize();
+ whinyBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+
// [ ] Check for updates on startup
@@ -436,6 +497,7 @@ public class Preferences {
// Launch programs as [ ] 32-bit [ ] 64-bit (Mac OS X only)
+ /*
if (Base.isMacOS()) {
box = Box.createHorizontalBox();
label = new JLabel("Launch programs in ");
@@ -454,6 +516,7 @@ public class Preferences {
box.setBounds(left, top, d.width, d.height);
top += d.height + GUI_BETWEEN;
}
+ */
// More preferences are in the ...
@@ -600,17 +663,18 @@ public class Preferences {
* then send a message to the editor saying that it's time to do the same.
*/
protected void applyFrame() {
- setBoolean("editor.antialias", editorAntialiasBox.isSelected()); //$NON-NLS-1$
+ setBoolean("editor.smooth", //$NON-NLS-1$
+ editorAntialiasBox.isSelected());
-// setBoolean("export.applet.separate_jar_files",
-// exportSeparateBox.isSelected());
setBoolean("export.delete_target_folder", //$NON-NLS-1$
deletePreviousBox.isSelected());
-// setBoolean("sketchbook.closing_last_window_quits",
-// closingLastQuitsBox.isSelected());
- //setBoolean("sketchbook.prompt", sketchPromptBox.isSelected());
- //setBoolean("sketchbook.auto_clean", sketchCleanBox.isSelected());
+ boolean wine = whinyBox.isSelected();
+ setBoolean("header.hide.image", wine); //$NON-NLS-1$
+ setBoolean("buttons.hide.image", wine); //$NON-NLS-1$
+ // Could iterate through editors here and repaint them all, but probably
+ // requires a doLayout() call, and that may have different effects on
+ // each platform, and nobody wants to debug/support that.
// if the sketchbook path has changed, rebuild the menus
String oldPath = get("sketchbook.path"); //$NON-NLS-1$
@@ -660,6 +724,7 @@ public class Preferences {
}
*/
+ /*
// If a change has been made between 32- and 64-bit, the libraries need
// to be reloaded so that their native paths are set correctly.
if (Base.isMacOS()) {
@@ -672,16 +737,51 @@ public class Preferences {
}
}
}
+ */
+ // Don't change anything if the user closes the window before fonts load
+ if (fontSelectionBox.isEnabled()) {
+ String fontFamily = (String) fontSelectionBox.getSelectedItem();
+ set("editor.font.family", fontFamily);
+ }
+
+ /*
String newSizeText = fontSizeField.getText();
try {
int newSize = Integer.parseInt(newSizeText.trim());
- String pieces[] = PApplet.split(get("editor.font"), ','); //$NON-NLS-1$
- pieces[2] = String.valueOf(newSize);
- set("editor.font", PApplet.join(pieces, ',')); //$NON-NLS-1$
+ //String pieces[] = PApplet.split(get("editor.font"), ','); //$NON-NLS-1$
+ //pieces[2] = String.valueOf(newSize);
+ //set("editor.font", PApplet.join(pieces, ',')); //$NON-NLS-1$
+ set("editor.font.size", String.valueOf(newSize));
} catch (Exception e) {
- Base.log("ignoring invalid font size " + newSizeText); //$NON-NLS-1$
+ Base.log("Ignoring invalid font size " + newSizeText); //$NON-NLS-1$
+ }
+ */
+ try {
+ Object selection = fontSizeField.getSelectedItem();
+ if (selection instanceof String) {
+ // Replace with Integer version
+ selection = Integer.parseInt((String) selection);
+ }
+ set("editor.font.size", String.valueOf(selection));
+
+ } catch (NumberFormatException e) {
+ Base.log("Ignoring invalid font size " + fontSizeField); //$NON-NLS-1$
+ fontSizeField.setSelectedItem(getInteger("editor.font.size"));
+ }
+
+ try {
+ Object selection = consoleSizeField.getSelectedItem();
+ if (selection instanceof String) {
+ // Replace with Integer version
+ selection = Integer.parseInt((String) selection);
+ }
+ set("console.font.size", String.valueOf(selection));
+
+ } catch (NumberFormatException e) {
+ Base.log("Ignoring invalid font size " + consoleSizeField); //$NON-NLS-1$
+ consoleSizeField.setSelectedItem(getInteger("console.font.size"));
}
setBoolean("editor.input_method_support", inputMethodBox.isSelected()); //$NON-NLS-1$
@@ -698,7 +798,7 @@ public class Preferences {
protected void showFrame() {
- editorAntialiasBox.setSelected(getBoolean("editor.antialias")); //$NON-NLS-1$
+ editorAntialiasBox.setSelected(getBoolean("editor.smooth")); //$NON-NLS-1$
inputMethodBox.setSelected(getBoolean("editor.input_method_support")); //$NON-NLS-1$
// set all settings entry boxes to their actual status
@@ -721,6 +821,9 @@ public class Preferences {
checkUpdatesBox.
setSelected(getBoolean("update.check")); //$NON-NLS-1$
+ whinyBox.setSelected(getBoolean("header.hide.image") || //$NON-NLS-1$
+ getBoolean("buttons.hide.image")); //$NON-NLS-1$
+
updateDisplayList();
int displayNum = getInteger("run.display"); //$NON-NLS-1$
// System.out.println("display is " + displayNum + ", d count is " + displayCount);
@@ -728,12 +831,23 @@ public class Preferences {
// System.out.println("setting num to " + displayNum);
displaySelectionBox.setSelectedIndex(displayNum);
}
+
+ // This takes a while to load, so run it from a separate thread
+ new Thread(new Runnable() {
+ public void run() {
+ initFontList();
+ }
+ }).start();
+
+ fontSizeField.setSelectedItem(getInteger("editor.font.size"));
+ consoleSizeField.setSelectedItem(getInteger("console.font.size"));
memoryOverrideBox.
setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$
memoryField.
setText(get("run.options.memory.maximum")); //$NON-NLS-1$
+ /*
if (Base.isMacOS()) {
String bits = Preferences.get("run.options.bits"); //$NON-NLS-1$
if (bits.equals("32")) { //$NON-NLS-1$
@@ -747,6 +861,7 @@ public class Preferences {
bitsThirtyTwoButton.setEnabled(false);
}
}
+ */
if (autoAssociateBox != null) {
autoAssociateBox.
@@ -757,6 +872,63 @@ public class Preferences {
}
+ /**
+ * I have some ideas on how we could make Swing even more obtuse for the
+ * most basic usage scenarios. Is there someone on the team I can contact?
+ * Oracle, are you listening?
+ */
+ class FontNamer extends JLabel implements ListCellRenderer {
+ public Component getListCellRendererComponent(JList extends Font> list,
+ Font value, int index,
+ boolean isSelected,
+ boolean cellHasFocus) {
+ //if (Base.isMacOS()) {
+ setText(value.getFamily() + " / " + value.getName() + " (" + value.getPSName() + ")");
+ return this;
+ }
+ }
+
+
+ void initFontList() {
+ /*
+ if (monoFontList == null) {
+ monoFontList = Toolkit.getMonoFontList().toArray(new Font[0]);
+ fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontList));
+ fontSelectionBox.setRenderer(new FontNamer());
+
+ // Preferred size just makes it extend to the container
+ //fontSelectionBox.setSize(fontSelectionBox.getPreferredSize());
+ // Minimum size is better, but cuts things off (on OS X), so we add 20
+ //Dimension minSize = fontSelectionBox.getMinimumSize();
+ //Dimension minSize = fontSelectionBox.getPreferredSize();
+ //fontSelectionBox.setSize(minSize.width + 20, minSize.height);
+ fontSelectionBox.setEnabled(true);
+ }
+ */
+ if (monoFontFamilies == null) {
+ monoFontFamilies = Toolkit.getMonoFontFamilies();
+ fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies));
+ String family = get("editor.font.family");
+// System.out.println("family is " + family);
+// System.out.println("font sel items = " + fontSelectionBox.getItemCount());
+// for (int i = 0; i < fontSelectionBox.getItemCount(); i++) {
+// String item = (String) fontSelectionBox.getItemAt(i);
+// if (fontSelectionBox.getItemAt(i) == family) {
+// System.out.println("found at index " + i);
+// } else if (item.equals(family)) {
+// System.out.println("equals at index " + i);
+// } else {
+// System.out.println("nothing doing: " + item);
+// }
+// }
+ // Set a reasonable default, in case selecting the family fails
+ fontSelectionBox.setSelectedItem("Monospaced");
+ fontSelectionBox.setSelectedItem(family);
+ fontSelectionBox.setEnabled(true);
+ }
+ }
+
+
void updateDisplayList() {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
displayCount = ge.getScreenDevices().length;
@@ -999,6 +1171,7 @@ public class Preferences {
}
+ /*
static public SyntaxStyle getStyle(String what) {
String str = get("editor." + what + ".style"); //, dflt); //$NON-NLS-1$ //$NON-NLS-2$
@@ -1013,9 +1186,11 @@ public class Preferences {
s = st.nextToken();
boolean bold = (s.indexOf("bold") != -1); //$NON-NLS-1$
- boolean italic = (s.indexOf("italic") != -1); //$NON-NLS-1$
+// boolean italic = (s.indexOf("italic") != -1); //$NON-NLS-1$
//System.out.println(what + " = " + str + " " + bold + " " + italic);
- return new SyntaxStyle(color, italic, bold);
+// return new SyntaxStyle(color, italic, bold);
+ return new SyntaxStyle(color, bold);
}
+ */
}
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
index 4b941413a..669452b8c 100644
--- a/app/src/processing/app/Sketch.java
+++ b/app/src/processing/app/Sketch.java
@@ -32,7 +32,7 @@ import javax.swing.*;
/**
- * Stores information about files in the current sketch
+ * Stores information about files in the current sketch.
*/
public class Sketch {
private Editor editor;
@@ -70,7 +70,7 @@ public class Sketch {
*/
private int codeCount;
private SketchCode[] code;
-
+
/** Moved out of Editor and into here for cleaner access. */
private boolean untitled;
@@ -536,6 +536,13 @@ public class Sketch {
return;
}
+ // don't allow if untitled
+ if (currentIndex == 0 && isUntitled()) {
+ Base.showMessage("Cannot Delete",
+ "You can't delete a sketch that has not been saved.");
+ return;
+ }
+
// confirm deletion with user, yes/no
Object[] options = { "OK", "Cancel" };
String prompt = (currentIndex == 0) ?
@@ -1420,7 +1427,7 @@ public class Sketch {
String msg =
"The sketch name had to be modified. Sketch names can only consist\n" +
"of ASCII characters and numbers (but cannot start with a number).\n" +
- "They should also be less less than 64 characters long.";
+ "They should also be less than 64 characters long.";
System.out.println(msg);
}
return newName;
@@ -1441,8 +1448,8 @@ public class Sketch {
static final boolean asciiLetter(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
-
-
+
+
/**
* Produce a sanitized name that fits our standards for likely to work.
*
@@ -1457,14 +1464,14 @@ public class Sketch {
* underscores. Also disallows starting the sketch name with a digit
* or underscore.
*
- * In Processing 2.0, sketches can no longer begin with an underscore,
+ * In Processing 2.0, sketches can no longer begin with an underscore,
* because these aren't valid class names on Android.
*/
static public String sanitizeName(String origName) {
char orig[] = origName.toCharArray();
StringBuffer buffer = new StringBuffer();
- // Can't lead with a digit (or anything besides a letter), so prefix with
+ // Can't lead with a digit (or anything besides a letter), so prefix with
// "sketch_". In 1.x this prefixed with an underscore, but those get shaved
// off later, since you can't start a sketch name with underscore anymore.
if (!asciiLetter(orig[0])) {
@@ -1476,8 +1483,8 @@ public class Sketch {
buffer.append(c);
} else {
- // Tempting to only add if prev char is not underscore, but that
- // might be more confusing if lots of chars are converted and the
+ // Tempting to only add if prev char is not underscore, but that
+ // might be more confusing if lots of chars are converted and the
// result is a very short string thats nothing like the original.
buffer.append('_');
}
diff --git a/app/src/processing/app/SketchCode.java b/app/src/processing/app/SketchCode.java
index 0a37efd20..8deaedbe7 100644
--- a/app/src/processing/app/SketchCode.java
+++ b/app/src/processing/app/SketchCode.java
@@ -31,7 +31,7 @@ import javax.swing.undo.*;
/**
- * Represents a single tab of a sketch.
+ * Represents a single tab of a sketch.
*/
public class SketchCode {
/** Pretty name (no extension), not the full file name */
@@ -40,12 +40,12 @@ public class SketchCode {
/** File object for where this code is located */
private File file;
- /** Extension for this file (no dots, and in lowercase). */
+ /** Extension for this file (no dots, and in lowercase). */
private String extension;
/** Text of the program text for this tab */
private String program;
-
+
/** Last version of the program on disk. */
private String savedProgram;
@@ -54,15 +54,15 @@ public class SketchCode {
/** Last time this tab was visited */
long visited;
-
+
/**
* Undo Manager for this tab, each tab keeps track of their own
* Editor.undo will be set to this object when this code is the tab
* that's currently the front.
*/
private UndoManager undo = new UndoManager();
-
- /** What was on top of the undo stack when last saved. */
+
+ /** What was on top of the undo stack when last saved. */
// private UndoableEdit lastEdit;
// saved positions from last time this tab was used
@@ -73,9 +73,9 @@ public class SketchCode {
private boolean modified;
/** name of .java file after preproc */
-// private String preprocName;
+// private String preprocName;
/** where this code starts relative to the concat'd code */
- private int preprocOffset;
+ private int preprocOffset;
public SketchCode(File file, String extension) {
@@ -102,23 +102,23 @@ public class SketchCode {
public File getFile() {
return file;
}
-
-
+
+
protected boolean fileExists() {
return file.exists();
}
-
-
+
+
protected boolean fileReadOnly() {
return !file.canWrite();
}
-
-
+
+
protected boolean deleteFile() {
return file.delete();
}
-
-
+
+
protected boolean renameTo(File what, String ext) {
// System.out.println("renaming " + file);
// System.out.println(" to " + what);
@@ -130,32 +130,32 @@ public class SketchCode {
}
return success;
}
-
-
+
+
public void copyTo(File dest) throws IOException {
Base.saveFile(program, dest);
}
-
+
public String getFileName() {
return file.getName();
}
-
-
+
+
public String getPrettyName() {
return prettyName;
}
-
-
+
+
public String getExtension() {
return extension;
}
-
-
+
+
public boolean isExtension(String what) {
return extension.equals(what);
}
-
+
/** get the current text for this tab */
public String getProgram() {
@@ -174,12 +174,12 @@ public class SketchCode {
return savedProgram;
}
-
+
public int getLineCount() {
return Base.countLines(program);
}
-
-
+
+
public void setModified(boolean modified) {
this.modified = modified;
}
@@ -208,8 +208,8 @@ public class SketchCode {
public int getPreprocOffset() {
return preprocOffset;
}
-
-
+
+
public void addPreprocOffset(int extra) {
preprocOffset += extra;
}
@@ -218,72 +218,81 @@ public class SketchCode {
public Document getDocument() {
return document;
}
-
-
+
+
public void setDocument(Document d) {
document = d;
}
-
-
+
+
public UndoManager getUndo() {
return undo;
}
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
// TODO these could probably be handled better, since it's a general state
// issue that's read/write from only one location in Editor (on tab switch.)
-
-
+
+
public int getSelectionStart() {
return selectionStart;
}
-
-
+
+
public int getSelectionStop() {
return selectionStop;
}
-
-
+
+
public int getScrollPosition() {
return scrollPosition;
}
-
-
+
+
protected void setState(String p, int start, int stop, int pos) {
program = p;
selectionStart = start;
selectionStop = stop;
scrollPosition = pos;
}
-
+
public long lastVisited() {
return visited;
}
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
/**
* Load this piece of code from a file.
*/
public void load() throws IOException {
program = Base.loadFile(file);
+
+ // Remove NUL characters because they'll cause problems,
+ // and their presence is very difficult to debug.
+ // https://github.com/processing/processing/issues/1973
+ if (program.indexOf('\0') != -1) {
+ program = program.replaceAll("\0", "");
+ }
savedProgram = program;
+ // This used to be the "Fix Encoding and Reload" warning, but since that
+ // tool has been removed, it just rambles about text editors and encodings.
if (program.indexOf('\uFFFD') != -1) {
- System.err.println(file.getName() + " contains unrecognized characters.");
- System.err.println("If this code was created with an older version of Processing,");
- System.err.println("you may need to use Tools -> Fix Encoding & Reload to update");
- System.err.println("the sketch to use UTF-8 encoding. If not, you may need to");
+ System.err.println(file.getName() + " contains unrecognized characters.");
+ System.err.println("You should re-open " + file.getName() +
+ " with a text editor,");
+ System.err.println("and re-save it in UTF-8 format. Otherwise, you can");
System.err.println("delete the bad characters to get rid of this warning.");
System.err.println();
}
-
+
setModified(false);
}
@@ -312,11 +321,11 @@ public class SketchCode {
makePrettyName();
setModified(false);
}
-
-
+
+
/**
- * Called when the sketch folder name/location has changed. Called when
- * renaming tab 0, the main code.
+ * Called when the sketch folder name/location has changed. Called when
+ * renaming tab 0, the main code.
*/
public void setFolder(File sketchFolder) {
file = new File(sketchFolder, file.getName());
diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java
old mode 100755
new mode 100644
index 34c68eed9..e549371af
--- a/app/src/processing/app/Toolkit.java
+++ b/app/src/processing/app/Toolkit.java
@@ -27,6 +27,8 @@ import java.awt.FontFormatException;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionEvent;
@@ -34,11 +36,15 @@ import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
@@ -216,24 +222,58 @@ public class Toolkit {
return awtToolkit.getSystemClipboard();
}
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ static Boolean highResProp;
- static Boolean retinaProp;
static public boolean highResDisplay() {
+ if (highResProp == null) {
+ highResProp = checkRetina();
+ }
+ return highResProp;
+ }
+
+
+ static private boolean checkRetina() {
if (Base.isMacOS()) {
- // 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 API.
- // Also, should we use the Toolkit associated with the editor window?
- if (retinaProp == null) {
+ // 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 API.
+ // Also, should we use the Toolkit associated with the editor window?
+// String javaVendor = System.getProperty("java.vendor");
+// if (javaVendor.contains("Apple")) {
+ if (System.getProperty("java.vendor").contains("Apple")) {
Float prop = (Float)
awtToolkit.getDesktopProperty("apple.awt.contentScaleFactor");
if (prop != null) {
- retinaProp = prop == 2;
- } else {
- retinaProp = false;
+ return prop == 2;
}
+// } else if (javaVendor.contains("Oracle")) {
+// String version = System.getProperty("java.version"); // 1.7.0_40
+// String[] m = PApplet.match(version, "1.(\\d).*_(\\d+)");
+//
+// // Make sure this is Oracle Java 7u40 or later
+// if (m != null &&
+// PApplet.parseInt(m[1]) >= 7 &&
+// PApplet.parseInt(m[1]) >= 40) {
+ } else if (Base.isUsableOracleJava()) {
+ GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice device = env.getDefaultScreenDevice();
+
+ try {
+ Field field = device.getClass().getDeclaredField("scale");
+ if (field != null) {
+ field.setAccessible(true);
+ Object scale = field.get(device);
+
+ if (scale instanceof Integer && ((Integer)scale).intValue() == 2) {
+ return true;
+ }
+ }
+ } catch (Exception ignore) { }
}
- return retinaProp;
}
return false;
}
@@ -283,17 +323,81 @@ public class Toolkit {
// }
+ // Gets the plain (not bold, not italic) version of each
+ static private List getMonoFontList() {
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ Font[] fonts = ge.getAllFonts();
+ ArrayList outgoing = new ArrayList();
+ // Using AffineTransform.getScaleInstance(100, 100) doesn't change sizes
+ FontRenderContext frc =
+ new FontRenderContext(new AffineTransform(),
+ Preferences.getBoolean("editor.antialias"),
+ true); // use fractional metrics
+ for (Font font : fonts) {
+ if (font.getStyle() == Font.PLAIN &&
+ font.canDisplay('i') && font.canDisplay('M') &&
+ font.canDisplay(' ') && font.canDisplay('.')) {
+
+ // The old method just returns 1 or 0, and using deriveFont(size)
+ // is overkill. It also causes deprecation warnings
+// @SuppressWarnings("deprecation")
+// FontMetrics fm = awtToolkit.getFontMetrics(font);
+ //FontMetrics fm = awtToolkit.getFontMetrics(font.deriveFont(24));
+// System.out.println(fm.charWidth('i') + " " + fm.charWidth('M'));
+// if (fm.charWidth('i') == fm.charWidth('M') &&
+// fm.charWidth('M') == fm.charWidth(' ') &&
+// fm.charWidth(' ') == fm.charWidth('.')) {
+ double w = font.getStringBounds(" ", frc).getWidth();
+ if (w == font.getStringBounds("i", frc).getWidth() &&
+ w == font.getStringBounds("M", frc).getWidth() &&
+ w == font.getStringBounds(".", frc).getWidth()) {
+
+// //PApplet.printArray(font.getAvailableAttributes());
+// Map attr = font.getAttributes();
+// System.out.println(font.getFamily() + " > " + font.getName());
+// System.out.println(font.getAttributes());
+// System.out.println(" " + attr.get(TextAttribute.WEIGHT));
+// System.out.println(" " + attr.get(TextAttribute.POSTURE));
+
+ outgoing.add(font);
+// System.out.println(" good " + w);
+ }
+ }
+ }
+ return outgoing;
+ }
+
+
+ static public String[] getMonoFontFamilies() {
+ HashSet families = new HashSet();
+ for (Font font : getMonoFontList()) {
+ families.add(font.getFamily());
+ }
+ return families.toArray(new String[0]);
+ }
+
+
static Font monoFont;
static Font monoBoldFont;
static Font sansFont;
static Font sansBoldFont;
+ static public String getMonoFontName() {
+ if (monoFont == null) {
+ getMonoFont(12, Font.PLAIN); // load a dummy version
+ }
+ return monoFont.getName();
+ }
+
+
static public Font getMonoFont(int size, int style) {
if (monoFont == null) {
try {
monoFont = createFont("SourceCodePro-Regular.ttf", size);
- monoBoldFont = createFont("SourceCodePro-Semibold.ttf", size);
+ //monoBoldFont = createFont("SourceCodePro-Semibold.ttf", size);
+ monoBoldFont = createFont("SourceCodePro-Bold.ttf", size);
} catch (Exception e) {
Base.log("Could not load mono font", e);
monoFont = new Font("Monospaced", Font.PLAIN, size);
@@ -304,20 +408,15 @@ public class Toolkit {
if (size == monoBoldFont.getSize()) {
return monoBoldFont;
} else {
-// System.out.println("deriving new font");
return monoBoldFont.deriveFont((float) size);
}
} else {
if (size == monoFont.getSize()) {
return monoFont;
} else {
-// System.out.println("deriving new font");
return monoFont.deriveFont((float) size);
}
}
-// return style == Font.BOLD ?
-// monoBoldFont.deriveFont((float) size) :
-// monoFont.deriveFont((float) size);
}
@@ -328,26 +427,20 @@ public class Toolkit {
sansBoldFont = createFont("SourceSansPro-Semibold.ttf", size);
} catch (Exception e) {
Base.log("Could not load sans font", e);
- sansFont = new Font("Monospaced", Font.PLAIN, size);
- sansBoldFont = new Font("Monospaced", Font.BOLD, size);
+ sansFont = new Font("SansSerif", Font.PLAIN, size);
+ sansBoldFont = new Font("SansSerif", Font.BOLD, size);
}
}
-// System.out.println("deriving new font");
-// return style == Font.BOLD ?
-// sansBoldFont.deriveFont((float) size) :
-// sansFont.deriveFont((float) size);
if (style == Font.BOLD) {
if (size == sansBoldFont.getSize()) {
return sansBoldFont;
} else {
-// System.out.println("deriving new font");
return sansBoldFont.deriveFont((float) size);
}
} else {
if (size == sansFont.getSize()) {
return sansFont;
} else {
-// System.out.println("deriving new font");
return sansFont.deriveFont((float) size);
}
}
diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java
index e387e527a..b4cb57cd4 100644
--- a/app/src/processing/app/contrib/AvailableContribution.java
+++ b/app/src/processing/app/contrib/AvailableContribution.java
@@ -41,7 +41,8 @@ class AvailableContribution extends Contribution {
this.type = type;
this.link = params.get("download");
- category = ContributionListing.getCategory(params.get("category"));
+ //category = ContributionListing.getCategory(params.get("category"));
+ categories = parseCategories(params.get("category"));
name = params.get("name");
authorList = params.get("authorList");
url = params.get("url");
@@ -65,12 +66,11 @@ class AvailableContribution extends Contribution {
// Unzip the file into the modes, tools, or libraries folder inside the
// sketchbook. Unzipping to /tmp is problematic because it may be on
// another file system, so move/rename operations will break.
- File sketchbookContribFolder = type.getSketchbookFolder();
+// File sketchbookContribFolder = type.getSketchbookFolder();
File tempFolder = null;
try {
- tempFolder =
- Base.createTempFolder(type.toString(), "tmp", sketchbookContribFolder);
+ tempFolder = type.createTempFolder();
} catch (IOException e) {
status.setErrorMessage("Could not create a temporary folder to install.");
return null;
@@ -121,10 +121,36 @@ class AvailableContribution extends Contribution {
LocalContribution newContrib =
type.load(editor.getBase(), contribFolder);
+ // 1.1. get info we need to delete the newContrib folder later
+ File newContribFolder = newContrib.getFolder();
+
// 2. Check to make sure nothing has the same name already,
// backup old if needed, then move things into place and reload.
installedContrib =
- newContrib.moveAndLoad(editor, confirmReplace, status);
+ newContrib.copyAndLoad(editor, confirmReplace, status);
+ if (newContrib != null && type.requiresRestart()) {
+ installedContrib.setRestartFlag();
+ //status.setMessage("Restart Processing to finish the installation.");
+ }
+
+ // 3. Delete the newContrib, do a garbage collection, hope and pray
+ // that Java will unlock the temp folder on Windows now
+ newContrib = null;
+ System.gc();
+
+
+ if (Base.isWindows()) {
+ // we'll even give it a second to finish up ... because file ops are
+ // just that flaky on Windows.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 4. Okay, now actually delete that temp folder
+ Base.removeDir(newContribFolder);
} else {
status.setErrorMessage("Error overwriting .properties file.");
@@ -163,7 +189,7 @@ class AvailableContribution extends Contribution {
PrintWriter writer = PApplet.createWriter(propFile);
writer.println("name=" + getName());
- writer.println("category=" + getCategory());
+ writer.println("category=" + getCategoryStr());
writer.println("authorList=" + getAuthorList());
writer.println("url=" + getUrl());
writer.println("sentence=" + getSentence());
diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java
index 759b85537..8367b98d3 100644
--- a/app/src/processing/app/contrib/Contribution.java
+++ b/app/src/processing/app/contrib/Contribution.java
@@ -21,9 +21,21 @@
*/
package processing.app.contrib;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import processing.core.PApplet;
+
abstract public class Contribution {
- protected String category; // "Sound"
+ static final List validCategories =
+ Arrays.asList("3D", "Animation", "Data", "Geometry", "GUI", "Hardware",
+ "I/O", "Math", "Simulation", "Sound", "Typography",
+ "Utilities", "Video & Vision", "Other");
+
+ //protected String category; // "Sound"
+ protected List categories; // "Sound", "Typography"
protected String name; // "pdf" or "PDF Export"
protected String authorList; // Ben Fry
protected String url; // http://processing.org
@@ -34,8 +46,37 @@ abstract public class Contribution {
// "Sound"
- public String getCategory() {
- return category;
+// public String getCategory() {
+// return category;
+// }
+
+
+ // "Sound", "Utilities"... see valid list in ContributionListing
+ protected List getCategories() {
+ return categories;
+ }
+
+
+ protected String getCategoryStr() {
+ StringBuilder sb = new StringBuilder();
+ for (String category : categories) {
+ sb.append(category);
+ sb.append(',');
+ }
+ sb.deleteCharAt(sb.length()-1); // delete last comma
+ return sb.toString();
+ }
+
+
+ protected boolean hasCategory(String category) {
+ if (category != null) {
+ for (String c : categories) {
+ if (category.equalsIgnoreCase(c)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
@@ -92,17 +133,54 @@ abstract public class Contribution {
abstract public boolean isInstalled();
- /**
- * Returns true if the type of contribution requires the PDE to restart
- * when being added or removed.
- */
- public boolean requiresRestart() {
- return getType() == ContributionType.TOOL || getType() == ContributionType.MODE;
- }
+// /**
+// * Returns true if the type of contribution requires the PDE to restart
+// * when being added or removed.
+// */
+// public boolean requiresRestart() {
+// return getType() == ContributionType.TOOL || getType() == ContributionType.MODE;
+// }
- /** Overridden by InstalledContribution. */
+ boolean isRestartFlagged() {
+ return false;
+ }
+
+
+ /** Overridden by LocalContribution. */
boolean isDeletionFlagged() {
return false;
}
+
+
+ /**
+ * @return a single element list with "Unknown" as the category.
+ */
+ static List defaultCategory() {
+ List outgoing = new ArrayList();
+ outgoing.add("Unknown");
+ return outgoing;
+ }
+
+
+ /**
+ * @return the list of categories that this contribution is part of
+ * (e.g. "Typography / Geometry"). "Unknown" if the category null.
+ */
+ static List parseCategories(String categoryStr) {
+ List outgoing = new ArrayList();
+
+ if (categoryStr != null) {
+ String[] listing = PApplet.trim(PApplet.split(categoryStr, ','));
+ for (String category : listing) {
+ if (validCategories.contains(category)) {
+ outgoing.add(category);
+ }
+ }
+ }
+ if (outgoing.size() == 0) {
+ return defaultCategory();
+ }
+ return outgoing;
+ }
}
diff --git a/app/src/processing/app/contrib/ContributionListPanel.java b/app/src/processing/app/contrib/ContributionListPanel.java
index e25537cf7..2fc5922fa 100644
--- a/app/src/processing/app/contrib/ContributionListPanel.java
+++ b/app/src/processing/app/contrib/ContributionListPanel.java
@@ -36,14 +36,11 @@ import processing.app.Base;
// The "Scrollable" implementation and its methods here take care of preventing
// the scrolling area from running exceptionally slowly. Not sure why they're
-// necessary in the first place, however; seems like odd behavior.
+// necessary in the first place, however; seems like odd behavior.
+// It also allows the description text in the panels to wrap properly.
public class ContributionListPanel extends JPanel implements Scrollable, ContributionChangeListener {
- static public final String DELETION_MESSAGE =
- "This tool has been flagged for deletion. " +
- "Restart Proessing to finalize the removal process.";
-
static public final String INSTALL_FAILURE_TITLE = "Install Failed";
static public final String MALFORMED_URL_MESSAGE =
diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java
index aa05a72c5..05531f63d 100644
--- a/app/src/processing/app/contrib/ContributionListing.java
+++ b/app/src/processing/app/contrib/ContributionListing.java
@@ -15,7 +15,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
+ You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -31,11 +31,12 @@ import processing.core.PApplet;
public class ContributionListing {
- static final String LISTING_URL =
- "https://raw.github.com/processing/processing-web/master/contrib_generate/contributions.txt";
+ // Stable URL that will redirect to wherever we're hosting the file
+ static final String LISTING_URL =
+ "http://download.processing.org/contributions.txt";
static ContributionListing singleInstance;
-
+
File listingFile;
ArrayList listeners;
ArrayList advertisedContributions;
@@ -44,12 +45,6 @@ public class ContributionListing {
boolean hasDownloadedLatestList;
ReentrantLock downloadingListingLock;
- static final String[] validCategories = {
- "3D", "Animation", "Compilations", "Data", "Geometry", "GUI",
- "Hardware", "I/O", "Math", "Simulation", "Sound", "Typography",
- "Utilities", "Video & Vision"
- };
-
private ContributionListing() {
listeners = new ArrayList();
@@ -85,16 +80,17 @@ public class ContributionListing {
Collections.sort(allContributions, nameComparator);
}
-
+
/**
* Adds the installed libraries to the listing of libraries, replacing any
* pre-existing libraries by the same name as one in the list.
*/
protected void updateInstalledList(List installedContributions) {
for (Contribution contribution : installedContributions) {
- Contribution preexistingContribution = getContribution(contribution);
- if (preexistingContribution != null) {
- replaceContribution(preexistingContribution, contribution);
+ Contribution existingContribution = getContribution(contribution);
+ if (existingContribution != null) {
+ replaceContribution(existingContribution, contribution);
+ //} else if (contribution != null) { // 130925 why would this be necessary?
} else {
addContribution(contribution);
}
@@ -103,59 +99,63 @@ public class ContributionListing {
protected void replaceContribution(Contribution oldLib, Contribution newLib) {
- if (oldLib == null || newLib == null) {
- return;
- }
+ if (oldLib != null && newLib != null) {
+ for (String category : oldLib.getCategories()) {
+ if (librariesByCategory.containsKey(category)) {
+ List list = librariesByCategory.get(category);
- if (librariesByCategory.containsKey(oldLib.getCategory())) {
- List list = librariesByCategory.get(oldLib.getCategory());
-
- for (int i = 0; i < list.size(); i++) {
- if (list.get(i) == oldLib) {
- list.set(i, newLib);
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i) == oldLib) {
+ list.set(i, newLib);
+ }
+ }
}
}
- }
- for (int i = 0; i < allContributions.size(); i++) {
- if (allContributions.get(i) == oldLib) {
- allContributions.set(i, newLib);
+ for (int i = 0; i < allContributions.size(); i++) {
+ if (allContributions.get(i) == oldLib) {
+ allContributions.set(i, newLib);
+ }
}
- }
- notifyChange(oldLib, newLib);
+ notifyChange(oldLib, newLib);
+ }
}
private void addContribution(Contribution contribution) {
- if (librariesByCategory.containsKey(contribution.getCategory())) {
- List list = librariesByCategory.get(contribution.getCategory());
- list.add(contribution);
- Collections.sort(list, nameComparator);
-
- } else {
- ArrayList list = new ArrayList();
- list.add(contribution);
- librariesByCategory.put(contribution.getCategory(), list);
+ for (String category : contribution.getCategories()) {
+ if (librariesByCategory.containsKey(category)) {
+ List list = librariesByCategory.get(category);
+ list.add(contribution);
+ Collections.sort(list, nameComparator);
+
+ } else {
+ ArrayList list = new ArrayList();
+ list.add(contribution);
+ librariesByCategory.put(category, list);
+ }
+ allContributions.add(contribution);
+ notifyAdd(contribution);
+ Collections.sort(allContributions, nameComparator);
}
- allContributions.add(contribution);
- notifyAdd(contribution);
- Collections.sort(allContributions, nameComparator);
}
- protected void removeContribution(Contribution info) {
- if (librariesByCategory.containsKey(info.getCategory())) {
- librariesByCategory.get(info.getCategory()).remove(info);
+ protected void removeContribution(Contribution contribution) {
+ for (String category : contribution.getCategories()) {
+ if (librariesByCategory.containsKey(category)) {
+ librariesByCategory.get(category).remove(contribution);
+ }
}
- allContributions.remove(info);
- notifyRemove(info);
+ allContributions.remove(contribution);
+ notifyRemove(contribution);
}
private Contribution getContribution(Contribution contribution) {
for (Contribution c : allContributions) {
- if (c.getName().equals(contribution.getName()) &&
+ if (c.getName().equals(contribution.getName()) &&
c.getType() == contribution.getType()) {
return c;
}
@@ -166,7 +166,7 @@ public class ContributionListing {
protected AvailableContribution getAvailableContribution(Contribution info) {
for (AvailableContribution advertised : advertisedContributions) {
- if (advertised.getType() == info.getType() &&
+ if (advertised.getType() == info.getType() &&
advertised.getName().equals(info.getName())) {
return advertised;
}
@@ -174,7 +174,7 @@ public class ContributionListing {
return null;
}
-
+
protected Set getCategories(ContributionFilter filter) {
Set outgoing = new HashSet();
@@ -194,12 +194,12 @@ public class ContributionListing {
return outgoing;
}
-
+
// public List getAllContributions() {
// return new ArrayList(allContributions);
// }
-
+
// public List getLibararies(String category) {
// ArrayList libinfos =
// new ArrayList(librariesByCategory.get(category));
@@ -207,14 +207,16 @@ public class ContributionListing {
// return libinfos;
// }
-
+
protected List getFilteredLibraryList(String category, List filters) {
- ArrayList filteredList = new ArrayList(allContributions);
+ ArrayList filteredList =
+ new ArrayList(allContributions);
Iterator it = filteredList.iterator();
while (it.hasNext()) {
Contribution libInfo = it.next();
- if (category != null && !category.equals(libInfo.getCategory())) {
+ //if (category != null && !category.equals(libInfo.getCategory())) {
+ if (category != null && !libInfo.hasCategory(category)) {
it.remove();
} else {
for (String filter : filters) {
@@ -254,7 +256,7 @@ public class ContributionListing {
return contrib.getAuthorList() != null && contrib.getAuthorList().toLowerCase().matches(filter)
|| contrib.getSentence() != null && contrib.getSentence().toLowerCase().matches(filter)
|| contrib.getParagraph() != null && contrib.getParagraph().toLowerCase().matches(filter)
- || contrib.getCategory() != null && contrib.getCategory().toLowerCase().matches(filter)
+ || contrib.hasCategory(filter)
|| contrib.getName() != null && contrib.getName().toLowerCase().matches(filter);
}
@@ -267,9 +269,9 @@ public class ContributionListing {
}
- /**
+ /**
* Returns true if the contribution fits the given property, false otherwise.
- * If the property is invalid, returns false.
+ * If the property is invalid, returns false.
*/
private boolean hasProperty(Contribution contrib, String property) {
// update, updates, updatable, upgrade
@@ -318,7 +320,7 @@ public class ContributionListing {
}
}
-
+
protected void addContributionListener(ContributionChangeListener listener) {
for (Contribution contrib : allContributions) {
listener.contributionAdded(contrib);
@@ -326,21 +328,21 @@ public class ContributionListing {
listeners.add(listener);
}
-
+
/*
private void removeContributionListener(ContributionChangeListener listener) {
listeners.remove(listener);
}
-
+
private ArrayList getContributionListeners() {
return new ArrayList(listeners);
}
*/
-
+
/**
- * Starts a new thread to download the advertised list of contributions.
+ * Starts a new thread to download the advertised list of contributions.
* Only one instance will run at a time.
*/
protected void downloadAvailableList(final ProgressMonitor progress) {
@@ -367,8 +369,8 @@ public class ContributionListing {
}
}).start();
}
-
-
+
+
boolean hasUpdates() {
for (Contribution info : allContributions) {
if (hasUpdates(info)) {
@@ -390,45 +392,45 @@ public class ContributionListing {
return false;
}
-
+
boolean hasDownloadedLatestList() {
return hasDownloadedLatestList;
}
-
- /**
- * @return a lowercase string with all non-alphabetic characters removed
- */
- static protected String normalize(String s) {
- return s.toLowerCase().replaceAll("^\\p{Lower}", "");
- }
+
+// /**
+// * @return a lowercase string with all non-alphabetic characters removed
+// */
+// static protected String normalize(String s) {
+// return s.toLowerCase().replaceAll("^\\p{Lower}", "");
+// }
- /**
- * @return the proper, valid name of this category to be displayed in the UI
- * (e.g. "Typography / Geometry"). "Unknown" if the category null.
- */
- static public String getCategory(String category) {
- if (category == null) {
- return "Unknown";
- }
- String normCatName = normalize(category);
+// /**
+// * @return the proper, valid name of this category to be displayed in the UI
+// * (e.g. "Typography / Geometry"). "Unknown" if the category null.
+// */
+// static public String getCategory(String category) {
+// if (category == null) {
+// return "Unknown";
+// }
+// String normCatName = normalize(category);
+//
+// for (String validCatName : validCategories) {
+// String normValidCatName = normalize(validCatName);
+// if (normValidCatName.equals(normCatName)) {
+// return validCatName;
+// }
+// }
+// return category;
+// }
- for (String validCatName : validCategories) {
- String normValidCatName = normalize(validCatName);
- if (normValidCatName.equals(normCatName)) {
- return validCatName;
- }
- }
- return category;
- }
-
ArrayList parseContribList(File file) {
ArrayList outgoing = new ArrayList();
if (file != null && file.exists()) {
- String lines[] = PApplet.loadStrings(file);
+ String[] lines = PApplet.loadStrings(file);
int start = 0;
while (start < lines.length) {
@@ -454,7 +456,7 @@ public class ContributionListing {
HashMap contribParams = new HashMap();
Base.readSettings(file.getName(), contribLines, contribParams);
-
+
outgoing.add(new AvailableContribution(contribType, contribParams));
start = end + 1;
// } else {
@@ -465,17 +467,17 @@ public class ContributionListing {
return outgoing;
}
-
+
// boolean isDownloadingListing() {
// return downloadingListingLock.isLocked();
// }
-
+
public Comparator super Contribution> getComparator() {
return nameComparator;
}
-
+
static Comparator nameComparator = new Comparator() {
public int compare(Contribution o1, Contribution o2) {
return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
diff --git a/app/src/processing/app/contrib/ContributionManager.java b/app/src/processing/app/contrib/ContributionManager.java
index 7659a1dfc..262b09573 100644
--- a/app/src/processing/app/contrib/ContributionManager.java
+++ b/app/src/processing/app/contrib/ContributionManager.java
@@ -22,9 +22,7 @@
package processing.app.contrib;
import java.io.*;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.net.URLConnection;
+import java.net.*;
import processing.app.Base;
import processing.app.Editor;
@@ -55,9 +53,13 @@ public class ContributionManager {
boolean success = false;
try {
// System.out.println("downloading file " + source);
- URLConnection conn = source.openConnection();
- conn.setConnectTimeout(2000);
- conn.setReadTimeout(5000);
+// URLConnection conn = source.openConnection();
+ HttpURLConnection conn = (HttpURLConnection) source.openConnection();
+ HttpURLConnection.setFollowRedirects(true);
+ conn.setConnectTimeout(15 * 1000);
+ conn.setReadTimeout(60 * 1000);
+ conn.setRequestMethod("GET");
+ conn.connect();
// TODO this is often -1, may need to set progress to indeterminate
int fileSize = conn.getContentLength();
@@ -147,6 +149,7 @@ public class ContributionManager {
static public void refreshInstalled(Editor editor) {
editor.getMode().rebuildImportMenu();
+ editor.getMode().resetExamples();
editor.rebuildToolMenu();
}
@@ -202,15 +205,21 @@ public class ContributionManager {
}
- /** Called by Base to clean up entries previously marked for deletion. */
- static public void deleteFlagged() {
+ /**
+ * Called by Base to clean up entries previously marked for deletion
+ * and remove any "requires restart" flags.
+ */
+ static public void cleanup() throws Exception {
deleteFlagged(Base.getSketchbookLibrariesFolder());
deleteFlagged(Base.getSketchbookModesFolder());
deleteFlagged(Base.getSketchbookToolsFolder());
+
+ clearRestartFlags(Base.getSketchbookModesFolder());
+ clearRestartFlags(Base.getSketchbookToolsFolder());
}
- static private void deleteFlagged(File root) {
+ static private void deleteFlagged(File root) throws Exception {
File[] markedForDeletion = root.listFiles(new FileFilter() {
public boolean accept(File folder) {
return (folder.isDirectory() &&
@@ -221,4 +230,16 @@ public class ContributionManager {
Base.removeDir(folder);
}
}
+
+
+ static private void clearRestartFlags(File root) throws Exception {
+ File[] folderList = root.listFiles(new FileFilter() {
+ public boolean accept(File folder) {
+ return folder.isDirectory();
+ }
+ });
+ for (File folder : folderList) {
+ LocalContribution.clearRestartFlags(folder);
+ }
+ }
}
diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java
index 19e5eb3b4..6cbe3b888 100644
--- a/app/src/processing/app/contrib/ContributionManagerDialog.java
+++ b/app/src/processing/app/contrib/ContributionManagerDialog.java
@@ -27,6 +27,7 @@ import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.*;
+import java.net.SocketTimeoutException;
import java.util.*;
import javax.swing.*;
@@ -85,13 +86,8 @@ public class ContributionManagerDialog {
dialog.pack();
dialog.setLocationRelativeTo(null);
-// Dimension screen = Toolkit.getScreenSize();
-// dialog.setLocation((screen.width - dialog.getWidth()) / 2,
-// (screen.height - dialog.getHeight()) / 2);
-
contributionListPanel.grabFocus();
}
-
dialog.setVisible(true);
if (contribListing.hasDownloadedLatestList()) {
@@ -99,19 +95,21 @@ public class ContributionManagerDialog {
} else {
contribListing.downloadAvailableList(new ProgressMonitor() {
-// public void startTask(String name, int maxValue) {
-// }
-//
+
public void finished() {
super.finished();
-
+
updateContributionListing();
updateCategoryChooser();
- if (isError()) {
- status.setErrorMessage("An error occured when downloading " +
- "the list of available contributions.");
-// } else {
-// status.updateUI();
+ if (error) {
+ if (exception instanceof SocketTimeoutException) {
+ status.setErrorMessage("Connection timed out while " +
+ "downloading the contribution list.");
+ } else {
+ status.setErrorMessage("Could not download the list" +
+ "of available contributions.");
+ }
+ exception.printStackTrace();
}
}
});
@@ -274,11 +272,15 @@ public class ContributionManagerDialog {
// }
Collections.sort(categories);
// categories.add(0, ContributionManagerDialog.ANY_CATEGORY);
+ boolean categoriesFound = false;
categoryChooser.addItem(ContributionManagerDialog.ANY_CATEGORY);
for (String s : categories) {
categoryChooser.addItem(s);
+ if (!s.equals("Unknown")) {
+ categoriesFound = true;
+ }
}
- categoryChooser.setEnabled(categories.size() != 0);
+ categoryChooser.setEnabled(categoriesFound);
}
}
@@ -318,7 +320,18 @@ public class ContributionManagerDialog {
protected void updateContributionListing() {
if (editor != null) {
- ArrayList libraries = new ArrayList(editor.getMode().contribLibraries);
+ ArrayList contributions = new ArrayList();
+
+ ArrayList libraries =
+ new ArrayList(editor.getMode().contribLibraries);
+ contributions.addAll(libraries);
+
+ ArrayList tools = editor.contribTools;
+ contributions.addAll(tools);
+
+ ArrayList modes = editor.getBase().getModeContribs();
+ contributions.addAll(modes);
+
// ArrayList compilations = LibraryCompilation.list(libraries);
//
// // Remove libraries from the list that are part of a compilations
@@ -332,11 +345,6 @@ public class ContributionManagerDialog {
// }
// }
- ArrayList contributions = new ArrayList();
- contributions.addAll(editor.contribTools);
- contributions.addAll(libraries);
-// contributions.addAll(compilations);
-
contribListing.updateInstalledList(contributions);
}
}
diff --git a/app/src/processing/app/contrib/ContributionPanel.java b/app/src/processing/app/contrib/ContributionPanel.java
index 9f0ff9a60..09ba24faf 100644
--- a/app/src/processing/app/contrib/ContributionPanel.java
+++ b/app/src/processing/app/contrib/ContributionPanel.java
@@ -44,6 +44,12 @@ import processing.app.Base;
* Panel that expands and gives a brief overview of a library when clicked.
*/
class ContributionPanel extends JPanel {
+ static public final String REMOVE_RESTART_MESSAGE =
+ "Please restart Processing to finish removing this item.";
+
+ static public final String INSTALL_RESTART_MESSAGE =
+ "Please restart Processing to finish installing this item.";
+
private final ContributionListPanel listPanel;
private final ContributionListing contribListing = ContributionListing.getInstance();
@@ -95,6 +101,7 @@ class ContributionPanel extends JPanel {
public void actionPerformed(ActionEvent e) {
if (contrib instanceof AvailableContribution) {
installContribution((AvailableContribution) contrib);
+ contribListing.replaceContribution(contrib, contrib);
}
}
};
@@ -103,7 +110,7 @@ class ContributionPanel extends JPanel {
public void actionPerformed(ActionEvent e) {
if (contrib instanceof LocalContribution) {
LocalContribution installed = (LocalContribution) contrib;
- installed.unsetDeletionFlag();
+ installed.setDeletionFlag(false);
contribListing.replaceContribution(contrib, contrib); // ??
}
}
@@ -336,9 +343,11 @@ class ContributionPanel extends JPanel {
}
description.append(" ");
- boolean isFlagged = contrib.isDeletionFlagged();
- if (isFlagged) {
- description.append(ContributionListPanel.DELETION_MESSAGE);
+ //System.out.println("checking restart flag for " + contrib + " " + contrib.getName() + " and it's " + contrib.isRestartFlagged());
+ if (contrib.isDeletionFlagged()) {
+ description.append(REMOVE_RESTART_MESSAGE);
+ } else if (contrib.isRestartFlagged()) {
+ description.append(INSTALL_RESTART_MESSAGE);
} else {
String sentence = contrib.getSentence();
if (sentence == null || sentence.isEmpty()) {
@@ -357,11 +366,14 @@ class ContributionPanel extends JPanel {
if (contribListing.hasUpdates(contrib)) {
StringBuilder versionText = new StringBuilder();
versionText.append("");
- if (isFlagged) {
- versionText.append("To finish an update, reinstall this contribution after the restart.");
+ if (contrib.isDeletionFlagged()) {
+ // Already marked for deletion, see requiresRestart() notes below.
+ versionText.append("To finish an update, reinstall this contribution after restarting.");
} else {
versionText.append("New version available!");
- if (contrib.requiresRestart()) {
+ if (contrib.getType().requiresRestart()) {
+ // If a contribution can't be reinstalled in-place, the user may need
+ // to remove the current version, restart Processing, then install.
versionText.append(" To update, first remove the current version.");
}
}
@@ -374,7 +386,7 @@ class ContributionPanel extends JPanel {
}
updateButton.setEnabled(true);
- if (contrib != null && !contrib.requiresRestart()) {
+ if (contrib != null && !contrib.getType().requiresRestart()) {
updateButton.setVisible(isSelected() && contribListing.hasUpdates(contrib));
}
@@ -382,7 +394,7 @@ class ContributionPanel extends JPanel {
installRemoveButton.removeActionListener(removeActionListener);
installRemoveButton.removeActionListener(undoActionListener);
- if (isFlagged) {
+ if (contrib.isDeletionFlagged()) {
installRemoveButton.addActionListener(undoActionListener);
installRemoveButton.setText("Undo");
} else if (contrib.isInstalled()) {
@@ -449,7 +461,8 @@ class ContributionPanel extends JPanel {
} catch (MalformedURLException e) {
Base.showWarning(ContributionListPanel.INSTALL_FAILURE_TITLE,
ContributionListPanel.MALFORMED_URL_MESSAGE, e);
- installRemoveButton.setEnabled(true);
+ // not sure why we'd re-enable the button if it had an error...
+// installRemoveButton.setEnabled(true);
}
}
@@ -487,7 +500,7 @@ class ContributionPanel extends JPanel {
// now a hyperlink, it will be opened as the mouse is released.
enableHyperlinks = alreadySelected;
- if (contrib != null && !contrib.requiresRestart()) {
+ if (contrib != null && !contrib.getType().requiresRestart()) {
updateButton.setVisible(isSelected() && contribListing.hasUpdates(contrib));
}
installRemoveButton.setVisible(isSelected() || installRemoveButton.getText().equals("Remove"));
diff --git a/app/src/processing/app/contrib/ContributionType.java b/app/src/processing/app/contrib/ContributionType.java
index 4c3b69fee..8b882ee59 100644
--- a/app/src/processing/app/contrib/ContributionType.java
+++ b/app/src/processing/app/contrib/ContributionType.java
@@ -23,6 +23,7 @@ package processing.app.contrib;
import java.io.File;
import java.io.FileFilter;
+import java.io.IOException;
import java.util.ArrayList;
import processing.app.Base;
@@ -30,7 +31,6 @@ import processing.app.Editor;
import processing.app.Library;
public enum ContributionType {
-// LIBRARY, LIBRARY_COMPILATION, TOOL, MODE;
LIBRARY, TOOL, MODE;
@@ -38,8 +38,6 @@ public enum ContributionType {
switch (this) {
case LIBRARY:
return "library";
-// case LIBRARY_COMPILATION:
-// return "compilation";
case TOOL:
return "tool";
case MODE:
@@ -49,7 +47,10 @@ public enum ContributionType {
};
- /** Return Mode for mode, Tool for tool, etc. */
+ /**
+ * Get this type name as a purtied up, capitalized version.
+ * @return Mode for mode, Tool for tool, etc.
+ */
public String getTitle() {
String s = toString();
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
@@ -60,8 +61,6 @@ public enum ContributionType {
switch (this) {
case LIBRARY:
return "libraries";
-// case LIBRARY_COMPILATION:
-// return "libraries";
case TOOL:
return "tools";
case MODE:
@@ -69,6 +68,26 @@ public enum ContributionType {
}
return null; // should be unreachable
}
+
+
+ public File createTempFolder() throws IOException {
+ return Base.createTempFolder(toString(), "tmp", getSketchbookFolder());
+ }
+
+
+ public boolean isTempFolderName(String name) {
+ return name.startsWith(toString()) && name.endsWith("tmp");
+ }
+
+
+// public String getTempPrefix() {
+// return toString();
+// }
+//
+//
+// public String getTempSuffix() {
+// return "tmp";
+// }
// public String getPropertiesName() {
@@ -78,16 +97,13 @@ public enum ContributionType {
static public ContributionType fromName(String s) {
if (s != null) {
- if ("library".equals(s.toLowerCase())) {
+ if ("library".equalsIgnoreCase(s)) {
return LIBRARY;
}
-// if ("compilation".equals(s.toLowerCase())) {
-// return LIBRARY_COMPILATION;
-// }
- if ("tool".equals(s.toLowerCase())) {
+ if ("tool".equalsIgnoreCase(s)) {
return TOOL;
}
- if ("mode".equals(s.toLowerCase())) {
+ if ("mode".equalsIgnoreCase(s)) {
return MODE;
}
}
@@ -109,7 +125,9 @@ public enum ContributionType {
boolean isCandidate(File potential) {
- return (potential.isDirectory() && new File(potential, toString()).exists());
+ return (potential.isDirectory() &&
+ new File(potential, toString()).exists() &&
+ !isTempFolderName(potential.getName()));
}
@@ -145,10 +163,20 @@ public enum ContributionType {
}
+ /**
+ * Returns true if the type of contribution requires the PDE to restart
+ * when being added or removed.
+ */
+ boolean requiresRestart() {
+ return this == ContributionType.TOOL || this == ContributionType.MODE;
+ }
+
+
LocalContribution load(Base base, File folder) {
switch (this) {
case LIBRARY:
- return new Library(folder);
+ //return new Library(folder);
+ return Library.load(folder);
case TOOL:
return ToolContribution.load(folder);
case MODE:
@@ -174,15 +202,20 @@ public enum ContributionType {
return contribs;
}
+
+ File getBackupFolder() {
+ return new File(getSketchbookFolder(), "old");
+ }
+
File createBackupFolder(StatusPanel status) {
- File backupFolder = new File(getSketchbookFolder(), "old");
- if (backupFolder.isDirectory()) {
- status.setErrorMessage("First remove the folder named \"old\" from the " +
- getFolderName() + " folder in the sketchbook.");
- return null;
- }
- if (!backupFolder.mkdirs()) {
+ File backupFolder = getBackupFolder();
+// if (backupFolder.isDirectory()) {
+// status.setErrorMessage("First remove the folder named \"old\" from the " +
+// getFolderName() + " folder in the sketchbook.");
+// return null;
+// }
+ if (!backupFolder.exists() && !backupFolder.mkdirs()) {
status.setErrorMessage("Could not create a backup folder in the " +
"sketchbook " + toString() + " folder.");
return null;
diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java
index 621448000..03a6e0f31 100644
--- a/app/src/processing/app/contrib/LocalContribution.java
+++ b/app/src/processing/app/contrib/LocalContribution.java
@@ -38,14 +38,15 @@ import processing.app.*;
* be installed.
*/
public abstract class LocalContribution extends Contribution {
- static public final String DELETION_FLAG = "flagged_for_deletion";
+ static public final String DELETION_FLAG = "marked_for_deletion";
+ static public final String RESTART_FLAG = "requires_restart";
protected String id; // 1 (unique id for this library)
protected int latestVersion; // 103
protected File folder;
protected HashMap properties;
protected ClassLoader loader;
-
+
public LocalContribution(File folder) {
this.folder = folder;
@@ -57,7 +58,7 @@ public abstract class LocalContribution extends Contribution {
name = properties.get("name");
id = properties.get("id");
- category = ContributionListing.getCategory(properties.get("category"));
+ categories = parseCategories(properties.get("category"));
if (name == null) {
name = folder.getName();
}
@@ -71,7 +72,6 @@ public abstract class LocalContribution extends Contribution {
} catch (NumberFormatException e) {
System.err.println("The version number for the “" + name + "” library is not set properly.");
System.err.println("Please contact the library author to fix it according to the guidelines.");
- //e.printStackTrace();
}
prettyVersion = properties.get("prettyVersion");
@@ -79,6 +79,7 @@ public abstract class LocalContribution extends Contribution {
Base.log("No properties file at " + propertiesFile.getAbsolutePath());
// We'll need this to be set at a minimum.
name = folder.getName();
+ categories = defaultCategory();
}
}
@@ -184,9 +185,9 @@ public abstract class LocalContribution extends Contribution {
// }
- LocalContribution moveAndLoad(Editor editor,
- boolean confirmReplace,
- StatusPanel status) {
+ LocalContribution copyAndLoad(Editor editor,
+ boolean confirmReplace,
+ StatusPanel status) {
ArrayList oldContribs =
getType().listContributions(editor);
@@ -199,7 +200,7 @@ public abstract class LocalContribution extends Contribution {
if ((oldContrib.getFolder().exists() && oldContrib.getFolder().equals(contribFolder)) ||
(oldContrib.getId() != null && oldContrib.getId().equals(getId()))) {
- if (oldContrib.requiresRestart()) {
+ if (oldContrib.getType().requiresRestart()) {
// XXX: We can't replace stuff, soooooo.... do something different
if (!oldContrib.backup(editor, false, status)) {
return null;
@@ -214,7 +215,7 @@ public abstract class LocalContribution extends Contribution {
"A pre-existing copy of the \"" + oldContrib.getName() + "\" library "+
"has been found in your sketchbook. Clicking “Yes” "+
"will move the existing library to a backup folder " +
- " in libraries/old before replacing it.");
+ "in libraries/old before replacing it.");
if (result != JOptionPane.YES_OPTION || !oldContrib.backup(editor, true, status)) {
return null;
}
@@ -243,12 +244,28 @@ public abstract class LocalContribution extends Contribution {
if (contribFolder.exists()) {
Base.removeDir(contribFolder);
}
+
+ File oldFolder = getFolder();
+
+ try {
+ Base.copyDir(oldFolder, contribFolder);
+ } catch (IOException e) {
+ status.setErrorMessage("Could not copy " + getTypeName() +
+ " \"" + getName() + "\" to the sketchbook.");
+ e.printStackTrace();
+ return null;
+ }
+
+
+ /*
if (!getFolder().renameTo(contribFolder)) {
status.setErrorMessage("Could not move " + getTypeName() +
" \"" + getName() + "\" to the sketchbook.");
return null;
}
+ */
+
return getType().load(editor.getBase(), contribFolder);
}
@@ -260,15 +277,15 @@ public abstract class LocalContribution extends Contribution {
* should instead be copied, leaving the original in place
*/
boolean backup(Editor editor, boolean deleteOriginal, StatusPanel status) {
-
- boolean success = false;
File backupFolder = getType().createBackupFolder(status);
+ boolean success = false;
if (backupFolder != null) {
String libFolderName = getFolder().getName();
String prefix = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
- final String backupName = prefix + "_" + libFolderName;
- File backupSubFolder = ContributionManager.getUniqueName(backupFolder, backupName);
+ final String backupName = prefix + " " + libFolderName;
+ File backupSubFolder =
+ ContributionManager.getUniqueName(backupFolder, backupName);
if (deleteOriginal) {
success = getFolder().renameTo(backupSubFolder);
@@ -310,9 +327,9 @@ public abstract class LocalContribution extends Contribution {
pm.startTask("Removing", ProgressMonitor.UNKNOWN);
boolean doBackup = Preferences.getBoolean("contribution.backup.on_remove");
- if (requiresRestart()) {
+ if (getType().requiresRestart()) {
if (!doBackup || (doBackup && backup(editor, false, status))) {
- if (setDeletionFlag()) {
+ if (setDeletionFlag(true)) {
contribListing.replaceContribution(this, this);
}
}
@@ -355,33 +372,6 @@ public abstract class LocalContribution extends Contribution {
return folder != null;
}
-
- boolean setDeletionFlag() {
- // Only returns false if the file already exists, so we can
- // ignore the return value.
- try {
- new File(getFolder(), DELETION_FLAG).createNewFile();
- return true;
- } catch (IOException e) {
- return false;
- }
- }
-
-
- boolean unsetDeletionFlag() {
- return new File(getFolder(), DELETION_FLAG).delete();
- }
-
-
- boolean isDeletionFlagged() {
- return isDeletionFlagged(getFolder());
- }
-
-
- static boolean isDeletionFlagged(File folder) {
- return new File(folder, DELETION_FLAG).exists();
- }
-
// public String getCategory() {
// return category;
@@ -449,8 +439,77 @@ public abstract class LocalContribution extends Contribution {
return null;
}
*/
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ boolean setDeletionFlag(boolean flag) {
+ return setFlag(DELETION_FLAG, flag);
+ }
+
+
+ boolean isDeletionFlagged() {
+ return isDeletionFlagged(getFolder());
+ }
+ static boolean isDeletionFlagged(File folder) {
+ return isFlagged(folder, DELETION_FLAG);
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ boolean setRestartFlag() {
+ //System.out.println("setting restart flag for " + folder);
+ return setFlag(RESTART_FLAG, true);
+ }
+
+
+ @Override
+ boolean isRestartFlagged() {
+ //System.out.println("checking for restart inside LocalContribution for " + getName());
+ return isFlagged(getFolder(), RESTART_FLAG);
+ }
+
+
+ static void clearRestartFlags(File folder) {
+ File restartFlag = new File(folder, RESTART_FLAG);
+ if (restartFlag.exists()) {
+ restartFlag.delete();
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ private boolean setFlag(String flagFilename, boolean flag) {
+ if (flag) {
+ // Only returns false if the file already exists, so we can
+ // ignore the return value.
+ try {
+ new File(getFolder(), flagFilename).createNewFile();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ } else {
+ return new File(getFolder(), flagFilename).delete();
+ }
+ }
+
+
+ static private boolean isFlagged(File folder, String flagFilename) {
+ return new File(folder, flagFilename).exists();
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
/**
*
* @param base name of the class, with or without the package
@@ -489,7 +548,7 @@ public abstract class LocalContribution extends Contribution {
}
- class IgnorableException extends Exception {
+ static protected class IgnorableException extends Exception {
public IgnorableException(String msg) {
super(msg);
}
diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java
index 44290d006..9fdac9f0d 100644
--- a/app/src/processing/app/contrib/ModeContribution.java
+++ b/app/src/processing/app/contrib/ModeContribution.java
@@ -15,7 +15,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
+ You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -39,20 +39,23 @@ public class ModeContribution extends LocalContribution {
}
- static public ModeContribution load(Base base, File folder,
+ static public ModeContribution load(Base base, File folder,
String searchName) {
try {
return new ModeContribution(base, folder, searchName);
+
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
- } catch (Exception e) {
+
+ } catch (Throwable err) {
+ // Throwable to catch Exceptions or UnsupportedClassVersionError et al
if (searchName == null) {
- e.printStackTrace();
+ err.printStackTrace();
} else {
- // For the built-in modes, don't print the exception, just log it
- // for debugging. This should be impossible for most users to reach,
+ // For the built-in modes, don't print the exception, just log it
+ // for debugging. This should be impossible for most users to reach,
// but it helps us load experimental mode when it's available.
- Base.log("ModeContribution.load() failed for " + searchName, e);
+ Base.log("ModeContribution.load() failed for " + searchName, err);
}
}
return null;
@@ -92,15 +95,19 @@ public class ModeContribution extends LocalContribution {
existing.put(contrib.getFolder(), contrib);
}
File[] potential = ContributionType.MODE.listCandidates(modesFolder);
- for (File folder : potential) {
- if (!existing.containsKey(folder)) {
+ // If modesFolder does not exist or is inaccessible (folks might like to
+ // mess with folders then report it as a bug) 'potential' will be null.
+ if (potential != null) {
+ for (File folder : potential) {
+ if (!existing.containsKey(folder)) {
try {
contribModes.add(new ModeContribution(base, folder, null));
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
- } catch (Exception e) {
+ } catch (Throwable e) {
e.printStackTrace();
}
+ }
}
}
}
diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java
index 94715497e..bccbda1bb 100644
--- a/app/src/processing/app/contrib/ToolContribution.java
+++ b/app/src/processing/app/contrib/ToolContribution.java
@@ -15,7 +15,7 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
+ You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -40,8 +40,11 @@ public class ToolContribution extends LocalContribution implements Tool {
return new ToolContribution(folder);
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
- } catch (Exception e) {
- e.printStackTrace();
+ } catch (Error err) {
+ // Handles UnsupportedClassVersionError and others
+ err.printStackTrace();
+ } catch (Exception ex) {
+ ex.printStackTrace();
}
return null;
}
@@ -71,27 +74,44 @@ public class ToolContribution extends LocalContribution implements Tool {
static public ArrayList loadAll(File toolsFolder) {
File[] list = ContributionType.TOOL.listCandidates(toolsFolder);
ArrayList outgoing = new ArrayList();
- for (File folder : list) {
- try {
- ToolContribution tc = load(folder);
- if (tc != null) {
- outgoing.add(tc);
+ // If toolsFolder does not exist or is inaccessible (stranger things have
+ // happened, and are reported as bugs) list will come back null.
+ if (list != null) {
+ for (File folder : list) {
+ try {
+ ToolContribution tc = load(folder);
+ if (tc != null) {
+ outgoing.add(tc);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
}
- } catch (Exception e) {
- e.printStackTrace();
}
}
return outgoing;
}
+// Editor editor; // used to send error messages
+
public void init(Editor editor) {
+// try {
+// this.editor = editor;
tool.init(editor);
+// } catch (NoSuchMethodError nsme) {
+// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing");
+// nsme.printStackTrace();
+// }
}
public void run() {
+// try {
tool.run();
+// } catch (NoSuchMethodError nsme) {
+// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing");
+// nsme.printStackTrace();
+// }
}
diff --git a/app/src/processing/app/linux/Platform.java b/app/src/processing/app/platform/LinuxPlatform.java
similarity index 89%
rename from app/src/processing/app/linux/Platform.java
rename to app/src/processing/app/platform/LinuxPlatform.java
index 2a5415b82..8e9ee7c71 100644
--- a/app/src/processing/app/linux/Platform.java
+++ b/app/src/processing/app/platform/LinuxPlatform.java
@@ -3,12 +3,12 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2008 Ben Fry and Casey Reas
+ Copyright (c) 2012-2013 The Processing Foundation
+ Copyright (c) 2008-2012 Ben Fry and Casey Reas
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,15 +20,16 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-package processing.app.linux;
+package processing.app.platform;
import java.io.File;
import processing.app.Base;
+import processing.app.Platform;
import processing.app.Preferences;
-public class Platform extends processing.app.Platform {
+public class LinuxPlatform extends Platform {
public void init(Base base) {
super.init(base);
diff --git a/app/src/processing/app/macosx/Platform.java b/app/src/processing/app/platform/MacPlatform.java
similarity index 91%
rename from app/src/processing/app/macosx/Platform.java
rename to app/src/processing/app/platform/MacPlatform.java
index 406e65987..0407fdc6f 100644
--- a/app/src/processing/app/macosx/Platform.java
+++ b/app/src/processing/app/platform/MacPlatform.java
@@ -3,12 +3,12 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2008 Ben Fry and Casey Reas
+ Copyright (c) 2012-2013 The Processing Foundation
+ Copyright (c) 2008-2012 Ben Fry and Casey Reas
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,7 +20,7 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-package processing.app.macosx;
+package processing.app.platform;
import java.io.File;
import java.io.FileNotFoundException;
@@ -28,12 +28,13 @@ import java.io.FileNotFoundException;
import com.apple.eio.FileManager;
import processing.app.Base;
+import processing.app.Platform;
/**
* Platform handler for Mac OS X.
*/
-public class Platform extends processing.app.Platform {
+public class MacPlatform extends Platform {
// Removing for 2.0b8 because Quaqua doesn't have OS X 10.8 version.
/*
@@ -79,8 +80,8 @@ public class Platform extends processing.app.Platform {
}
*/
}
-
-
+
+
public File getSettingsFolder() throws Exception {
return new File(getLibraryFolder(), "Processing");
}
@@ -101,6 +102,15 @@ public class Platform extends processing.app.Platform {
}
*/
}
+
+
+// /**
+// * Moves the specified File object (which might be a file or folder)
+// * to the trash.
+// */
+// public boolean deleteFile(File file) throws IOException {
+// return FileManager.moveToTrash(file);
+// }
/*
diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java
similarity index 75%
rename from app/src/processing/app/macosx/ThinkDifferent.java
rename to app/src/processing/app/platform/ThinkDifferent.java
index 9a328d500..aba1ed4ba 100644
--- a/app/src/processing/app/macosx/ThinkDifferent.java
+++ b/app/src/processing/app/platform/ThinkDifferent.java
@@ -3,11 +3,12 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2007-2010 Ben Fry and Casey Reas
+ Copyright (c) 2012-2013 The Processing Foundation
+ Copyright (c) 2007-2012 Ben Fry and Casey Reas
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, version 2.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,15 +20,12 @@
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-package processing.app.macosx;
+package processing.app.platform;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
+import java.awt.Dimension;
+import java.awt.event.*;
+
+import javax.swing.*;
import processing.app.About;
import processing.app.Base;
@@ -76,35 +74,39 @@ public class ThinkDifferent implements ApplicationListener {
application.setEnabledPreferencesMenu(true);
// Set the menubar to be used when nothing else is open. http://j.mp/dkZmka
- // http://developer.apple.com/mac/library/documentation/Java/Reference/
- // JavaSE6_AppleExtensionsRef/api/com/apple/eawt/Application.html
- // Only available since Java for Mac OS X 10.6 Update 1, and
- // Java for Mac OS X 10.5 Update 6, so need to load this dynamically
+ // Only available since Java for Mac OS X 10.6 Update 1, but removed
+ // dynamic loading code because that should be installed in 10.6.8, and
+ // we may be dropped 10.6 really soon anyway
+
+ JMenuBar defaultMenuBar = new JMenuBar();
+ JMenu fileMenu = buildFileMenu(base);
+ defaultMenuBar.add(fileMenu);
+ // This is kind of a gross way to do this, but the alternatives? Hrm.
+ Base.defaultFileMenu = fileMenu;
+
if (PApplet.javaVersion <= 1.6f) { // doesn't work on Oracle's Java
try {
- // com.apple.eawt.Application.setDefaultMenuBar(JMenuBar)
- Class> appClass = Application.class;
- Method method =
- appClass.getMethod("setDefaultMenuBar", new Class[] { JMenuBar.class });
- if (method != null) {
- JMenuBar defaultMenuBar = new JMenuBar();
- JMenu fileMenu = buildFileMenu(base);
- defaultMenuBar.add(fileMenu);
- method.invoke(application, new Object[] { defaultMenuBar });
- // This is kind of a gross way to do this, but the alternatives? Hrm.
- Base.defaultFileMenu = fileMenu;
- }
- } catch (InvocationTargetException ite) {
- ite.getTargetException().printStackTrace();
+ application.setDefaultMenuBar(defaultMenuBar);
+
} catch (Exception e) {
e.printStackTrace(); // oh well nevermind
}
} else {
- // http://java.net/jira/browse/MACOSX_PORT-775?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel
- System.out.println("Skipping default menu bar due to apparent Oracle Java bug.");
+ // The douchebags at Oracle didn't feel that a working f*king menubar
+ // on OS X was important enough to make it into the 7u40 release.
+ //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267
+ // It languished in the JDK 8 source and has been backported for 7u60:
+ //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667
+
+ JFrame offscreen = new JFrame();
+ offscreen.setUndecorated(true);
+ offscreen.setJMenuBar(defaultMenuBar);
+ Dimension screen = Toolkit.getScreenSize();
+ offscreen.setLocation(screen.width, screen.height);
+ offscreen.setVisible(true);
}
}
-
+
public ThinkDifferent(Base base) {
this.base = base;
diff --git a/app/src/processing/app/platform/WindowsPlatform.java b/app/src/processing/app/platform/WindowsPlatform.java
new file mode 100644
index 000000000..0c14b5ead
--- /dev/null
+++ b/app/src/processing/app/platform/WindowsPlatform.java
@@ -0,0 +1,584 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2012-2013 The Processing Foundation
+ Copyright (c) 2008-2012 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2, as published by the Free Software Foundation.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.platform;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.platform.win32.Kernel32Util;
+import com.sun.jna.platform.win32.Shell32;
+import com.sun.jna.platform.win32.ShlObj;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinError;
+import com.sun.jna.platform.win32.WinNT.HRESULT;
+
+import processing.app.Base;
+import processing.app.Platform;
+import processing.app.Preferences;
+import processing.app.platform.WindowsRegistry.REGISTRY_ROOT_KEY;
+import processing.core.PApplet;
+
+
+/**
+ * Platform-specific glue for Windows.
+ */
+public class WindowsPlatform extends Platform {
+
+ static final String APP_NAME = "Processing";
+ static final String REG_OPEN_COMMAND =
+ System.getProperty("user.dir").replace('/', '\\') +
+ "\\" + APP_NAME.toLowerCase() + ".exe \"%1\"";
+ static final String REG_DOC = APP_NAME + ".Document";
+
+
+ public void init(Base base) {
+ super.init(base);
+ checkAssociations();
+ //checkQuickTime();
+ checkPath();
+
+ /*
+ File f = new File(System.getProperty("user.dir"), "recycle-test.txt");
+ //File f = new File("C:\\recycle-test.txt");
+ System.out.println(f.getAbsolutePath());
+ java.io.PrintWriter writer = PApplet.createWriter(f);
+ writer.println("blah");
+ writer.flush();
+ writer.close();
+ try {
+ deleteFile(f);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ */
+
+ //findJDK();
+ /*
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ie) { }
+ findJDK();
+ }
+ }).start();
+ */
+ }
+
+
+// HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit\CurrentVersion -> 1.6 (String)
+// HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit\CurrentVersion\1.6\JavaHome -> c:\jdk-1.6.0_05
+
+ /*
+ static public void findJDK() {
+ try {
+ String jcpo = System.getProperty("java.home");
+ String jv = System.getProperty("java.version");
+ System.out.println("home and version = " + jcpo + " and " + jv);
+
+ // the last parameter will be anything appearing on the right-hand
+ // side of regedit.
+ final String JDK_KEY = "SOFTWARE\\JavaSoft\\Java Development Kit";
+ String currentVersion =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.LOCAL_MACHINE,
+ JDK_KEY,
+ "CurrentVersion");
+ System.out.println("current version is " + currentVersion);
+ if (currentVersion != null) {
+ String javaHome =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.LOCAL_MACHINE,
+ JDK_KEY + "\\" + currentVersion,
+ "JavaHome");
+ System.out.println("home is where the " + javaHome + " is");
+ if (javaHome != null) {
+ String jcp = System.getProperty("java.class.path");
+ String toolsJar = javaHome + "\\lib\\tools.jar";
+ System.setProperty("java.class.path",
+ jcp + File.pathSeparator + toolsJar);
+ System.out.println("set jcp to " +
+ System.getProperty("java.class.path"));
+ }
+ }
+ } catch (UnsupportedEncodingException uee) {
+ uee.printStackTrace();
+ }
+ }
+ */
+
+
+ /**
+ * Make sure that .pde files are associated with processing.exe.
+ */
+ protected void checkAssociations() {
+ try {
+ if (Preferences.getBoolean("platform.auto_file_type_associations")) {
+ // Check the key that should be set by a previous run of Processing
+ String knownCommand =
+ WindowsRegistry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER,
+ "Software\\Classes\\" + REG_DOC + "\\shell\\open\\command", "");
+ // If the association hasn't been set, or it's not correct, set it.
+ if (knownCommand == null || !knownCommand.equals(REG_OPEN_COMMAND)) {
+ setAssociations();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Associate .pde files with this version of Processing. After 2.0.1,
+ * this was changed to only set the values for the current user, so that
+ * it would no longer silently fail on systems that have UAC turned on.
+ */
+ protected void setAssociations() throws UnsupportedEncodingException {
+ // http://support.microsoft.com/kb/184082
+ // http://msdn.microsoft.com/en-us/library/cc144175%28v=VS.85%29.aspx
+ // http://msdn.microsoft.com/en-us/library/cc144104%28v=VS.85%29.aspx
+ // http://msdn.microsoft.com/en-us/library/cc144067%28v=VS.85%29.aspx
+ // msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
+
+// HKEY_CLASSES_ROOT
+// MyProgram.exe
+// shell
+// open
+// command
+// (Default) = C:\MyDir\MyProgram.exe "%1"
+
+/*
+ REGISTRY_ROOT_KEY rootKey = REGISTRY_ROOT_KEY.CLASSES_ROOT;
+ if (Registry.createKey(rootKey,
+ "", ".pde") &&
+ Registry.setStringValue(rootKey,
+ ".pde", "", DOC) &&
+
+ Registry.createKey(rootKey, "", DOC) &&
+ Registry.setStringValue(rootKey, DOC, "",
+ "Processing Source Code") &&
+
+ Registry.createKey(rootKey,
+ DOC, "shell") &&
+ Registry.createKey(rootKey,
+ DOC + "\\shell", "open") &&
+ Registry.createKey(rootKey,
+ DOC + "\\shell\\open", "command") &&
+ Registry.setStringValue(rootKey,
+ DOC + "\\shell\\open\\command", "",
+ openCommand)) {
+*/
+
+ // "To change the settings for the interactive user, store the changes
+ // under HKEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT."
+ // msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
+ final REGISTRY_ROOT_KEY rootKey = REGISTRY_ROOT_KEY.CURRENT_USER;
+ final String docPrefix = "Software\\Classes\\" + REG_DOC;
+
+ // First create the .pde association
+ if (WindowsRegistry.createKey(rootKey, "Software\\Classes", ".pde") &&
+ WindowsRegistry.setStringValue(rootKey, "Software\\Classes\\.pde", "", REG_DOC) &&
+
+ // Now give files with a .pde extension a name for the explorer
+ WindowsRegistry.createKey(rootKey, "Software\\Classes", REG_DOC) &&
+ WindowsRegistry.setStringValue(rootKey, docPrefix, "", APP_NAME + " Source Code") &&
+
+ // Now associate the 'open' command with the current processing.exe
+ WindowsRegistry.createKey(rootKey, docPrefix, "shell") &&
+ WindowsRegistry.createKey(rootKey, docPrefix + "\\shell", "open") &&
+ WindowsRegistry.createKey(rootKey, docPrefix + "\\shell\\open", "command") &&
+ WindowsRegistry.setStringValue(rootKey, docPrefix + "\\shell\\open\\command", "", REG_OPEN_COMMAND)) {
+
+ // everything ok
+ // hooray!
+
+ } else {
+ Base.log("Could not associate files, turning off auto-associate pref.");
+ Preferences.setBoolean("platform.auto_file_type_associations", false);
+ }
+ }
+
+
+ /**
+ * Remove extra quotes, slashes, and garbage from the Windows PATH.
+ */
+ protected void checkPath() {
+ String path = System.getProperty("java.library.path");
+ String[] pieces = PApplet.split(path, File.pathSeparatorChar);
+ String[] legit = new String[pieces.length];
+ int legitCount = 0;
+ for (String item : pieces) {
+ if (item.startsWith("\"")) {
+ item = item.substring(1);
+ }
+ if (item.endsWith("\"")) {
+ item = item.substring(0, item.length() - 1);
+ }
+ if (item.endsWith(File.separator)) {
+ item = item.substring(0, item.length() - File.separator.length());
+ }
+ File directory = new File(item);
+ if (!directory.exists()) {
+ continue;
+ }
+ if (item.trim().length() == 0) {
+ continue;
+ }
+ legit[legitCount++] = item;
+ }
+ legit = PApplet.subset(legit, 0, legitCount);
+ String newPath = PApplet.join(legit, File.pathSeparator);
+ if (!newPath.equals(path)) {
+ System.setProperty("java.library.path", newPath);
+ }
+ }
+
+
+ // looking for Documents and Settings/blah/Application Data/Processing
+ public File getSettingsFolder() throws Exception {
+ String appData = getAppDataPath();
+ if (appData != null) {
+ return new File(appData, APP_NAME);
+ }
+ return null;
+ }
+
+
+ static private String getAppDataPath() throws Exception {
+ // HKEY_CURRENT_USER\Software\Microsoft
+ // \Windows\CurrentVersion\Explorer\Shell Folders
+ // Value Name: AppData
+ // Value Type: REG_SZ
+ // Value Data: path
+
+ //String keyPath =
+ // "Software\\Microsoft\\Windows\\CurrentVersion" +
+ // "\\Explorer\\Shell Folders";
+ //String appDataPath =
+ // Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "AppData");
+
+ // Fix for Issue 410
+ // Java 1.6 doesn't provide a good workaround (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519127)
+ // Using JNA and SHGetFolderPath instead.
+
+ // this will be contain the path if SHGetFolderPath is successful
+ char[] pszPath = new char[WinDef.MAX_PATH];
+ HRESULT hResult =
+ Shell32.INSTANCE.SHGetFolderPath(null, ShlObj.CSIDL_APPDATA,
+ null, ShlObj.SHGFP_TYPE_CURRENT,
+ pszPath);
+
+ if (!hResult.equals(WinError.S_OK)) {
+ System.err.println(Kernel32Util.formatMessageFromHR(hResult));
+ throw new Exception("Problem city, population: your computer.");
+ }
+
+ String appDataPath = new String(pszPath);
+ int len = appDataPath.indexOf("\0");
+// appDataPath = appDataPath.substring(0, len);
+// return new File(appDataPath, "Processing");
+ return appDataPath.substring(0, len);
+ }
+
+
+ // looking for Documents and Settings/blah/My Documents/Processing
+ public File getDefaultSketchbookFolder() throws Exception {
+ String documentsPath = getDocumentsPath();
+ if (documentsPath != null) {
+ return new File(documentsPath, APP_NAME);
+ }
+ return null;
+ }
+
+
+ static private String getDocumentsPath() throws Exception {
+ // http://support.microsoft.com/?kbid=221837&sd=RMVP
+ // http://support.microsoft.com/kb/242557/en-us
+
+ // The path to the My Documents folder is stored in the following
+ // registry key, where path is the complete path to your storage location
+
+ // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
+ // Value Name: Personal
+ // Value Type: REG_SZ
+ // Value Data: path
+
+ // in some instances, this may be overridden by a policy, in which case check:
+ // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
+
+ //String keyPath =
+ // "Software\\Microsoft\\Windows\\CurrentVersion" +
+ // "\\Explorer\\Shell Folders";
+ //String personalPath =
+ // Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "Personal");
+
+ // "The "Shell Folders" key exists solely to permit four programs written
+ // in 1994 to continue running on the RTM version of Windows 95." -- Raymond Chen, MSDN
+
+ char[] pszPath = new char[WinDef.MAX_PATH]; // this will be contain the path if SHGetFolderPath is successful
+ HRESULT hResult = Shell32.INSTANCE.SHGetFolderPath(null, ShlObj.CSIDL_PERSONAL, null, ShlObj.SHGFP_TYPE_CURRENT, pszPath);
+
+ if (!hResult.equals(WinError.S_OK)) {
+ System.err.println(Kernel32Util.formatMessageFromHR(hResult));
+ throw new Exception("Problem city, population: your computer.");
+ }
+
+ String personalPath = new String(pszPath);
+ int len = personalPath.indexOf("\0");
+// personalPath = personalPath.substring(0, len);
+// return new File(personalPath, "Processing");
+ return personalPath.substring(0, len);
+ }
+
+
+// @Override
+// public boolean deleteFile(File file) {
+// try {
+// moveToTrash(new File[] { file });
+// } catch (IOException e) {
+// e.printStackTrace();
+// Base.log("Could not move " + file.getAbsolutePath() + " to the trash.", e);
+// return false;
+// }
+// return true;
+// }
+
+
+// /**
+// * Move files/folders to the trash. If this file is on another file system
+// * or on a shared network directory, it will simply be deleted without any
+// * additional confirmation. Take that.
+// *
+// * Based on JNA source for com.sun.jna.platform.win32.W32FileUtils
+// *
+// * @param files array of File objects to be removed
+// * @return true if no error codes returned
+// * @throws IOException if something bad happened along the way
+// */
+// static private boolean moveToTrash(File[] files) throws IOException {
+// Shell32 shell = Shell32.INSTANCE;
+// SHFILEOPSTRUCT fileop = new SHFILEOPSTRUCT();
+// fileop.wFunc = ShellAPI.FO_DELETE;
+// String[] paths = new String[files.length];
+// for (int i = 0; i < paths.length; i++) {
+// paths[i] = files[i].getAbsolutePath();
+// System.out.println(paths[i]);
+// }
+// fileop.pFrom = new WString(fileop.encodePaths(paths));
+// fileop.fFlags = ShellAPI.FOF_ALLOWUNDO | ShellAPI.FOF_NO_UI;
+// int ret = shell.SHFileOperation(fileop);
+// if (ret != 0) {
+// throw new IOException("Move to trash failed: " +
+// fileop.pFrom + ": error code " + ret);
+//// throw new IOException("Move to trash failed: " + fileop.pFrom + ": " +
+//// Kernel32Util.formatMessageFromLastErrorCode(ret));
+// }
+// if (fileop.fAnyOperationsAborted) {
+// throw new IOException("Move to trash aborted");
+// }
+// return true;
+// }
+
+
+// /**
+// * Ported from ShellAPI.h in the Microsoft Windows SDK 6.0A.
+// * Modified (bastardized) version from the JNA "platform" classes.
+// * @author dblock[at]dblock.org
+// */
+// public interface ShellAPI extends StdCallLibrary {
+//
+// int STRUCTURE_ALIGNMENT = com.sun.jna.Platform.is64Bit() ?
+// Structure.ALIGN_DEFAULT : Structure.ALIGN_NONE;
+//
+// int FO_MOVE = 0x0001;
+// int FO_COPY = 0x0002;
+// int FO_DELETE = 0x0003;
+// int FO_RENAME = 0x0004;
+//
+// int FOF_MULTIDESTFILES = 0x0001;
+// int FOF_CONFIRMMOUSE = 0x0002;
+// int FOF_SILENT = 0x0004; // don't display progress UI (confirm prompts may be displayed still)
+// int FOF_RENAMEONCOLLISION = 0x0008; // automatically rename the source files to avoid the collisions
+// int FOF_NOCONFIRMATION = 0x0010; // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not
+// int FOF_WANTMAPPINGHANDLE = 0x0020; // Fill in SHFILEOPSTRUCT.hNameMappings
+// int FOF_ALLOWUNDO = 0x0040; // enable undo including Recycle behavior for IFileOperation::Delete()
+// int FOF_FILESONLY = 0x0080; // only operate on the files (non folders), both files and folders are assumed without this
+// int FOF_SIMPLEPROGRESS = 0x0100; // means don't show names of files
+// int FOF_NOCONFIRMMKDIR = 0x0200; // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases
+// int FOF_NOERRORUI = 0x0400; // don't put up error UI, other UI may be displayed, progress, confirmations
+// int FOF_NOCOPYSECURITYATTRIBS = 0x0800; // dont copy file security attributes (ACLs)
+// int FOF_NORECURSION = 0x1000; // don't recurse into directories for operations that would recurse
+// int FOF_NO_CONNECTED_ELEMENTS = 0x2000; // don't operate on connected elements ("xxx_files" folders that go with .htm files)
+// int FOF_WANTNUKEWARNING = 0x4000; // during delete operation, warn if nuking instead of recycling (partially overrides FOF_NOCONFIRMATION)
+// int FOF_NORECURSEREPARSE = 0x8000; // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts)
+// int FOF_NO_UI = (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR); // don't display any UI at all
+//
+// int PO_DELETE = 0x0013; // printer is being deleted
+// int PO_RENAME = 0x0014; // printer is being renamed
+// int PO_PORTCHANGE = 0x0020; // port this printer connected to is being changed
+// int PO_REN_PORT = 0x0034; // PO_RENAME and PO_PORTCHANGE at same time.
+// }
+
+
+ /*
+ public void openURL(String url) throws Exception {
+ // this is not guaranteed to work, because who knows if the
+ // path will always be c:\progra~1 et al. also if the user has
+ // a different browser set as their default (which would
+ // include me) it'd be annoying to be dropped into ie.
+ //Runtime.getRuntime().exec("c:\\progra~1\\intern~1\\iexplore "
+ // + currentDir
+
+ // the following uses a shell execute to launch the .html file
+ // note that under cygwin, the .html files have to be chmodded +x
+ // after they're unpacked from the zip file. i don't know why,
+ // and don't understand what this does in terms of windows
+ // permissions. without the chmod, the command prompt says
+ // "Access is denied" in both cygwin and the "dos" prompt.
+ //Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" +
+ // referenceFile + ".html");
+ if (url.startsWith("http://")) {
+ // open dos prompt, give it 'start' command, which will
+ // open the url properly. start by itself won't work since
+ // it appears to need cmd
+ Runtime.getRuntime().exec("cmd /c start " + url);
+ } else {
+ // just launching the .html file via the shell works
+ // but make sure to chmod +x the .html files first
+ // also place quotes around it in case there's a space
+ // in the user.dir part of the url
+ Runtime.getRuntime().exec("cmd /c \"" + url + "\"");
+ }
+ }
+
+
+ public boolean openFolderAvailable() {
+ return true;
+ }
+
+
+ public void openFolder(File file) throws Exception {
+ String folder = file.getAbsolutePath();
+
+ // doesn't work
+ //Runtime.getRuntime().exec("cmd /c \"" + folder + "\"");
+
+ // works fine on winxp, prolly win2k as well
+ Runtime.getRuntime().exec("explorer \"" + folder + "\"");
+
+ // not tested
+ //Runtime.getRuntime().exec("start explorer \"" + folder + "\"");
+ }
+ */
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ // Code partially thanks to Richard Quirk from:
+ // http://quirkygba.blogspot.com/2009/11/setting-environment-variables-in-java.html
+
+ static WinLibC clib = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
+
+ public interface WinLibC extends Library {
+ //WinLibC INSTANCE = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
+ //libc = Native.loadLibrary("msvcrt", WinLibC.class);
+ public int _putenv(String name);
+ }
+
+
+ public void setenv(String variable, String value) {
+ //WinLibC clib = WinLibC.INSTANCE;
+ clib._putenv(variable + "=" + value);
+ }
+
+
+ public String getenv(String variable) {
+ return System.getenv(variable);
+ }
+
+
+ public int unsetenv(String variable) {
+ //WinLibC clib = WinLibC.INSTANCE;
+ //clib._putenv(variable + "=");
+ //return 0;
+ return clib._putenv(variable + "=");
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+ // JNA code for using SHGetFolderPath to fix Issue 410
+ // https://code.google.com/p/processing/issues/detail?id=410
+ // Based on answer provided by McDowell at
+ // http://stackoverflow.com/questions/585534/what-is-the-best-way-to-find-the-users-home-directory-in-java/586917#586917
+
+// private static Map OPTIONS = new HashMap();
+//
+// static {
+// OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
+// OPTIONS.put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
+// }
+//
+//
+// static class HANDLE extends PointerType implements NativeMapped {
+// public HANDLE() { }
+// }
+//
+// static class HWND extends HANDLE { }
+//
+//
+// public interface Shell32 extends Library {
+//
+// public static final int MAX_PATH = 260;
+// public static final int SHGFP_TYPE_CURRENT = 0;
+// public static final int SHGFP_TYPE_DEFAULT = 1;
+// public static final int S_OK = 0;
+//
+// // KNOWNFOLDERIDs are preferred to CSDIL values
+// // but Windows XP only supports CSDIL so thats what we have to use
+// public static final int CSIDL_APPDATA = 0x001a; // "Application Data"
+// public static final int CSIDL_PERSONAL = 0x0005; // "My Documents"
+//
+// static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, OPTIONS);
+//
+// /**
+// * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
+// *
+// * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken,
+// * DWORD dwFlags, LPTSTR pszPath);
+// */
+// public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken,
+// int dwFlags, char[] pszPath);
+//
+// /**
+// * This function can be used to copy, move, rename,
+// * or delete a file system object.
+// * @param fileop Address of an SHFILEOPSTRUCT structure that contains
+// * information this function needs to carry out the specified operation.
+// * @return Returns zero if successful, or nonzero otherwise.
+// */
+// public int SHFileOperation(SHFILEOPSTRUCT fileop);
+// }
+}
diff --git a/app/src/processing/app/platform/WindowsRegistry.java b/app/src/processing/app/platform/WindowsRegistry.java
new file mode 100644
index 000000000..dd2581cd5
--- /dev/null
+++ b/app/src/processing/app/platform/WindowsRegistry.java
@@ -0,0 +1,486 @@
+package processing.app.platform;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import com.sun.jna.platform.win32.Advapi32;
+import com.sun.jna.platform.win32.WinBase;
+import com.sun.jna.platform.win32.WinError;
+import com.sun.jna.platform.win32.WinNT;
+import com.sun.jna.platform.win32.WinReg;
+import com.sun.jna.platform.win32.WinReg.HKEY;
+import com.sun.jna.platform.win32.WinReg.HKEYByReference;
+import com.sun.jna.ptr.IntByReference;
+
+
+/**
+ * Methods for accessing the Windows Registry. Only String and DWORD values
+ * supported at the moment.
+ *
+ * Not sure where this code came from originally (if you know the reference,
+ * please get in touch so that we can add a proper citation). Several changes
+ * were made to update it for JNA 3.5.2's platform classes and clean up the
+ * syntax to make it less like a C program. [fry 130720]
+ */
+public class WindowsRegistry {
+ static public enum REGISTRY_ROOT_KEY {
+ CLASSES_ROOT, CURRENT_USER, LOCAL_MACHINE, USERS
+ };
+ //private final static HashMap rootKeyMap = new HashMap();
+ private final static HashMap rootKeyMap =
+ new HashMap();
+
+ static {
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CLASSES_ROOT, WinReg.HKEY_CLASSES_ROOT);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CURRENT_USER, WinReg.HKEY_CURRENT_USER);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.LOCAL_MACHINE, WinReg.HKEY_LOCAL_MACHINE);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.USERS, WinReg.HKEY_USERS);
+ }
+
+
+ /**
+ * Gets one of the root keys.
+ *
+ * @param key key type
+ * @return root key
+ */
+ private static HKEY getRegistryRootKey(REGISTRY_ROOT_KEY key) {
+ //Advapi32 advapi32;
+ //IntByReference pHandle;
+ //int handle = 0;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+// pHandle = new IntByReference();
+ HKEYByReference pHandle = new WinReg.HKEYByReference();
+
+ HKEY handle = null;
+ if (advapi32.RegOpenKeyEx(rootKeyMap.get(key), null, 0, 0, pHandle) == WinError.ERROR_SUCCESS) {
+ handle = pHandle.getValue();
+ }
+ return handle;
+ }
+
+
+ /**
+ * Opens a key.
+ *
+ * @param rootKey root key
+ * @param subKeyName name of the key
+ * @param access access mode
+ * @return handle to the key or 0
+ */
+ private static HKEY openKey(REGISTRY_ROOT_KEY rootKey, String subKeyName, int access) {
+ //Advapi32 advapi32;
+ //IntByReference pHandle;
+ //int rootKeyHandle;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY rootKeyHandle = getRegistryRootKey(rootKey);
+ //pHandle = new IntByReference();
+ HKEYByReference pHandle = new HKEYByReference();
+
+ if (advapi32.RegOpenKeyEx(rootKeyHandle, subKeyName, 0, access, pHandle) == WinError.ERROR_SUCCESS) {
+ return pHandle.getValue();
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Converts a Windows buffer to a Java String.
+ *
+ * @param buf buffer
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String
+ */
+ private static String convertBufferToString(byte[] buf) throws UnsupportedEncodingException {
+ return new String(buf, 0, buf.length - 2, "UTF-16LE");
+ }
+
+
+ /**
+ * Converts a Windows buffer to an int.
+ *
+ * @param buf buffer
+ * @return int
+ */
+ private static int convertBufferToInt(byte[] buf) {
+ return ((buf[0] & 0xff) +
+ ((buf[1] & 0xff) << 8) +
+ ((buf[2] & 0xff) << 16) +
+ ((buf[3] & 0xff) << 24));
+ }
+
+
+ /**
+ * Read a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String or null
+ */
+ static public String getStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) throws UnsupportedEncodingException {
+ //Advapi32 advapi32;
+ //IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ //int handle = 0;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ IntByReference pType = new IntByReference();
+ IntByReference lpcbData = new IntByReference();
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ);
+
+ String ret = null;
+ //if (handle != 0) {
+ if (handle != null) {
+ //if (advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WinError.ERROR_MORE_DATA) {
+ if (advapi32.RegQueryValueEx(handle, name, 0, pType, lpData, lpcbData) == WinError.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ //if (advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WinError.ERROR_SUCCESS) {
+ if (advapi32.RegQueryValueEx(handle, name, 0, pType, lpData, lpcbData) == WinError.ERROR_SUCCESS) {
+ ret = convertBufferToString(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Read an int value.
+ *
+ * @return int or 0
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ */
+ static public int getIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ IntByReference pType = new IntByReference();
+ IntByReference lpcbData = new IntByReference();
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ);
+
+ int ret = 0;
+ byte[] lpData = new byte[1];
+ //if(handle != 0) {
+ if (handle != null) {
+ //if (advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WinError.ERROR_MORE_DATA) {
+ if (advapi32.RegQueryValueEx(handle, name, 0, pType, lpData, lpcbData) == WinError.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ //if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WinError.ERROR_SUCCESS) {
+ if (advapi32.RegQueryValueEx(handle, name, 0, pType, lpData, lpcbData) == WinError.ERROR_SUCCESS) {
+ ret = convertBufferToInt(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Delete a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true on success
+ */
+ static public boolean deleteValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ //int handle;
+
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ | WinNT.KEY_WRITE);
+
+ boolean ret = true;
+ //if(handle != 0) {
+ if (handle != null) {
+ if (advapi32.RegDeleteValue(handle, name) == WinError.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Writes a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return true on success
+ */
+ static public boolean setStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, String value) throws UnsupportedEncodingException {
+ //int handle;
+ //byte[] data;
+
+ // appears to be Java 1.6 syntax, removing [fry]
+ //data = Arrays.copyOf(value.getBytes("UTF-16LE"), value.length() * 2 + 2);
+ byte[] data = new byte[value.length() * 2 + 2];
+ byte[] src = value.getBytes("UTF-16LE");
+ System.arraycopy(src, 0, data, 0, src.length);
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ | WinNT.KEY_WRITE);
+
+ boolean ret = false;
+ //if(handle != 0) {
+ if (handle != null) {
+ if (advapi32.RegSetValueEx(handle, name, 0, WinNT.REG_SZ, data, data.length) == WinError.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Writes an int value.
+ *
+ * @return true on success
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ */
+ static public boolean setIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, int value) {
+ //Advapi32 advapi32;
+ //int handle;
+ //byte[] data;
+
+ byte[] data = new byte[4];
+ data[0] = (byte)(value & 0xff);
+ data[1] = (byte)((value >> 8) & 0xff);
+ data[2] = (byte)((value >> 16) & 0xff);
+ data[3] = (byte)((value >> 24) & 0xff);
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ | WinNT.KEY_WRITE);
+
+ boolean ret = false;
+ //if(handle != 0) {
+ if (handle != null) {
+ if (advapi32.RegSetValueEx(handle, name, 0, WinNT.REG_DWORD, data, data.length) == WinError.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Check for existence of a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true if exists
+ */
+ static public boolean valueExists(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ //Advapi32 advapi32;
+ //IntByReference pType, lpcbData;
+ //int handle = 0;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ IntByReference pType = new IntByReference();
+ IntByReference lpcbData = new IntByReference();
+ HKEY handle = openKey(rootKey, subKeyName, WinNT.KEY_READ);
+
+ byte[] lpData = new byte[1];
+ boolean ret = false;
+ //if(handle != 0) {
+ if (handle != null) {
+ //if (advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) != WinError.ERROR_FILE_NOT_FOUND) {
+ if (advapi32.RegQueryValueEx(handle, name, 0, pType, lpData, lpcbData) != WinError.ERROR_FILE_NOT_FOUND) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Create a new key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ static public boolean createKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ //Advapi32 advapi32;
+ //IntByReference hkResult, dwDisposition;
+ //int handle = 0;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ //IntByReference hkResult = new IntByReference();
+ HKEYByReference hkResult = new HKEYByReference();
+ IntByReference dwDisposition = new IntByReference();
+ HKEY handle = openKey(rootKey, parent, WinNT.KEY_READ);
+
+ boolean ret = false;
+ //if(handle != 0) {
+ if (handle != null) {
+ if (advapi32.RegCreateKeyEx(handle, name, 0, null, WinNT.REG_OPTION_NON_VOLATILE, WinNT.KEY_READ, null,
+ hkResult, dwDisposition) == WinError.ERROR_SUCCESS) {
+ ret = true;
+ advapi32.RegCloseKey(hkResult.getValue());
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Delete a key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ static public boolean deleteKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ //Advapi32 advapi32;
+ //int handle = 0;
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY handle = openKey(rootKey, parent, WinNT.KEY_READ);
+
+ boolean ret = false;
+ //if(handle != 0) {
+ if (handle != null) {
+ if (advapi32.RegDeleteKey(handle, name) == WinError.ERROR_SUCCESS) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return ret;
+ }
+
+
+ /**
+ * Get all sub keys of a key.
+ *
+ * @param rootKey root key
+ * @param parent key name
+ * @return array with all sub key names
+ */
+ static public String[] getSubKeys(REGISTRY_ROOT_KEY rootKey, String parent) {
+ //Advapi32 advapi32;
+ //int handle = 0, dwIndex;
+ //char[] lpName;
+ //IntByReference lpcName;
+ //WinBase.FILETIME lpftLastWriteTime;
+ TreeSet subKeys = new TreeSet();
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY handle = openKey(rootKey, parent, WinNT.KEY_READ);
+ char[] lpName = new char[256];
+ IntByReference lpcName = new IntByReference(256);
+ WinBase.FILETIME lpftLastWriteTime = new WinBase.FILETIME();
+
+ //if(handle != 0) {
+ if (handle != null) {
+ int dwIndex = 0;
+
+ while (advapi32.RegEnumKeyEx(handle, dwIndex, lpName, lpcName, null,
+ null, null, lpftLastWriteTime) == WinError.ERROR_SUCCESS) {
+ subKeys.add(new String(lpName, 0, lpcName.getValue()));
+ lpcName.setValue(256);
+ dwIndex++;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return subKeys.toArray(new String[] { });
+ }
+
+
+ /**
+ * Get all values under a key.
+ *
+ * @param rootKey root key
+ * @param key jey name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return TreeMap with name and value pairs
+ */
+ static public TreeMap getValues(REGISTRY_ROOT_KEY rootKey, String key) throws UnsupportedEncodingException {
+ //Advapi32 advapi32;
+ //int handle = 0, dwIndex, result = 0;
+ //char[] lpValueName;
+ //byte[] lpData;
+ //IntByReference lpcchValueName, lpType, lpcbData;
+ //String name;
+ TreeMap values =
+ new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+ Advapi32 advapi32 = Advapi32.INSTANCE;
+ HKEY handle = openKey(rootKey, key, WinNT.KEY_READ);
+ char[] lpValueName = new char[16384];
+ IntByReference lpcchValueName = new IntByReference(16384);
+ IntByReference lpType = new IntByReference();
+ byte[] lpData = new byte[1];
+ IntByReference lpcbData = new IntByReference();
+
+ //if(handle != 0) {
+ if (handle != null) {
+ int dwIndex = 0;
+ int result = 0;
+ String name;
+
+ do {
+ lpcbData.setValue(0);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if (result == WinError.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+ lpcchValueName = new IntByReference(16384);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if (result == WinError.ERROR_SUCCESS) {
+ name = new String(lpValueName, 0, lpcchValueName.getValue());
+
+ switch(lpType.getValue()) {
+ case WinNT.REG_SZ:
+ values.put(name, convertBufferToString(lpData));
+ break;
+ case WinNT.REG_DWORD:
+ values.put(name, convertBufferToInt(lpData));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ dwIndex++;
+ } while (result == WinError.ERROR_SUCCESS);
+
+ advapi32.RegCloseKey(handle);
+ }
+ return values;
+ }
+}
diff --git a/app/src/processing/app/syntax/HtmlSelection.java b/app/src/processing/app/syntax/HtmlSelection.java
index d8e906604..d7a016aa5 100644
--- a/app/src/processing/app/syntax/HtmlSelection.java
+++ b/app/src/processing/app/syntax/HtmlSelection.java
@@ -9,12 +9,14 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
+
public class HtmlSelection implements Transferable {
- private static List flavors = new ArrayList();
+ private static List flavors;
static {
try {
+ flavors = new ArrayList();
flavors.add(DataFlavor.stringFlavor);
flavors.add(new DataFlavor("text/html;class=java.lang.String"));
flavors.add(new DataFlavor("text/html;class=java.io.Reader"));
@@ -26,18 +28,22 @@ public class HtmlSelection implements Transferable {
private String html;
+
public HtmlSelection(String html) {
this.html = html;
}
+
public DataFlavor[] getTransferDataFlavors() {
return flavors.toArray(new DataFlavor[flavors.size()]);
}
+
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavors.contains(flavor);
}
+
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (flavor.equals(DataFlavor.stringFlavor)) {
diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java
index 361f41def..bc5bb0ed3 100644
--- a/app/src/processing/app/syntax/JEditTextArea.java
+++ b/app/src/processing/app/syntax/JEditTextArea.java
@@ -24,7 +24,9 @@ import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
import javax.swing.*;
+
import java.awt.im.InputMethodRequests;
+import java.awt.print.Printable;
import processing.app.syntax.im.InputMethodSupport;
import processing.core.PApplet;
@@ -78,7 +80,7 @@ public class JEditTextArea extends JComponent
private InputMethodSupport inputMethodSupport = null;
private Brackets bracketHelper = new Brackets();
-
+
/**
* Creates a new JEditTextArea with the specified settings.
@@ -129,7 +131,7 @@ public class JEditTextArea extends JComponent
// Load the defaults
setInputHandler(defaults.inputHandler);
setDocument(defaults.document);
- editable = defaults.editable;
+// editable = defaults.editable;
caretVisible = defaults.caretVisible;
caretBlinks = defaults.caretBlinks;
electricScroll = defaults.electricScroll;
@@ -156,8 +158,8 @@ public class JEditTextArea extends JComponent
// System.out.println(" mods extext = " + mods + " " + mods.length() + " " + PApplet.hex(mods.charAt(0)));
// }
// System.out.println(" " + e);
-
- // inertia scrolling on OS X will fire several shift-wheel events
+
+ // inertia scrolling on OS X will fire several shift-wheel events
// that are negative values.. this makes the scrolling area jump.
boolean skip = Base.isMacOS() && e.isShiftDown();
//if (ex == 0) {
@@ -187,7 +189,7 @@ public class JEditTextArea extends JComponent
return null;
}
-
+
/**
* Get current position of the vertical scroll bar. [fry]
*/
@@ -210,8 +212,13 @@ public class JEditTextArea extends JComponent
public final TextAreaPainter getPainter() {
return painter;
}
-
+
+ public final Printable getPrintable() {
+ return painter.getPrintable();
+ }
+
+
/**
* Returns the input handler.
*/
@@ -219,7 +226,7 @@ public class JEditTextArea extends JComponent
return inputHandler;
}
-
+
/**
* Sets the input handler.
* @param inputHandler The new input handler
@@ -228,7 +235,7 @@ public class JEditTextArea extends JComponent
this.inputHandler = inputHandler;
}
-
+
/**
* Returns true if the caret is blinking, false otherwise.
*/
@@ -236,7 +243,7 @@ public class JEditTextArea extends JComponent
return caretBlinks;
}
-
+
/**
* Toggles caret blinking.
* @param caretBlinks True if the caret should blink, false otherwise
@@ -249,7 +256,7 @@ public class JEditTextArea extends JComponent
painter.invalidateSelectedLines();
}
-
+
/**
* Returns true if the caret is visible, false otherwise.
*/
@@ -257,7 +264,7 @@ public class JEditTextArea extends JComponent
return (!caretBlinks || blink) && caretVisible;
}
-
+
/**
* Sets if the caret should be visible.
* @param caretVisible True if the caret should be visible, false
@@ -270,7 +277,7 @@ public class JEditTextArea extends JComponent
painter.invalidateSelectedLines();
}
-
+
/**
* Blinks the caret.
*/
@@ -283,7 +290,7 @@ public class JEditTextArea extends JComponent
}
}
-
+
/**
* Returns the number of lines from the top and button of the
* text area that are always visible.
@@ -292,7 +299,7 @@ public class JEditTextArea extends JComponent
return electricScroll;
}
-
+
/**
* Sets the number of lines from the top and bottom of the text
* area that are always visible
@@ -349,7 +356,7 @@ public class JEditTextArea extends JComponent
}
}
-
+
/**
* Returns the line displayed at the text area's origin.
*/
@@ -357,7 +364,7 @@ public class JEditTextArea extends JComponent
return firstLine;
}
-
+
/**
* Sets the line displayed at the text area's origin without
* updating the scroll bars.
@@ -371,15 +378,15 @@ public class JEditTextArea extends JComponent
}
painter.repaint();
}
-
-
- /**
- * Convenience for checking what's on-screen. [fry]
+
+
+ /**
+ * Convenience for checking what's on-screen. [fry]
*/
public final int getLastLine() {
return getFirstLine() + getVisibleLines();
}
-
+
/**
* Returns the number of lines visible in this text area.
@@ -388,7 +395,7 @@ public class JEditTextArea extends JComponent
return visibleLines;
}
-
+
/**
* Recalculates the number of visible lines. This should not
* be called directly.
@@ -402,7 +409,7 @@ public class JEditTextArea extends JComponent
updateScrollBars();
}
-
+
/**
* Returns the horizontal offset of drawn lines.
*/
@@ -410,7 +417,7 @@ public class JEditTextArea extends JComponent
return horizontalOffset;
}
-
+
/**
* Sets the horizontal offset of drawn lines. This can be used to
* implement horizontal scrolling.
@@ -427,7 +434,7 @@ public class JEditTextArea extends JComponent
painter.repaint();
}
-
+
/**
* A fast way of changing both the first line and horizontal
* offset.
@@ -442,12 +449,12 @@ public class JEditTextArea extends JComponent
this.horizontalOffset = horizontalOffset;
changed = true;
}
-
+
if (firstLine != this.firstLine) {
this.firstLine = firstLine;
changed = true;
}
-
+
if (changed) {
updateScrollBars();
painter.repaint();
@@ -455,7 +462,7 @@ public class JEditTextArea extends JComponent
return changed;
}
-
+
/**
* Ensures that the caret is visible by scrolling the text area if
* necessary.
@@ -471,7 +478,7 @@ public class JEditTextArea extends JComponent
return scrollTo(line,offset);
}
-
+
/**
* Ensures that the specified line and offset is visible by scrolling
* the text area if necessary.
@@ -516,7 +523,7 @@ public class JEditTextArea extends JComponent
return setOrigin(newFirstLine,newHorizontalOffset);
}
-
+
/**
* Converts a line index to a y co-ordinate.
* @param line The line
@@ -527,7 +534,7 @@ public class JEditTextArea extends JComponent
- (fm.getLeading() + fm.getMaxDescent());
}
-
+
/**
* Converts a y co-ordinate to a line index.
* @param y The y co-ordinate
@@ -539,7 +546,7 @@ public class JEditTextArea extends JComponent
y / height + firstLine));
}
-
+
/**
* Converts an offset in a line into an x co-ordinate. This is a
* slow version that can be used any time.
@@ -552,7 +559,7 @@ public class JEditTextArea extends JComponent
return _offsetToX(line,offset);
}
-
+
/**
* Converts an offset in a line into an x coordinate. This is a
* fast version that should only be used if no changes were made
@@ -575,9 +582,9 @@ public class JEditTextArea extends JComponent
if (tokenMarker == null) {
lineSegment.count = offset;
return x + Utilities.getTabbedTextWidth(lineSegment, fm, x, painter, 0);
-
+
} else {
- // If syntax coloring is enabled, we have to do this
+ // If syntax coloring is enabled, we have to do this
// because tokens can vary in width
Token tokens;
if (painter.currentLineIndex == line && painter.currentLineTokens != null) {
@@ -587,7 +594,7 @@ public class JEditTextArea extends JComponent
tokens = painter.currentLineTokens = tokenMarker.markTokens(lineSegment, line);
}
- Font defaultFont = painter.getFont();
+// Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
for (;;) {
@@ -599,7 +606,8 @@ public class JEditTextArea extends JComponent
if (id == Token.NULL) {
fm = painter.getFontMetrics();
} else {
- fm = styles[id].getFontMetrics(defaultFont, this);
+ //fm = styles[id].getFontMetrics(defaultFont, this);
+ fm = painter.getFontMetrics(styles[id]);
}
int length = tokens.length;
@@ -674,19 +682,21 @@ public class JEditTextArea extends JComponent
}
int offset = 0;
- Font defaultFont = painter.getFont();
+// Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
// System.out.println("painter is " + painter + ", doc is " + document);
- for(;;) {
+ for (;;) {
byte id = tokens.id;
if(id == Token.END)
return offset;
- if(id == Token.NULL)
+ if (id == Token.NULL) {
fm = painter.getFontMetrics();
- else
- fm = styles[id].getFontMetrics(defaultFont, this);
+ } else {
+ //fm = styles[id].getFontMetrics(defaultFont, this);
+ fm = painter.getFontMetrics(styles[id]);
+ }
int length = tokens.length;
@@ -1395,30 +1405,23 @@ public class JEditTextArea extends JComponent
* Replaces the selection with the specified text.
* @param selectedText The replacement text for the selection
*/
- public void setSelectedText(String selectedText)
- {
- if(!editable)
- {
- throw new InternalError("Text component"
- + " read only");
+ public void setSelectedText(String selectedText) {
+ if (!editable) {
+ throw new InternalError("Text component read only");
}
-
document.beginCompoundEdit();
- try
- {
- if(rectSelect)
- {
+ try {
+ if (rectSelect) {
Element map = document.getDefaultRootElement();
- int start = selectionStart - map.getElement(selectionStartLine)
- .getStartOffset();
- int end = selectionEnd - map.getElement(selectionEndLine)
- .getStartOffset();
+ int start = selectionStart -
+ map.getElement(selectionStartLine).getStartOffset();
+ int end = selectionEnd -
+ map.getElement(selectionEndLine).getStartOffset();
// Certain rectangles satisfy this condition...
- if(end < start)
- {
+ if (end < start) {
int tmp = end;
end = start;
start = tmp;
@@ -1427,123 +1430,102 @@ public class JEditTextArea extends JComponent
int lastNewline = 0;
int currNewline = 0;
- for(int i = selectionStartLine; i <= selectionEndLine; i++)
- {
+ for (int i = selectionStartLine; i <= selectionEndLine; i++) {
Element lineElement = map.getElement(i);
int lineStart = lineElement.getStartOffset();
int lineEnd = lineElement.getEndOffset() - 1;
int rectStart = Math.min(lineEnd,lineStart + start);
- document.remove(rectStart,Math.min(lineEnd - rectStart,
- end - start));
+ document.remove(rectStart,Math.min(lineEnd - rectStart, end - start));
- if(selectedText == null)
- continue;
-
- currNewline = selectedText.indexOf('\n',lastNewline);
- if(currNewline == -1)
- currNewline = selectedText.length();
-
- document.insertString(rectStart,selectedText
- .substring(lastNewline,currNewline),null);
-
- lastNewline = Math.min(selectedText.length(),
- currNewline + 1);
+ if (selectedText != null) {
+ currNewline = selectedText.indexOf('\n', lastNewline);
+ if (currNewline == -1) {
+ currNewline = selectedText.length();
+ }
+ document.insertString(rectStart, selectedText.substring(lastNewline, currNewline), null);
+ lastNewline = Math.min(selectedText.length(), currNewline + 1);
+ }
}
- if(selectedText != null &&
- currNewline != selectedText.length())
- {
- int offset = map.getElement(selectionEndLine)
- .getEndOffset() - 1;
- document.insertString(offset,"\n",null);
- document.insertString(offset + 1,selectedText
- .substring(currNewline + 1),null);
+ if (selectedText != null &&
+ currNewline != selectedText.length()) {
+ int offset = map.getElement(selectionEndLine).getEndOffset() - 1;
+ document.insertString(offset, "\n", null);
+ document.insertString(offset + 1,selectedText.substring(currNewline + 1), null);
+ }
+ } else {
+ document.remove(selectionStart, selectionEnd - selectionStart);
+ if (selectedText != null) {
+ document.insertString(selectionStart, selectedText,null);
}
}
- else
- {
- document.remove(selectionStart,
- selectionEnd - selectionStart);
- if(selectedText != null)
- {
- document.insertString(selectionStart,
- selectedText,null);
- }
- }
- }
- catch(BadLocationException bl)
- {
+ } catch(BadLocationException bl) {
bl.printStackTrace();
- throw new InternalError("Cannot replace"
- + " selection");
- }
- // No matter what happends... stops us from leaving document
- // in a bad state
- finally
- {
+ throw new InternalError("Cannot replace selection");
+
+ } finally {
+ // No matter what happens... stops us from leaving document in a bad state
document.endCompoundEdit();
}
-
setCaretPosition(selectionEnd);
}
+
/**
* Returns true if this text area is editable, false otherwise.
*/
- public final boolean isEditable()
- {
+ public final boolean isEditable() {
return editable;
}
+
/**
* Sets if this component is editable.
* @param editable True if this text area should be editable,
* false otherwise
*/
- public final void setEditable(boolean editable)
- {
+ public final void setEditable(boolean editable) {
this.editable = editable;
}
+
/**
* Returns the right click popup menu.
*/
- public final JPopupMenu getRightClickPopup()
- {
+ public final JPopupMenu getRightClickPopup() {
return popup;
}
+
/**
* Sets the right click popup menu.
* @param popup The popup
*/
- //public final void setRightClickPopup(EditPopupMenu popup)
- public final void setRightClickPopup(JPopupMenu popup)
- {
+ public final void setRightClickPopup(JPopupMenu popup) {
this.popup = popup;
}
/**
- * Returns the `magic' caret position. This can be used to preserve
+ * Returns the 'magic' caret position. This can be used to preserve
* the column position when moving up and down lines.
*/
- public final int getMagicCaretPosition()
- {
+ public final int getMagicCaretPosition() {
return magicCaret;
}
+
/**
- * Sets the `magic' caret position. This can be used to preserve
+ * Sets the 'magic' caret position. This can be used to preserve
* the column position when moving up and down lines.
* @param magicCaret The magic caret position
*/
- public final void setMagicCaretPosition(int magicCaret)
- {
+ public final void setMagicCaretPosition(int magicCaret) {
this.magicCaret = magicCaret;
}
+
/**
* Similar to setSelectedText(), but overstrikes the
* appropriate number of characters if overwrite mode is enabled.
@@ -1880,11 +1862,21 @@ public class JEditTextArea extends JComponent
selection = selection.replaceAll("\t", tabString);
}
- // particularly on macosx when pasting from safari,
- // replace unicode x00A0 (non-breaking space)
- // with just a plain space. [fry 030929]
+ // Replace unicode x00A0 (non-breaking space) with just a plain space.
+ // Seen often on Mac OS X when pasting from Safari. [fry 030929]
selection = selection.replace('\u00A0', ' ');
+ // Remove ASCII NUL characters. Reported when pasting from
+ // Acrobat Reader and PDF documents. [fry 130719]
+ // https://github.com/processing/processing/issues/1973
+ if (selection.indexOf('\0') != -1) {
+ //System.out.println("found NUL charaacters");
+ //int before = selection.length();
+ selection = selection.replaceAll("\0", "");
+ //int after = selection.length();
+ //System.out.println(before + " " + after);
+ }
+
int repeatCount = inputHandler.getRepeatCount();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < repeatCount; i++) {
@@ -1973,7 +1965,7 @@ public class JEditTextArea extends JComponent
protected boolean caretVisible;
protected boolean blink;
- protected boolean editable;
+ protected boolean editable = true;
protected int firstLine;
protected int visibleLines;
@@ -2323,8 +2315,8 @@ public class JEditTextArea extends JComponent
}
}
-
- class DragHandler implements MouseMotionListener
+
+ class DragHandler implements MouseMotionListener
{
public void mouseDragged(MouseEvent evt) {
if (popup != null && popup.isVisible()) return;
@@ -2359,28 +2351,21 @@ public class JEditTextArea extends JComponent
}
- class FocusHandler implements FocusListener
- {
- public void focusGained(FocusEvent evt)
- {
-// System.out.println("JEditTextArea: focusGained");
+ class FocusHandler implements FocusListener {
+
+ public void focusGained(FocusEvent evt) {
setCaretVisible(true);
-// focusedComponent = JEditTextArea.this;
}
- public void focusLost(FocusEvent evt)
- {
-// System.out.println("JEditTextArea: focusLost");
+ public void focusLost(FocusEvent evt) {
setCaretVisible(false);
-// focusedComponent = null;
}
}
- class MouseHandler extends MouseAdapter
- {
- public void mousePressed(MouseEvent evt)
- {
+ class MouseHandler extends MouseAdapter {
+
+ public void mousePressed(MouseEvent event) {
// try {
// requestFocus();
// // Focus events not fired sometimes?
@@ -2393,48 +2378,41 @@ public class JEditTextArea extends JComponent
// the problem, though it's not clear why the wrong Document data was
// being using regardless of the focusedComponent.
// if (focusedComponent != JEditTextArea.this) return;
- if (!hasFocus()) {
+ if (!hasFocus()) {
// System.out.println("requesting focus in window");
- requestFocusInWindow();
- return;
- }
-
- // isPopupTrigger wasn't working for danh on windows
- boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0;
- // but it's required for macosx, since control-click does
- // the same thing as a right-mouse click
- if (!trigger && evt.isPopupTrigger()) trigger = true;
-
- if (trigger && (popup != null)) {
- popup.show(painter,evt.getX(),evt.getY());
+ requestFocusInWindow();
return;
}
- int line = yToLine(evt.getY());
- int offset = xToOffset(line,evt.getX());
+ if (event.isPopupTrigger() && (popup != null)) {
+ popup.show(painter, event.getX(), event.getY());
+ return;
+ }
+
+ int line = yToLine(event.getY());
+ int offset = xToOffset(line, event.getX());
int dot = getLineStartOffset(line) + offset;
selectLine = false;
selectWord = false;
- switch(evt.getClickCount()) {
+ switch (event.getClickCount()) {
case 1:
- doSingleClick(evt,line,offset,dot);
+ doSingleClick(event,line,offset,dot);
break;
case 2:
- // It uses the bracket matching stuff, so
- // it can throw a BLE
+ // It uses the bracket matching stuff, so it can throw a BLE
try {
- doDoubleClick(evt,line,offset,dot);
- } catch(BadLocationException bl) {
+ doDoubleClick(event, line, offset, dot);
+ } catch (BadLocationException bl) {
bl.printStackTrace();
}
break;
case 3:
- doTripleClick(evt,line,offset,dot);
+ doTripleClick(event,line,offset,dot);
break;
}
// } catch (ArrayIndexOutOfBoundsException aioobe) {
@@ -2445,8 +2423,17 @@ public class JEditTextArea extends JComponent
}
- private void doSingleClick(MouseEvent evt, int line,
- int offset, int dot) {
+ // Because isPopupTrigger() is handled differently across platforms,
+ // it may fire during release, or during the press.
+ // http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html#isPopupTrigger()
+ public void mouseReleased(MouseEvent event) {
+ if (event.isPopupTrigger() && (popup != null)) {
+ popup.show(painter, event.getX(), event.getY());
+ }
+ }
+
+
+ private void doSingleClick(MouseEvent evt, int line, int offset, int dot) {
if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
select(getMarkPosition(),dot);
@@ -2456,35 +2443,32 @@ public class JEditTextArea extends JComponent
}
- private void doDoubleClick(MouseEvent evt, int line,
- int offset, int dot) throws BadLocationException
- {
+ private void doDoubleClick(MouseEvent evt, int line, int offset,
+ int dot) throws BadLocationException {
// Ignore empty lines
- if (getLineLength(line) == 0)
- return;
-
- try {
- int bracket = bracketHelper.findMatchingBracket(document.getText(0, document.getLength()),
- Math.max(0,dot - 1));
- if (bracket != -1) {
- int mark = getMarkPosition();
- // Hack
- if (bracket > mark) {
- bracket++;
- mark--;
+ if (getLineLength(line) != 0) {
+ try {
+ String text = document.getText(0, document.getLength());
+ int bracket = bracketHelper.findMatchingBracket(text, Math.max(0, dot - 1));
+ if (bracket != -1) {
+ int mark = getMarkPosition();
+ // Hack
+ if (bracket > mark) {
+ bracket++;
+ mark--;
+ }
+ select(mark,bracket);
+ return;
}
- select(mark,bracket);
- return;
+ } catch(BadLocationException bl) {
+ bl.printStackTrace();
}
- } catch(BadLocationException bl) {
- bl.printStackTrace();
- }
- setNewSelectionWord( line, offset );
- select(newSelectionStart,newSelectionEnd);
- selectWord = true;
- selectionAncorStart = selectionStart;
- selectionAncorEnd = selectionEnd;
+ setNewSelectionWord( line, offset );
+ select(newSelectionStart,newSelectionEnd);
+ selectWord = true;
+ selectionAncorStart = selectionStart;
+ selectionAncorEnd = selectionEnd;
/*
String lineText = getLineText(line);
@@ -2495,11 +2479,11 @@ public class JEditTextArea extends JComponent
int lineStart = getLineStartOffset(line);
select(lineStart + wordStart,lineStart + wordEnd);
*/
- }
+ }
+ }
- private void doTripleClick(MouseEvent evt, int line,
- int offset, int dot)
- {
+
+ private void doTripleClick(MouseEvent evt, int line, int offset, int dot) {
selectLine = true;
select(getLineStartOffset(line),getLineSelectionStopOffset(line));
selectionAncorStart = selectionStart;
@@ -2507,61 +2491,43 @@ public class JEditTextArea extends JComponent
}
}
- class CaretUndo extends AbstractUndoableEdit
- {
+
+ class CaretUndo extends AbstractUndoableEdit {
private int start;
private int end;
- CaretUndo(int start, int end)
- {
+ CaretUndo(int start, int end) {
this.start = start;
this.end = end;
}
- public boolean isSignificant()
- {
+ public boolean isSignificant() {
return false;
}
- public String getPresentationName()
- {
+ public String getPresentationName() {
return "caret move";
}
- public void undo() throws CannotUndoException
- {
+ public void undo() throws CannotUndoException {
super.undo();
-
select(start,end);
}
- public void redo() throws CannotRedoException
- {
+ public void redo() throws CannotRedoException {
super.redo();
-
select(start,end);
}
- public boolean addEdit(UndoableEdit edit)
- {
- if(edit instanceof CaretUndo)
- {
+ public boolean addEdit(UndoableEdit edit) {
+ if (edit instanceof CaretUndo) {
CaretUndo cedit = (CaretUndo)edit;
start = cedit.start;
end = cedit.end;
cedit.die();
-
return true;
}
- else
- return false;
+ return false;
}
}
-
-// static
-// {
-// caretTimer = new Timer(500, new CaretBlinker());
-// caretTimer.setInitialDelay(500);
-// caretTimer.start();
-// }
}
diff --git a/app/src/processing/app/syntax/KeywordMap.java b/app/src/processing/app/syntax/KeywordMap.java
index b8b66871d..cfa4caa68 100644
--- a/app/src/processing/app/syntax/KeywordMap.java
+++ b/app/src/processing/app/syntax/KeywordMap.java
@@ -76,7 +76,7 @@ public class KeywordMap {
// continue;
// }
if (length == k.keyword.length) {
- if (SyntaxUtilities.regionMatches(ignoreCase, text, offset, k.keyword)) {
+ if (regionMatches(ignoreCase, text, offset, k.keyword)) {
return k.id;
}
}
@@ -84,6 +84,36 @@ public class KeywordMap {
}
return Token.NULL;
}
+
+
+ /**
+ * Checks if a subregion of a Segment is equal to a
+ * character array.
+ * @param ignoreCase True if case should be ignored, false otherwise
+ * @param text The segment
+ * @param offset The offset into the segment
+ * @param match The character array to match
+ */
+ static public boolean regionMatches(boolean ignoreCase, Segment text,
+ int offset, char[] match) {
+ int length = offset + match.length;
+ char[] textArray = text.array;
+ if(length > text.offset + text.count)
+ return false;
+ for(int i = offset, j = 0; i < length; i++, j++)
+ {
+ char c1 = textArray[i];
+ char c2 = match[j];
+ if(ignoreCase)
+ {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ }
+ if(c1 != c2)
+ return false;
+ }
+ return true;
+ }
/**
diff --git a/app/src/processing/app/syntax/PdeKeywords.java b/app/src/processing/app/syntax/PdeKeywords.java
index 9b5ea6838..977d6f4b7 100644
--- a/app/src/processing/app/syntax/PdeKeywords.java
+++ b/app/src/processing/app/syntax/PdeKeywords.java
@@ -38,11 +38,11 @@ public class PdeKeywords extends TokenMarker {
private int lastOffset;
private int lastKeyword;
-
+
/**
- * Add a keyword, and the associated coloring. KEYWORD2 and KEYWORD3
- * should only be used with functions (where parens are present).
+ * Add a keyword, and the associated coloring. KEYWORD2 and KEYWORD3
+ * should only be used with functions (where parens are present).
* This is done for the extra paren handling.
* @param coloring one of KEYWORD1, KEYWORD2, LITERAL1, etc.
*/
@@ -57,7 +57,7 @@ public class PdeKeywords extends TokenMarker {
boolean paren = false;
switch (coloring.charAt(0)) {
case 'K': id = Token.KEYWORD1 + num; break;
- case 'L': id = Token.LITERAL1 + num; break;
+ case 'L': id = Token.LITERAL1 + num; break;
case 'F': id = Token.FUNCTION1 + num; paren = true; break;
}
keywordColoring.add(keyword, (byte) id, paren);
@@ -137,7 +137,10 @@ public class PdeKeywords extends TokenMarker {
lastOffset = lastKeyword = mlength;
break loop;
}
- i++; // http://processing.org/bugs/bugzilla/609.html [jdf]
+ // https://github.com/processing/processing/issues/1681
+ if (array[i1] != ' ') {
+ i++; // http://processing.org/bugs/bugzilla/609.html [jdf]
+ }
}
break;
default:
@@ -216,24 +219,24 @@ public class PdeKeywords extends TokenMarker {
}
return token;
}
-
-
+
+
private boolean doKeyword(Segment line, int i, char c) {
// return doKeyword(line, i, false);
// }
-//
-//
+//
+//
// //private boolean doKeyword(Segment line, int i, char c) {
// private boolean doKeyword(Segment line, int i, boolean paren) {
int i1 = i + 1;
int len = i - lastKeyword;
-
+
boolean paren = Editor.checkParen(line.array, i, line.array.length);
// String s = new String(line.array, lastKeyword, len);
// if (s.equals("mousePressed")) {
// System.out.println("found mousePressed" + (paren ? "()" : ""));
// //new Exception().printStackTrace(System.out);
-//// System.out.println(" " + i + " " + line.count + " " +
+//// System.out.println(" " + i + " " + line.count + " " +
//// //new String(line.array, line.offset + i, line.offset + line.count - i));
//// new String(line.array, i, line.array.length - i));
// }
diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java
index 16ba8a876..33427f864 100644
--- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java
+++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java
@@ -180,7 +180,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
document = new SyntaxDocument();
- editable = true;
+// editable = true;
// Set to 0 for revision 0215 because it causes strange jumps
// http://code.google.com/p/processing/issues/detail?id=1055
@@ -194,8 +194,16 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
// http://code.google.com/p/processing/issues/detail?id=1275
rows = 5;
- font = Preferences.getFont("editor.font");
+ /*
+ String fontFamily = Preferences.get("editor.font.family");
+ int fontSize = Preferences.getInteger("editor.font.size");
+ plainFont = new Font(fontFamily, Font.PLAIN, fontSize);
+ boldFont = new Font(fontFamily, Font.BOLD, fontSize);
antialias = Preferences.getBoolean("editor.antialias");
+ */
+
+ fgcolor = mode.getColor("editor.fgcolor");
+ bgcolor = mode.getColor("editor.bgcolor");
styles = new SyntaxStyle[Token.ID_COUNT];
@@ -222,9 +230,6 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
// area that's not in use by the text (replaced with tildes)
styles[Token.INVALID] = mode.getStyle("invalid");
- fgcolor = mode.getColor("editor.fgcolor");
- bgcolor = mode.getColor("editor.bgcolor");
-
caretColor = mode.getColor("editor.caret.color");
selectionColor = mode.getColor("editor.selection.color");
lineHighlight = mode.getBoolean("editor.linehighlight");
diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java
index 674bbdc78..9415a4bf0 100644
--- a/app/src/processing/app/syntax/SyntaxStyle.java
+++ b/app/src/processing/app/syntax/SyntaxStyle.java
@@ -9,191 +9,179 @@
package processing.app.syntax;
-import java.awt.*;
-import javax.swing.JComponent;
-
-import processing.app.Preferences;
+import java.awt.Color;
/**
- * A simple text style class. It can specify the color, italic flag,
- * and bold flag of a run of text.
+ * A simple text style class.
+ * It can specify the color and bold flag of a run of text.
* @author Slava Pestov
* @version $Id$
*/
-public class SyntaxStyle
-{
+public class SyntaxStyle {
+ private Color color;
+// private boolean italic;
+ private boolean bold;
+// private Font lastFont;
+// private Font lastStyledFont;
+// private FontMetrics fontMetrics;
+
+
/**
* Creates a new SyntaxStyle.
* @param color The text color
* @param italic True if the text should be italics
* @param bold True if the text should be bold
*/
- public SyntaxStyle(Color color, boolean italic, boolean bold)
- {
+// public SyntaxStyle(Color color, boolean italic, boolean bold) {
+ public SyntaxStyle(Color color, boolean bold) {
this.color = color;
- this.italic = italic;
+// this.italic = italic;
this.bold = bold;
}
- /**
- * Returns the color specified in this style.
- */
- public Color getColor()
- {
+
+ /** Returns the color specified in this style. */
+ public Color getColor() {
return color;
}
- /**
- * Returns true if no font styles are enabled.
- */
- public boolean isPlain()
- {
- return !(bold || italic);
- }
+
+// /**
+// * Returns true if no font styles are enabled.
+// */
+// public boolean isPlain() {
+// return !(bold || italic);
+// }
- /**
- * Returns true if italics is enabled for this style.
- */
- public boolean isItalic()
- {
- return italic;
- }
+// /**
+// * Returns true if italics is enabled for this style.
+// */
+// public boolean isItalic() {
+// return italic;
+// }
- /**
- * Returns true if boldface is enabled for this style.
- */
- public boolean isBold()
- {
+
+ /** Returns true if boldface is enabled for this style. */
+ public boolean isBold() {
return bold;
}
- /**
- * Returns the specified font, but with the style's bold and
- * italic flags applied.
- */
- public Font getStyledFont(Font font)
- {
- if(font == null)
- throw new NullPointerException("font param must not"
- + " be null");
- if(font.equals(lastFont))
- return lastStyledFont;
- lastFont = font;
-// lastStyledFont = new Font(font.getFamily(),
-// (bold ? Font.BOLD : 0)
-// | (italic ? Font.ITALIC : 0),
-// font.getSize());
- lastStyledFont =
- findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize());
- return lastStyledFont;
- }
-
- /**
- * Returns the font metrics for the styled font.
- */
- public FontMetrics getFontMetrics(Font font, JComponent comp) {
- if (font == null) {
- throw new NullPointerException("font param must not be null");
- }
- if (font.equals(lastFont) && fontMetrics != null) {
- return fontMetrics;
- }
- lastFont = font;
-// lastStyledFont = new Font(font.getFamily(),
-// (bold ? Font.BOLD : 0)
-// | (italic ? Font.ITALIC : 0),
-// font.getSize());
- lastStyledFont =
- findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize());
-
- //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont);
- fontMetrics = comp.getFontMetrics(lastStyledFont);
- return fontMetrics;
- }
-
- /*
- on Windows (and I presume Linux) we get something like this:
-
- mono family Source Code Pro
- mono fontname Source Code Pro
- mono name Source Code Pro
- mono psname SourceCodePro-Regular
-
- mono family Source Code Pro Semibold
- mono fontname Source Code Pro Semibold
- mono name Source Code Pro Semibold
- mono psname SourceCodePro-Semibold
-
- ...which means that 'family' is not a usable method.
- */
- //private String monoFontFamily;
-
- private Font findFont(String familyName, int style, int size) {
- // getFamily() is too unreliable across platforms
- if (Preferences.get("editor.font").startsWith("processing.mono")) {
- return processing.app.Toolkit.getMonoFont(size, style);
- } else {
- return new Font(familyName, style, size);
- }
- /*
- if (monoFontFamily == null) {
- // This should be more reliable across platforms than the
- // family name, which only seems to work correctly on OS X.
- // (Or perhaps only when it's installed locally.)
- String psName =
- processing.app.Toolkit.getMonoFont(size, style).getPSName();
- int dash = psName.indexOf('-');
- monoFontFamily = psName.substring(0, dash);
-
- // Just get the font family name for comparison
- //monoFontFamily =
- //processing.app.Toolkit.getMonoFont(size, style).getFamily();
- //processing.app.Toolkit.getMonoFont(size, style).getFamily();
- Font mono = processing.app.Toolkit.getMonoFont(size, style);
- System.out.println("mono family " + mono.getFamily());
- System.out.println("mono fontname " + mono.getFontName());
- System.out.println("mono name " + mono.getName());
- System.out.println("mono psname " + mono.getPSName());
- }
- if (familyName.equals(monoFontFamily)) {
- System.out.println("getting style bold? " + (style == Font.BOLD));
- return processing.app.Toolkit.getMonoFont(size, style);
- } else {
- //System.out.println("name is " + name + " mono name is " + monoFontName + " " + style);
- return new Font(familyName, style, size);
- }
- */
- }
-
- /**
- * Sets the foreground color and font of the specified graphics
- * context to that specified in this style.
- * @param gfx The graphics context
- * @param font The font to add the styles to
- */
- public void setGraphicsFlags(Graphics gfx, Font font)
- {
- Font _font = getStyledFont(font);
- gfx.setFont(_font);
- gfx.setColor(color);
- }
+
+// /**
+// * Returns the specified font, but with the style's bold flags applied.
+// */
+// public Font getStyledFont(Font font) {
+// if (font.equals(lastFont)) {
+// return lastStyledFont;
+// }
+// lastFont = font;
+// lastStyledFont =
+// findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize());
+// return lastStyledFont;
+// }
+//
+//
+// /**
+// * Returns the font metrics for the styled font.
+// */
+// public FontMetrics getFontMetrics(Font font, JComponent comp) {
+//// if (font == null) {
+//// throw new NullPointerException("font param must not be null");
+//// }
+// if (font.equals(lastFont) && fontMetrics != null) {
+// return fontMetrics;
+// }
+// lastFont = font;
+//// lastStyledFont = new Font(font.getFamily(),
+//// (bold ? Font.BOLD : 0)
+//// | (italic ? Font.ITALIC : 0),
+//// font.getSize());
+// lastStyledFont =
+// findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize());
+//
+// //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont);
+// fontMetrics = comp.getFontMetrics(lastStyledFont);
+// return fontMetrics;
+// }
+//
+//
+// /*
+// on Windows (and I presume Linux) we get something like this:
+//
+// mono family Source Code Pro
+// mono fontname Source Code Pro
+// mono name Source Code Pro
+// mono psname SourceCodePro-Regular
+//
+// mono family Source Code Pro Semibold
+// mono fontname Source Code Pro Semibold
+// mono name Source Code Pro Semibold
+// mono psname SourceCodePro-Semibold
+//
+// ...which means that 'family' is not a usable method.
+// */
+// //private String monoFontFamily;
+//
+// private Font findFont(String familyName, int style, int size) {
+//// // getFamily() is too unreliable across platforms
+//// if (Preferences.get("editor.font").startsWith("processing.mono")) {
+//// return processing.app.Toolkit.getMonoFont(size, style);
+//// } else {
+// System.out.println("creating new font for " + familyName);
+// return new Font(familyName, style, size);
+//// }
+//
+// /*
+// if (monoFontFamily == null) {
+// // This should be more reliable across platforms than the
+// // family name, which only seems to work correctly on OS X.
+// // (Or perhaps only when it's installed locally.)
+// String psName =
+// processing.app.Toolkit.getMonoFont(size, style).getPSName();
+// int dash = psName.indexOf('-');
+// monoFontFamily = psName.substring(0, dash);
+//
+// // Just get the font family name for comparison
+// //monoFontFamily =
+// //processing.app.Toolkit.getMonoFont(size, style).getFamily();
+// //processing.app.Toolkit.getMonoFont(size, style).getFamily();
+// Font mono = processing.app.Toolkit.getMonoFont(size, style);
+// System.out.println("mono family " + mono.getFamily());
+// System.out.println("mono fontname " + mono.getFontName());
+// System.out.println("mono name " + mono.getName());
+// System.out.println("mono psname " + mono.getPSName());
+// }
+// if (familyName.equals(monoFontFamily)) {
+// System.out.println("getting style bold? " + (style == Font.BOLD));
+// return processing.app.Toolkit.getMonoFont(size, style);
+// } else {
+// //System.out.println("name is " + name + " mono name is " + monoFontName + " " + style);
+// return new Font(familyName, style, size);
+// }
+// */
+// }
+//
+//
+// /**
+// * Sets the foreground color and font of the specified graphics
+// * context to that specified in this style.
+// * @param gfx The graphics context
+// * @param font The font to add the styles to
+// */
+// public void setGraphicsFlags(Graphics gfx, Font font) {
+// Font _font = getStyledFont(font);
+// gfx.setFont(_font);
+// gfx.setColor(color);
+// }
+
/**
* Returns a string representation of this object.
*/
- public String toString()
- {
+ public String toString() {
return getClass().getName() + "[color=" + color +
- (italic ? ",italic" : "") +
+// (italic ? ",italic" : "") +
(bold ? ",bold" : "") + "]";
}
-
- // private members
- private Color color;
- private boolean italic;
- private boolean bold;
- private Font lastFont;
- private Font lastStyledFont;
- private FontMetrics fontMetrics;
}
diff --git a/app/src/processing/app/syntax/SyntaxUtilities.java b/app/src/processing/app/syntax/SyntaxUtilities.java
deleted file mode 100644
index 1e40ac831..000000000
--- a/app/src/processing/app/syntax/SyntaxUtilities.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * SyntaxUtilities.java - Utility functions used by syntax colorizing
- * Copyright (C) 1999 Slava Pestov
- *
- * You may use and modify this package for any purpose. Redistribution is
- * permitted, in both source and binary form, provided that this notice
- * remains intact in all source distributions of this package.
- */
-
-package processing.app.syntax;
-
-import javax.swing.text.*;
-import java.awt.*;
-
-
-/**
- * Class with several utility functions used by jEdit's syntax colorizing
- * subsystem.
- *
- * @author Slava Pestov
- * @version $Id$
- */
-public class SyntaxUtilities {
-
- /**
- * Checks if a subregion of a Segment is equal to a
- * string.
- * @param ignoreCase True if case should be ignored, false otherwise
- * @param text The segment
- * @param offset The offset into the segment
- * @param match The string to match
- */
- public static boolean regionMatches(boolean ignoreCase, Segment text,
- int offset, String match) {
- int length = offset + match.length();
- char[] textArray = text.array;
- if(length > text.offset + text.count)
- return false;
- for(int i = offset, j = 0; i < length; i++, j++)
- {
- char c1 = textArray[i];
- char c2 = match.charAt(j);
- if(ignoreCase)
- {
- c1 = Character.toUpperCase(c1);
- c2 = Character.toUpperCase(c2);
- }
- if(c1 != c2)
- return false;
- }
- return true;
- }
-
-
- /**
- * Checks if a subregion of a Segment is equal to a
- * character array.
- * @param ignoreCase True if case should be ignored, false otherwise
- * @param text The segment
- * @param offset The offset into the segment
- * @param match The character array to match
- */
- public static boolean regionMatches(boolean ignoreCase, Segment text,
- int offset, char[] match) {
- int length = offset + match.length;
- char[] textArray = text.array;
- if(length > text.offset + text.count)
- return false;
- for(int i = offset, j = 0; i < length; i++, j++)
- {
- char c1 = textArray[i];
- char c2 = match[j];
- if(ignoreCase)
- {
- c1 = Character.toUpperCase(c1);
- c2 = Character.toUpperCase(c2);
- }
- if(c1 != c2)
- return false;
- }
- return true;
- }
-
-
-// /**
-// * Returns the default style table. This can be passed to the
-// * setStyles() method of SyntaxDocument
-// * to use the default syntax styles.
-// */
-// public static SyntaxStyle[] getDefaultSyntaxStyles() {
-// SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
-//
-// styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false);
-// styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false);
-// styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
-// styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false);
-// styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
-// styles[Token.FUNCTION1] = new SyntaxStyle(Color.magenta,false,false);
-// styles[Token.FUNCTION2] = new SyntaxStyle(new Color(0x009600),false,false);
-// styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
-// styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
-// styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
-// styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
-// styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
-//
-// return styles;
-// }
-
-
- /**
- * Paints the specified line onto the graphics context. Note that this
- * method munges the offset and count values of the segment.
- * @param line The line segment
- * @param tokens The token list for the line
- * @param styles The syntax style list
- * @param expander The tab expander used to determine tab stops. May
- * be null
- * @param gfx The graphics context
- * @param x The x co-ordinate
- * @param y The y co-ordinate
- * @return The x co-ordinate, plus the width of the painted string
- */
- public static int paintSyntaxLine(Segment line, Token tokens,
- SyntaxStyle[] styles,
- TabExpander expander, Graphics gfx,
- int x, int y) {
- Font defaultFont = gfx.getFont();
- Color defaultColor = gfx.getColor();
-
- for (;;) {
- byte id = tokens.id;
- if(id == Token.END)
- break;
-
- int length = tokens.length;
- if (id == Token.NULL) {
- if(!defaultColor.equals(gfx.getColor()))
- gfx.setColor(defaultColor);
- if(!defaultFont.equals(gfx.getFont()))
- gfx.setFont(defaultFont);
- } else {
- styles[id].setGraphicsFlags(gfx,defaultFont);
- }
- line.count = length;
- x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
- line.offset += length;
-
- tokens = tokens.next;
- }
-
- return x;
- }
-
- // private members
- private SyntaxUtilities() {}
-}
diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java
index 9401c4e32..1c9edb7cd 100644
--- a/app/src/processing/app/syntax/TextAreaDefaults.java
+++ b/app/src/processing/app/syntax/TextAreaDefaults.java
@@ -20,15 +20,17 @@ import java.awt.*;
public class TextAreaDefaults {
public InputHandler inputHandler;
public SyntaxDocument document;
- public boolean editable;
+// public boolean editable;
public boolean caretVisible;
public boolean caretBlinks;
public boolean blockCaret;
public int electricScroll;
+ // default/preferred number of rows/cols
public int cols;
public int rows;
+
public SyntaxStyle[] styles;
public Color caretColor;
public Color selectionColor;
@@ -40,9 +42,11 @@ public class TextAreaDefaults {
public boolean eolMarkers;
public boolean paintInvalid;
- // moved from TextAreaPainter [fry]
- public Font font;
+ /*
+ public Font plainFont;
+ public Font boldFont;
+ public boolean antialias;
+ */
public Color fgcolor;
public Color bgcolor;
- public boolean antialias;
}
diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java
index 4f23686ce..d1679ddaa 100644
--- a/app/src/processing/app/syntax/TextAreaPainter.java
+++ b/app/src/processing/app/syntax/TextAreaPainter.java
@@ -10,14 +10,16 @@
*/
package processing.app.syntax;
-import processing.app.syntax.im.CompositionTextPainter;
+import java.awt.event.MouseEvent;
+import java.awt.*;
+import java.awt.print.*;
import javax.swing.ToolTipManager;
import javax.swing.text.*;
import javax.swing.JComponent;
-import java.awt.event.MouseEvent;
-import java.awt.*;
-import java.awt.print.*;
+
+import processing.app.Preferences;
+import processing.app.syntax.im.CompositionTextPainter;
/**
@@ -25,25 +27,56 @@ import java.awt.print.*;
* lines of text.
* @author Slava Pestov
*/
-public class TextAreaPainter extends JComponent
-implements TabExpander, Printable {
+public class TextAreaPainter extends JComponent implements TabExpander {
/** True if inside printing, will handle disabling the highlight */
boolean printing;
- /** Current setting for editor.antialias preference */
- boolean antialias;
/** A specific painter composed by the InputMethod.*/
protected CompositionTextPainter compositionTextPainter;
+ protected JEditTextArea textArea;
+ protected TextAreaDefaults defaults;
+
+// protected boolean blockCaret;
+// protected SyntaxStyle[] styles;
+// protected Color caretColor;
+// protected Color selectionColor;
+// protected Color lineHighlightColor;
+// protected boolean lineHighlight;
+// protected Color bracketHighlightColor;
+// protected boolean bracketHighlight;
+// protected Color eolMarkerColor;
+// protected boolean eolMarkers;
+
+// protected int cols;
+// protected int rows;
+
+ // moved from TextAreaDefaults
+ private Font plainFont;
+ private Font boldFont;
+ private boolean antialias;
+// private Color fgcolor;
+// private Color bgcolor;
+
+ protected int tabSize;
+ protected FontMetrics fm;
+
+ protected Highlight highlights;
+
+ int currentLineIndex;
+ Token currentLineTokens;
+ Segment currentLine;
+
/**
* Creates a new repaint manager. This should be not be called directly.
*/
public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults) {
this.textArea = textArea;
+ this.defaults = defaults;
setAutoscrolls(true);
- setDoubleBuffered(true);
+// setDoubleBuffered(true);
setOpaque(true);
ToolTipManager.sharedInstance().registerComponent(this);
@@ -53,28 +86,61 @@ implements TabExpander, Printable {
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
- // unfortunately probably can't just do setDefaults() since things aren't quite set up
- setFont(defaults.font);
- setForeground(defaults.fgcolor);
- setBackground(defaults.bgcolor);
+// // unfortunately probably can't just do setDefaults() since things aren't quite set up
+// setFont(defaults.plainFont);
+//// System.out.println("defaults font is " + defaults.font);
+// setForeground(defaults.fgcolor);
+// setBackground(defaults.bgcolor);
+ updateAppearance();
- blockCaret = defaults.blockCaret;
- styles = defaults.styles;
- caretColor = defaults.caretColor;
- selectionColor = defaults.selectionColor;
- lineHighlightColor = defaults.lineHighlightColor;
- lineHighlight = defaults.lineHighlight;
- bracketHighlightColor = defaults.bracketHighlightColor;
- bracketHighlight = defaults.bracketHighlight;
- eolMarkerColor = defaults.eolMarkerColor;
- eolMarkers = defaults.eolMarkers;
- antialias = defaults.antialias;
+// blockCaret = defaults.blockCaret;
+// styles = defaults.styles;
+// caretColor = defaults.caretColor;
+// selectionColor = defaults.selectionColor;
+// lineHighlightColor = defaults.lineHighlightColor;
+// lineHighlight = defaults.lineHighlight;
+// bracketHighlightColor = defaults.bracketHighlightColor;
+// bracketHighlight = defaults.bracketHighlight;
+// eolMarkerColor = defaults.eolMarkerColor;
+// eolMarkers = defaults.eolMarkers;
+// antialias = defaults.antialias;
- cols = defaults.cols;
- rows = defaults.rows;
+// cols = defaults.cols;
+// rows = defaults.rows;
}
+ public void updateAppearance() {
+// // unfortunately probably can't just do setDefaults() since things aren't quite set up
+// setFont(defaults.plainFont);
+//// System.out.println("defaults font is " + defaults.font);
+ setForeground(defaults.fgcolor);
+ setBackground(defaults.bgcolor);
+
+ String fontFamily = Preferences.get("editor.font.family");
+ int fontSize = Preferences.getInteger("editor.font.size");
+ plainFont = new Font(fontFamily, Font.PLAIN, fontSize);
+ if (!fontFamily.equals(plainFont.getFamily())) {
+ System.err.println(fontFamily + " not available, resetting to monospaced");
+ fontFamily = "Monospaced";
+ Preferences.set("editor.font.family", fontFamily);
+ plainFont = new Font(fontFamily, Font.PLAIN, fontSize);
+ }
+ boldFont = new Font(fontFamily, Font.BOLD, fontSize);
+ antialias = Preferences.getBoolean("editor.smooth");
+// System.out.println(plainFont.getFamily());
+// System.out.println(plainFont);
+
+ // moved from setFont() override (never quite comfortable w/ that override)
+ fm = super.getFontMetrics(plainFont);
+ textArea.recalculateVisibleLines();
+
+// fgcolor = mode.getColor("editor.fgcolor");
+// bgcolor = mode.getColor("editor.bgcolor");
+ }
+
+
+ /*
public void setDefaults(TextAreaDefaults defaults) {
setFont(defaults.font);
setForeground(defaults.fgcolor);
@@ -96,12 +162,13 @@ implements TabExpander, Printable {
cols = defaults.cols;
rows = defaults.rows;
}
+ */
/**
- * Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
+ * Get CompositionTextPainter, creating one if it doesn't exist.
*/
- public CompositionTextPainter getCompositionTextpainter(){
+ public CompositionTextPainter getCompositionTextpainter() {
if (compositionTextPainter == null){
compositionTextPainter = new CompositionTextPainter(textArea);
}
@@ -115,81 +182,82 @@ implements TabExpander, Printable {
* @see processing.app.syntax.Token
*/
public final SyntaxStyle[] getStyles() {
- return styles;
+ return defaults.styles;
}
- /**
- * Sets the syntax styles used to paint colorized text. Entry n
- * will be used to paint tokens with id = n.
- * @param styles The syntax styles
- * @see processing.app.syntax.Token
- */
- public final void setStyles(SyntaxStyle[] styles) {
- this.styles = styles;
- repaint();
- }
+// /**
+// * Sets the syntax styles used to paint colorized text. Entry n
+// * will be used to paint tokens with id = n.
+// * @param styles The syntax styles
+// * @see processing.app.syntax.Token
+// */
+// public final void setStyles(SyntaxStyle[] styles) {
+// this.styles = styles;
+// repaint();
+// }
- /**
- * Returns the caret color.
- */
- public final Color getCaretColor() {
- return caretColor;
- }
+// /**
+// * Returns the caret color.
+// */
+// public final Color getCaretColor() {
+// return caretColor;
+// }
- /**
- * Sets the caret color.
- * @param caretColor The caret color
- */
- public final void setCaretColor(Color caretColor) {
- this.caretColor = caretColor;
- invalidateSelectedLines();
- }
-
- /**
- * Returns the selection color.
- */
- public final Color getSelectionColor() {
- return selectionColor;
- }
+// /**
+// * Sets the caret color.
+// * @param caretColor The caret color
+// */
+// public final void setCaretColor(Color caretColor) {
+// this.caretColor = caretColor;
+// invalidateSelectedLines();
+// }
- /**
- * Sets the selection color.
- * @param selectionColor The selection color
- */
- public final void setSelectionColor(Color selectionColor) {
- this.selectionColor = selectionColor;
- invalidateSelectedLines();
- }
-
-
- /**
- * Returns the line highlight color.
- */
- public final Color getLineHighlightColor() {
- return lineHighlightColor;
- }
+// /**
+// * Returns the selection color.
+// */
+// public final Color getSelectionColor() {
+// return selectionColor;
+// }
- /**
- * Sets the line highlight color.
- * @param lineHighlightColor The line highlight color
- */
- public final void setLineHighlightColor(Color lineHighlightColor) {
- this.lineHighlightColor = lineHighlightColor;
- invalidateSelectedLines();
- }
+// /**
+// * Sets the selection color.
+// * @param selectionColor The selection color
+// */
+// public final void setSelectionColor(Color selectionColor) {
+// this.selectionColor = selectionColor;
+// invalidateSelectedLines();
+// }
- /**
- * Returns true if line highlight is enabled, false otherwise.
- */
- public final boolean isLineHighlightEnabled() {
- return lineHighlight;
- }
+// /**
+// * Returns the line highlight color.
+// */
+// public final Color getLineHighlightColor() {
+// return lineHighlightColor;
+// }
+
+
+// /**
+// * Sets the line highlight color.
+// * @param lineHighlightColor The line highlight color
+// */
+// public final void setLineHighlightColor(Color lineHighlightColor) {
+// this.lineHighlightColor = lineHighlightColor;
+// invalidateSelectedLines();
+// }
+
+
+// /**
+// * Returns true if line highlight is enabled, false otherwise.
+// */
+// public final boolean isLineHighlightEnabled() {
+// return lineHighlight;
+// }
/**
@@ -198,28 +266,29 @@ implements TabExpander, Printable {
* should be enabled, false otherwise
*/
public final void setLineHighlightEnabled(boolean lineHighlight) {
- this.lineHighlight = lineHighlight;
+// this.lineHighlight = lineHighlight;
+ defaults.lineHighlight = lineHighlight;
invalidateSelectedLines();
}
- /**
- * Returns the bracket highlight color.
- */
- public final Color getBracketHighlightColor() {
- return bracketHighlightColor;
- }
+// /**
+// * Returns the bracket highlight color.
+// */
+// public final Color getBracketHighlightColor() {
+// return bracketHighlightColor;
+// }
- /**
- * Sets the bracket highlight color.
- * @param bracketHighlightColor The bracket highlight color
- */
- public final void setBracketHighlightColor(Color bracketHighlightColor)
- {
- this.bracketHighlightColor = bracketHighlightColor;
- invalidateLine(textArea.getBracketLine());
- }
+// /**
+// * Sets the bracket highlight color.
+// * @param bracketHighlightColor The bracket highlight color
+// */
+// public final void setBracketHighlightColor(Color bracketHighlightColor) {
+// this.bracketHighlightColor = bracketHighlightColor;
+// invalidateLine(textArea.getBracketLine());
+// }
+
/**
* Returns true if bracket highlighting is enabled, false otherwise.
@@ -227,91 +296,92 @@ implements TabExpander, Printable {
* one before the caret (if any) is highlighted.
*/
public final boolean isBracketHighlightEnabled() {
- return bracketHighlight;
+// return bracketHighlight;
+ return defaults.bracketHighlight;
}
- /**
- * Enables or disables bracket highlighting.
- * When bracket highlighting is enabled, the bracket matching the
- * one before the caret (if any) is highlighted.
- * @param bracketHighlight True if bracket highlighting should be
- * enabled, false otherwise
- */
- public final void setBracketHighlightEnabled(boolean bracketHighlight) {
- this.bracketHighlight = bracketHighlight;
- invalidateLine(textArea.getBracketLine());
- }
+// /**
+// * Enables or disables bracket highlighting.
+// * When bracket highlighting is enabled, the bracket matching the
+// * one before the caret (if any) is highlighted.
+// * @param bracketHighlight True if bracket highlighting should be
+// * enabled, false otherwise
+// */
+// public final void setBracketHighlightEnabled(boolean bracketHighlight) {
+// this.bracketHighlight = bracketHighlight;
+// invalidateLine(textArea.getBracketLine());
+// }
/**
* Returns true if the caret should be drawn as a block, false otherwise.
*/
public final boolean isBlockCaretEnabled() {
- return blockCaret;
+ return defaults.blockCaret;
}
- /**
- * Sets if the caret should be drawn as a block, false otherwise.
- * @param blockCaret True if the caret should be drawn as a block,
- * false otherwise.
- */
- public final void setBlockCaretEnabled(boolean blockCaret) {
- this.blockCaret = blockCaret;
- invalidateSelectedLines();
- }
+// /**
+// * Sets if the caret should be drawn as a block, false otherwise.
+// * @param blockCaret True if the caret should be drawn as a block,
+// * false otherwise.
+// */
+// public final void setBlockCaretEnabled(boolean blockCaret) {
+// this.blockCaret = blockCaret;
+// invalidateSelectedLines();
+// }
- /**
- * Returns the EOL marker color.
- */
- public final Color getEOLMarkerColor() {
- return eolMarkerColor;
- }
+// /**
+// * Returns the EOL marker color.
+// */
+// public final Color getEOLMarkerColor() {
+// return eolMarkerColor;
+// }
- /**
- * Sets the EOL marker color.
- * @param eolMarkerColor The EOL marker color
- */
- public final void setEOLMarkerColor(Color eolMarkerColor) {
- this.eolMarkerColor = eolMarkerColor;
- repaint();
- }
+// /**
+// * Sets the EOL marker color.
+// * @param eolMarkerColor The EOL marker color
+// */
+// public final void setEOLMarkerColor(Color eolMarkerColor) {
+// this.eolMarkerColor = eolMarkerColor;
+// repaint();
+// }
- /**
- * Returns true if EOL markers are drawn, false otherwise.
- */
- public final boolean getEOLMarkersPainted() {
- return eolMarkers;
- }
+// /**
+// * Returns true if EOL markers are drawn, false otherwise.
+// */
+// public final boolean getEOLMarkersPainted() {
+// return eolMarkers;
+// }
- /**
- * Sets if EOL markers are to be drawn.
- * @param eolMarkers True if EOL markers should be drawn, false otherwise
- */
- public final void setEOLMarkersPainted(boolean eolMarkers) {
- this.eolMarkers = eolMarkers;
- repaint();
- }
+// /**
+// * Sets if EOL markers are to be drawn.
+// * @param eolMarkers True if EOL markers should be drawn, false otherwise
+// */
+// public final void setEOLMarkersPainted(boolean eolMarkers) {
+// this.eolMarkers = eolMarkers;
+// repaint();
+// }
- public final void setAntialias(boolean antialias) {
- this.antialias = antialias;
- }
+// public final void setAntialias(boolean antialias) {
+// this.antialias = antialias;
+// }
- /**
- * Adds a custom highlight painter.
- * @param highlight The highlight
- */
- public void addCustomHighlight(Highlight highlight) {
- highlight.init(textArea,highlights);
- highlights = highlight;
- }
+// /**
+// * Adds a custom highlight painter.
+// * @param highlight The highlight
+// */
+// public void addCustomHighlight(Highlight highlight) {
+// highlight.init(textArea,highlights);
+// highlights = highlight;
+// }
/**
@@ -345,35 +415,41 @@ implements TabExpander, Printable {
}
- /**
- * Returns the tool tip to display at the specified location.
- * @param evt The mouse event
- */
- public String getToolTipText(MouseEvent evt) {
- return (highlights == null) ? null : highlights.getToolTipText(evt);
- }
+// /**
+// * Returns the tool tip to display at the specified location.
+// * @param evt The mouse event
+// */
+// public String getToolTipText(MouseEvent evt) {
+// return (highlights == null) ? null : highlights.getToolTipText(evt);
+// }
- /**
- * Returns the font metrics used by this component.
- */
+ /** Returns the font metrics used by this component. */
public FontMetrics getFontMetrics() {
return fm;
}
-
- /**
- * Sets the font for this component. This is overridden to update the
- * cached font metrics and to recalculate which lines are visible.
- * @param font The font
- */
- public void setFont(Font font) {
- super.setFont(font);
- fm = super.getFontMetrics(font);
- textArea.recalculateVisibleLines();
+
+ public FontMetrics getFontMetrics(SyntaxStyle style) {
+// return getFontMetrics(style.isBold() ?
+// defaults.boldFont : defaults.plainFont);
+ return getFontMetrics(style.isBold() ? boldFont : plainFont);
}
+// /**
+// * Sets the font for this component. This is overridden to update the
+// * cached font metrics and to recalculate which lines are visible.
+// * @param font The font
+// */
+// public void setFont(Font font) {
+//// new Exception().printStackTrace(System.out);
+// super.setFont(font);
+// fm = super.getFontMetrics(font);
+// textArea.recalculateVisibleLines();
+// }
+
+
/**
* Repaints the text.
* @param gfx The graphics context
@@ -385,12 +461,16 @@ implements TabExpander, Printable {
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ // no effect, one way or the other
+// g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+// RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
Rectangle clipRect = gfx.getClipBounds();
gfx.setColor(getBackground());
- gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
+ gfx.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
// We don't use yToLine() here because that method doesn't
// return lines past the end of the document
@@ -407,44 +487,50 @@ implements TabExpander, Printable {
int x = textArea.getHorizontalOffset();
for (int line = firstInvalid; line <= lastInvalid; line++) {
- paintLine(gfx,tokenMarker,line,x);
+ paintLine(gfx, line, x, tokenMarker);
}
if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
int h = clipRect.y + clipRect.height;
- repaint(0,h,getWidth(),getHeight() - h);
+ repaint(0, h, getWidth(), getHeight() - h);
}
} catch (Exception e) {
- System.err.println("Error repainting line"
- + " range {" + firstInvalid + ","
- + lastInvalid + "}:");
+ System.err.println("Error repainting line" +
+ " range {" + firstInvalid + "," + lastInvalid + "}:");
e.printStackTrace();
}
}
- public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
- int lineHeight = fm.getHeight();
- int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
- int lineCount = textArea.getLineCount();
- int lastPage = lineCount / linesPerPage;
+ public Printable getPrintable() {
+ return new Printable() {
+
+ @Override
+ public int print(Graphics graphics, PageFormat pageFormat,
+ int pageIndex) throws PrinterException {
+ int lineHeight = fm.getHeight();
+ int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
+ int lineCount = textArea.getLineCount();
+ int lastPage = lineCount / linesPerPage;
- if (pageIndex > lastPage) {
- return NO_SUCH_PAGE;
+ if (pageIndex > lastPage) {
+ return NO_SUCH_PAGE;
- } else {
- Graphics2D g2d = (Graphics2D)g;
- TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
- int firstLine = pageIndex*linesPerPage;
- g2d.translate(Math.max(54, pageFormat.getImageableX()),
- pageFormat.getImageableY() - firstLine*lineHeight);
- printing = true;
- for (int line = firstLine; line < firstLine + linesPerPage; line++) {
- paintLine(g2d, tokenMarker, line, 0);
+ } else {
+ Graphics2D g2 = (Graphics2D) graphics;
+ TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
+ int firstLine = pageIndex*linesPerPage;
+ g2.translate(Math.max(54, pageFormat.getImageableX()),
+ pageFormat.getImageableY() - firstLine*lineHeight);
+ printing = true;
+ for (int line = firstLine; line < firstLine + linesPerPage; line++) {
+ paintLine(g2, line, 0, tokenMarker);
+ }
+ printing = false;
+ return PAGE_EXISTS;
+ }
}
- printing = false;
- return PAGE_EXISTS;
- }
+ };
}
@@ -452,9 +538,9 @@ implements TabExpander, Printable {
* Marks a line as needing a repaint.
* @param line The line to invalidate
*/
- public final void invalidateLine(int line) {
- repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
- getWidth(),fm.getHeight());
+ final public void invalidateLine(int line) {
+ repaint(0, textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
+ getWidth(), fm.getHeight());
}
@@ -463,57 +549,41 @@ implements TabExpander, Printable {
* @param firstLine The first line to invalidate
* @param lastLine The last line to invalidate
*/
- public final void invalidateLineRange(int firstLine, int lastLine) {
+ final void invalidateLineRange(int firstLine, int lastLine) {
repaint(0,textArea.lineToY(firstLine) +
fm.getMaxDescent() + fm.getLeading(),
getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
}
- /**
- * Repaints the lines containing the selection.
- */
- public final void invalidateSelectedLines() {
+ /** Repaints the lines containing the selection. */
+ final void invalidateSelectedLines() {
invalidateLineRange(textArea.getSelectionStartLine(),
textArea.getSelectionStopLine());
}
- /**
- * Implementation of TabExpander interface. Returns next tab stop after
- * a specified point.
- * @param x The x co-ordinate
- * @param tabOffset Ignored
- * @return The next tab stop after x
- */
+ /** Returns next tab stop after a specified point. */
+// TabExpander tabExpander = new TabExpander() {
+ @Override
public float nextTabStop(float x, int tabOffset) {
int offset = textArea.getHorizontalOffset();
int ntabs = ((int)x - offset) / tabSize;
return (ntabs + 1) * tabSize + offset;
}
+// };
+
- /**
- * Returns the painter's preferred size.
- */
public Dimension getPreferredSize() {
- Dimension dim = new Dimension();
- dim.width = fm.charWidth('w') * cols;
- dim.height = fm.getHeight() * rows;
- return dim;
+ return new Dimension(fm.charWidth('w') * defaults.cols,
+ fm.getHeight() * defaults.rows);
}
- /**
- * Returns the painter's minimum size.
- */
public Dimension getMinimumSize() {
return getPreferredSize();
}
- // package-private members
- int currentLineIndex;
- Token currentLineTokens;
- Segment currentLine;
/**
* Accessor used by tools that want to hook in and grab the formatting.
@@ -521,6 +591,7 @@ implements TabExpander, Printable {
public int getCurrentLineIndex() {
return currentLineIndex;
}
+
/**
* Accessor used by tools that want to hook in and grab the formatting.
@@ -528,6 +599,7 @@ implements TabExpander, Printable {
public void setCurrentLineIndex(int what) {
currentLineIndex = what;
}
+
/**
* Accessor used by tools that want to hook in and grab the formatting.
@@ -536,12 +608,14 @@ implements TabExpander, Printable {
return currentLineTokens;
}
+
/**
* Accessor used by tools that want to hook in and grab the formatting.
*/
public void setCurrentLineTokens(Token tokens) {
currentLineTokens = tokens;
}
+
/**
* Accessor used by tools that want to hook in and grab the formatting.
@@ -551,106 +625,175 @@ implements TabExpander, Printable {
}
- // protected members
- protected JEditTextArea textArea;
-
- protected SyntaxStyle[] styles;
- protected Color caretColor;
- protected Color selectionColor;
- protected Color lineHighlightColor;
- protected Color bracketHighlightColor;
- protected Color eolMarkerColor;
-
- protected boolean blockCaret;
- protected boolean lineHighlight;
- protected boolean bracketHighlight;
- protected boolean eolMarkers;
- protected int cols;
- protected int rows;
-
- protected int tabSize;
- protected FontMetrics fm;
-
- protected Highlight highlights;
-
- protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
+ /** Old paintLine() method with kooky args order, kept around for X Mode. */
+ @Deprecated
+ protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
int line, int x) {
- Font defaultFont = getFont();
- Color defaultColor = getForeground();
+// Font defaultFont = getFont();
+// Color defaultColor = getForeground();
currentLineIndex = line;
int y = textArea.lineToY(line);
if (tokenMarker == null) {
- paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
+ //paintPlainLine(gfx, line, defaultFont, defaultColor, x, y);
+ paintPlainLine(gfx, line, x, y);
} else if (line >= 0 && line < textArea.getLineCount()) {
- paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
- defaultColor,x,y);
+ //paintSyntaxLine(gfx, tokenMarker, line, defaultFont, defaultColor, x, y);
+ paintSyntaxLine(gfx, line, x, y, tokenMarker);
}
}
-
- protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
- Color defaultColor, int x, int y) {
- paintHighlight(gfx,line,y);
- textArea.getLineText(line,currentLine);
-
- gfx.setFont(defaultFont);
- gfx.setColor(defaultColor);
-
- y += fm.getHeight();
- x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
- // Draw characters via input method.
- if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
- compositionTextPainter.draw(gfx, lineHighlightColor);
- }
- if (eolMarkers) {
- gfx.setColor(eolMarkerColor);
- gfx.drawString(".",x,y);
- }
+
+
+ protected void paintLine(Graphics gfx, int line, int x,
+ TokenMarker tokenMarker) {
+ paintLine(gfx, tokenMarker, line, x);
}
- protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
- int line, Font defaultFont,
- Color defaultColor, int x, int y) {
- textArea.getLineText(currentLineIndex,currentLine);
- currentLineTokens = tokenMarker.markTokens(currentLine,
- currentLineIndex);
-
- paintHighlight(gfx,line,y);
-
- gfx.setFont(defaultFont);
- gfx.setColor(defaultColor);
- y += fm.getHeight();
- x = SyntaxUtilities.paintSyntaxLine(currentLine,
- currentLineTokens,
- styles, this, gfx, x, y);
- /*
- * Draw characters via input method.
- */
- if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
- compositionTextPainter.draw(gfx, lineHighlightColor);
- }
- if (eolMarkers) {
- gfx.setColor(eolMarkerColor);
- gfx.drawString(".",x,y);
- }
- }
-
-
- protected void paintHighlight(Graphics gfx, int line, int y) {
+
+// protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
+// Color defaultColor, int x, int y) {
+ protected void paintPlainLine(Graphics gfx, int line, int x, int y) {
if (!printing) {
- if (line >= textArea.getSelectionStartLine()
- && line <= textArea.getSelectionStopLine())
- paintLineHighlight(gfx,line,y);
+ paintHighlight(gfx,line,y);
+ }
+ textArea.getLineText(line, currentLine);
- if (highlights != null)
- highlights.paintHighlight(gfx,line,y);
+// gfx.setFont(plainFont);
+// gfx.setFont(defaultFont);
+// gfx.setColor(defaultColor);
- if (bracketHighlight && line == textArea.getBracketLine())
- paintBracketHighlight(gfx,line,y);
+ y += fm.getHeight();
+ // doesn't respect fixed width like it should
+// x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0);
+ int w = fm.charWidth(' ');
+ for (int i = 0; i < currentLine.count; i++) {
+ gfx.drawChars(currentLine.array, currentLine.offset+i, 1, x, y);
+ x += w;
+ }
- if (line == textArea.getCaretLine())
- paintCaret(gfx,line,y);
+ // Draw characters via input method.
+ if (compositionTextPainter != null &&
+ compositionTextPainter.hasComposedTextLayout()) {
+ compositionTextPainter.draw(gfx, defaults.lineHighlightColor);
+ }
+ if (defaults.eolMarkers) {
+ gfx.setColor(defaults.eolMarkerColor);
+ gfx.drawString(".", x, y);
+ }
+ }
+
+
+// protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
+// int line, Font defaultFont,
+// Color defaultColor, int x, int y) {
+ protected void paintSyntaxLine(Graphics gfx, int line, int x, int y,
+ TokenMarker tokenMarker) {
+ textArea.getLineText(currentLineIndex, currentLine);
+ currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex);
+
+// gfx.setFont(plainFont);
+ paintHighlight(gfx, line, y);
+
+// gfx.setFont(defaultFont);
+// gfx.setColor(defaultColor);
+ y += fm.getHeight();
+// x = paintSyntaxLine(currentLine,
+// currentLineTokens,
+// defaults.styles, this, gfx, x, y);
+ x = paintSyntaxLine(gfx, currentLine, x, y,
+ currentLineTokens,
+ defaults.styles);
+ // Draw characters via input method.
+ if (compositionTextPainter != null &&
+ compositionTextPainter.hasComposedTextLayout()) {
+ compositionTextPainter.draw(gfx, defaults.lineHighlightColor);
+ }
+ if (defaults.eolMarkers) {
+ gfx.setColor(defaults.eolMarkerColor);
+ gfx.drawString(".", x, y);
+ }
+ }
+
+
+ /**
+ * Paints the specified line onto the graphics context. Note that this
+ * method munges the offset and count values of the segment.
+ * @param line The line segment
+ * @param tokens The token list for the line
+ * @param styles The syntax style list
+ * @param expander The tab expander used to determine tab stops. May
+ * be null
+ * @param gfx The graphics context
+ * @param x The x co-ordinate
+ * @param y The y co-ordinate
+ * @return The x co-ordinate, plus the width of the painted string
+ */
+// public int paintSyntaxLine(Segment line, Token tokens, SyntaxStyle[] styles,
+// TabExpander expander, Graphics gfx,
+// int x, int y) {
+ protected int paintSyntaxLine(Graphics gfx, Segment line, int x, int y,
+ Token tokens, SyntaxStyle[] styles) {
+// Font defaultFont = gfx.getFont();
+// Color defaultColor = gfx.getColor();
+
+// for (byte id = tokens.id; id != Token.END; tokens = tokens.next) {
+ for (;;) {
+ byte id = tokens.id;
+ if (id == Token.END)
+ break;
+
+ int length = tokens.length;
+ if (id == Token.NULL) {
+// if(!defaultColor.equals(gfx.getColor()))
+// gfx.setColor(defaultColor);
+// if(!defaultFont.equals(gfx.getFont()))
+// gfx.setFont(defaultFont);
+ gfx.setColor(defaults.fgcolor);
+ gfx.setFont(plainFont);
+ } else {
+ //styles[id].setGraphicsFlags(gfx,defaultFont);
+ SyntaxStyle ss = styles[id];
+ gfx.setColor(ss.getColor());
+ gfx.setFont(ss.isBold() ? boldFont : plainFont);
+ }
+ line.count = length; // huh? suspicious
+ // doesn't respect mono metrics, insists on spacing w/ fractional or something
+// x = Utilities.drawTabbedText(line, x, y, gfx, this, 0);
+// gfx.drawChars(line.array, line.offset, line.count, x, y);
+ int w = fm.charWidth(' ');
+ for (int i = 0; i < line.count; i++) {
+ gfx.drawChars(line.array, line.offset+i, 1, x, y);
+ x += w;
+ }
+ //x += fm.charsWidth(line.array, line.offset, line.count);
+ //x += fm.charWidth(' ') * line.count;
+ line.offset += length;
+
+ tokens = tokens.next;
+ }
+
+ return x;
+ }
+
+
+ protected void paintHighlight(Graphics gfx, int line, int y) {//, boolean printing) {
+// if (!printing) {
+ if (line >= textArea.getSelectionStartLine() &&
+ line <= textArea.getSelectionStopLine()) {
+ paintLineHighlight(gfx, line, y);
+ }
+
+ if (highlights != null) {
+ highlights.paintHighlight(gfx, line, y);
+ }
+
+ if (defaults.bracketHighlight && line == textArea.getBracketLine()) {
+ paintBracketHighlight(gfx, line, y);
+ }
+
+ if (line == textArea.getCaretLine()) {
+ paintCaret(gfx, line, y);
}
}
@@ -663,12 +806,12 @@ implements TabExpander, Printable {
int selectionEnd = textArea.getSelectionStop();
if (selectionStart == selectionEnd) {
- if (lineHighlight) {
- gfx.setColor(lineHighlightColor);
- gfx.fillRect(0,y,getWidth(),height);
+ if (defaults.lineHighlight) {
+ gfx.setColor(defaults.lineHighlightColor);
+ gfx.fillRect(0, y, getWidth(), height);
}
} else {
- gfx.setColor(selectionColor);
+ gfx.setColor(defaults.selectionColor);
int selectionStartLine = textArea.getSelectionStartLine();
int selectionEndLine = textArea.getSelectionStopLine();
@@ -712,17 +855,15 @@ implements TabExpander, Printable {
protected void paintBracketHighlight(Graphics gfx, int line, int y) {
int position = textArea.getBracketPosition();
- if (position == -1) {
- return;
+ if (position != -1) {
+ y += fm.getLeading() + fm.getMaxDescent();
+ int x = textArea._offsetToX(line, position);
+ gfx.setColor(defaults.bracketHighlightColor);
+ // Hack!!! Since there is no fast way to get the character
+ // from the bracket matching routine, we use ( since all
+ // brackets probably have the same width anyway
+ gfx.drawRect(x,y,fm.charWidth('(') - 1, fm.getHeight() - 1);
}
- y += fm.getLeading() + fm.getMaxDescent();
- int x = textArea._offsetToX(line,position);
- gfx.setColor(bracketHighlightColor);
- // Hack!!! Since there is no fast way to get the character
- // from the bracket matching routine, we use ( since all
- // brackets probably have the same width anyway
- gfx.drawRect(x,y,fm.charWidth('(') - 1,
- fm.getHeight() - 1);
}
@@ -733,7 +874,7 @@ implements TabExpander, Printable {
int offset =
textArea.getCaretPosition() - textArea.getLineStartOffset(line);
int caretX = textArea._offsetToX(line, offset);
- int caretWidth = ((blockCaret ||
+ int caretWidth = ((defaults.blockCaret ||
textArea.isOverwriteEnabled()) ?
fm.charWidth('w') : 1);
y += fm.getLeading() + fm.getMaxDescent();
@@ -741,10 +882,10 @@ implements TabExpander, Printable {
//System.out.println("caretX, width = " + caretX + " " + caretWidth);
- gfx.setColor(caretColor);
+ gfx.setColor(defaults.caretColor);
if (textArea.isOverwriteEnabled()) {
- gfx.fillRect(caretX,y + height - 1, caretWidth,1);
+ gfx.fillRect(caretX, y + height - 1, caretWidth,1);
} else {
// some machines don't like the drawRect for the single
diff --git a/app/src/processing/app/syntax/im/CompositionTextPainter.java b/app/src/processing/app/syntax/im/CompositionTextPainter.java
index 0084f491f..ae0930a3b 100644
--- a/app/src/processing/app/syntax/im/CompositionTextPainter.java
+++ b/app/src/processing/app/syntax/im/CompositionTextPainter.java
@@ -8,7 +8,6 @@ import java.awt.Point;
import java.awt.font.TextLayout;
import processing.app.syntax.JEditTextArea;
-import processing.app.syntax.TextAreaPainter;
/**
* Paint texts from input method. Text via input method are transmitted by
@@ -26,15 +25,17 @@ public class CompositionTextPainter {
private int composedBeginCaretPosition = 0;
private JEditTextArea textArea;
+
/**
* Constructor for painter.
- * @param textarea textarea used by PDE.
+ * @param textArea textarea used by PDE.
*/
public CompositionTextPainter(JEditTextArea textArea) {
this.textArea = textArea;
composedTextLayout = null;
}
+
/**
* Check the painter has TextLayout.
* If a user input via InputMethod, this result will return true.
@@ -44,6 +45,7 @@ public class CompositionTextPainter {
return (composedTextLayout != null);
}
+
/**
* Set TextLayout to the painter.
* TextLayout will be created and set by CompositionTextManager.
@@ -55,6 +57,7 @@ public class CompositionTextPainter {
this.composedTextLayout = composedTextLayout;
this.composedBeginCaretPosition = composedStartCaretPosition;
}
+
/**
* Invalidate this TextLayout to set null.
@@ -66,6 +69,7 @@ public class CompositionTextPainter {
//this.composedBeginCaretPosition = textArea.getCaretPosition();
}
+
/**
* Draw text via input method with composed text information.
* This method can draw texts with some underlines to illustrate converting characters.
@@ -92,6 +96,7 @@ public class CompositionTextPainter {
refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
}
+
/**
* Fill color to erase characters drawn by original TextAreaPainter.
@@ -109,16 +114,18 @@ public class CompositionTextPainter {
int paintWidth = (int) composedTextLayout.getBounds().getWidth();
gfx.fillRect(x, newY, paintWidth, paintHeight);
}
+
private Point getCaretLocation() {
- Point loc = new Point();
- TextAreaPainter painter = textArea.getPainter();
- FontMetrics fm = painter.getFontMetrics();
+ FontMetrics fm = textArea.getPainter().getFontMetrics();
int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
- loc.y = lineIndex * fm.getHeight() + offsetY;
+// loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
- loc.x = textArea.offsetToX(lineIndex, offsetX);
- return loc;
+// loc.x = textArea.offsetToX(lineIndex, offsetX);
+ return new Point(textArea.offsetToX(lineIndex, offsetX),
+ lineIndex * fm.getHeight() + offsetY);
+// Point loc = new Point();
+// return loc;
}
}
diff --git a/app/src/processing/app/tools/Archiver.java b/app/src/processing/app/tools/Archiver.java
old mode 100755
new mode 100644
diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java
index 217af0bfa..17d6cbc73 100644
--- a/app/src/processing/app/tools/CreateFont.java
+++ b/app/src/processing/app/tools/CreateFont.java
@@ -112,9 +112,11 @@ public class CreateFont extends JFrame implements Tool {
// also ignore dialog, dialoginput, monospaced, serif, sansserif
// getFontList is deprecated in 1.4, so this has to be used
+ //long t = System.currentTimeMillis();
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
- Font fonts[] = ge.getAllFonts();
+ Font[] fonts = ge.getAllFonts();
+ //System.out.println("font startup took " + (System.currentTimeMillis() - t) + " ms");
if (false) {
ArrayList fontList = new ArrayList();
diff --git a/app/src/processing/app/tools/ExportExamples.java b/app/src/processing/app/tools/ExportExamples.java
deleted file mode 100644
index 65889cbad..000000000
--- a/app/src/processing/app/tools/ExportExamples.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-package processing.app.tools;
-
-import java.io.*;
-//import java.util.HashMap;
-
-import processing.app.*;
-import processing.mode.java.JavaBuild;
-
-public class ExportExamples implements Tool {
- static final String DELETE_TARGET = "export.delete_target_folder";
- static final String SEPARATE_JAR = "export.applet.separate_jar_files";
-
-// HashMap errors;
- Editor orig;
-
- // copy the files to processing.org/content/examples with their hierarchy intact
- // that won't be checked into svn, even though they were before
-
-// File webroot;
-// File templates;
-// File xml;
-
- Base base;
- File[] folders;
- File outputFolder;
- String examplesPath;
-
-
- public void init(Editor editor) {
- orig = editor;
- base = editor.getBase();
- Mode mode = editor.getMode();
- folders = mode.getExampleCategoryFolders();
- examplesPath = mode.getExamplesFolder().getAbsolutePath();
-
- // Not perfect, but will work for Casey and I
- File desktop = new File(System.getProperty("user.home"), "Desktop");
- outputFolder = new File(desktop, "examples");
-// webroot = new File("/Users/fry/coconut/processing.web");
-// templates = new File(webroot, "templates");
- }
-
-
- public void run() {
- new Thread(new Runnable() { public void run() {
- if (outputFolder.exists()) {
- Base.showWarning("Try Again", "Please remove the examples folder from the desktop,\n" +
- "because that's where I wanna put things.", null);
- return;
- }
-// errors = new HashMap();
- boolean delete = Preferences.getBoolean(DELETE_TARGET);
- Preferences.setBoolean(DELETE_TARGET, false);
- boolean separate = Preferences.getBoolean(SEPARATE_JAR);
- Preferences.setBoolean(SEPARATE_JAR, true);
-
- for (File folder : folders) {
- if (!folder.getName().equals("Books")) {
- handleFolder(folder);
- }
- }
-
- Preferences.setBoolean(DELETE_TARGET, delete);
- Preferences.setBoolean(SEPARATE_JAR, separate);
- orig.statusNotice("Finished exporting examples.");
- } }).start();
-
-// if (errors.size() > 0) {
-// orig.statusError((errors.size() == 1 ? "One sketch" : (errors.size() + " sketches")) + " had errors.");
-// } else {
-// }
-// for (String path : errors.keySet()) {
-// System.err.println("Error: "
-// }
- }
-
-
- public void handleFolder(File folder) {
- File pdeFile = new File(folder, folder.getName() + ".pde");
- if (pdeFile.exists()) {
- String pdePath = pdeFile.getAbsolutePath();
- Editor editor = base.handleOpen(pdePath);
- if (editor != null) {
- try {
-// System.out.println(pdePath);
- if (handle(editor)) {
- base.handleClose(editor, false);
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) { }
- }
- } catch (Exception e) {
- e.printStackTrace();
- // errors.put(pdePath, e);
- // System.err.println("Error handling " + pdePath);
- // e.printStackTrace();
- }
- }
- } else { // recurse into the folder
- //System.out.println(" into " + folder.getAbsolutePath());
- File[] sub = folder.listFiles();
- for (File f : sub) {
- if (f.isDirectory()) {
- handleFolder(f);
- }
- }
- }
- }
-
-
- public boolean handle(Editor editor) throws SketchException, IOException {
- Sketch sketch = editor.getSketch();
- File sketchFolder = sketch.getFolder();
- String sketchPath = sketchFolder.getAbsolutePath();
- String uniquePath = sketchPath.substring(examplesPath.length());
- File sketchTarget = new File(outputFolder, uniquePath);
-
- // copy the PDE files so that they can be pulled in by the generator script
-// File[] files = sketchFolder.listFiles();
-// for (File file : files) {
-// if (file.getName().endsWith(".pde")) {
-// Base.copyFile(file, new File(sketchTarget, file.getName()));
-// }
-// }
- // no need to do this because the source files will be in 'applet' anyway
-
- // build the applet into this folder
- File appletFolder = new File(sketchTarget, "applet");
- JavaBuild build = new JavaBuild(sketch);
- boolean result = build.exportApplet(appletFolder);
-
- // Just one copy of core.jar into the root
- File coreTarget = new File(outputFolder, "core.jar");
- File sketchCore = new File(appletFolder, "core.jar");
- if (!coreTarget.exists()) {
- Base.copyFile(sketchCore, coreTarget);
- }
- sketchCore.delete();
-
- File loadingTarget = new File(outputFolder, "loading.gif");
- if (!loadingTarget.exists()) {
- Base.copyFile(new File(appletFolder, "loading.gif"), loadingTarget);
- }
-
- new File(appletFolder, "index.html").delete();
- new File(appletFolder, "loading.gif").delete();
- new File(appletFolder, sketch.getName() + ".java").delete();
-
- return result;
- }
-
-
- public String getMenuTitle() {
- return "Export Examples";
- }
-}
-*/
\ No newline at end of file
diff --git a/app/src/processing/app/tools/FixEncoding.java b/app/src/processing/app/tools/FixEncoding.java
deleted file mode 100644
index e58768ab3..000000000
--- a/app/src/processing/app/tools/FixEncoding.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2008-11 Ben Fry and Casey Reas
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, version 2.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app.tools;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-import javax.swing.JOptionPane;
-
-import processing.app.*;
-
-
-public class FixEncoding implements Tool {
- Editor editor;
-
-
- public String getMenuTitle() {
- return "Fix Encoding & Reload";
- }
-
-
- public void init(Editor editor) {
- this.editor = editor;
- }
-
-
- public void run() {
- Sketch sketch = editor.getSketch();
- //SketchCode code = sketch.current;
-
- if (sketch.isModified()) {
- int result =
- JOptionPane.showConfirmDialog(editor,
- "Discard all changes and reload sketch?",
- "Fix Encoding & Reload",
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE);
-
- if (result == JOptionPane.NO_OPTION) {
- return;
- }
- }
- try {
- for (int i = 0; i < sketch.getCodeCount(); i++) {
- SketchCode code = sketch.getCode(i);
- code.setProgram(loadWithLocalEncoding(code.getFile()));
- code.setModified(true); // yes, because we want them to save this
- }
- // Update the currently visible program with its code
- editor.setText(sketch.getCurrentCode().getProgram());
-
- } catch (IOException e) {
- String msg =
- "An error occurred while trying to fix the file encoding.\n" +
- "Do not attempt to save this sketch as it may overwrite\n" +
- "the old version. Use Open to re-open the sketch and try again.\n" +
- e.getMessage();
- Base.showWarning("Fix Encoding & Reload", msg, e);
- }
- }
-
-
- protected String loadWithLocalEncoding(File file) throws IOException {
- // FileReader uses the default encoding, which is what we want.
- String encoding = System.getProperty("file.encoding");
- if (Base.isMacOS()) {
- // Remember that time that Apple decided to change the file encoding
- // in later releases of Java? That was really awesome.
- if (encoding.equals("UTF-8")) {
- // Changing from UTF-8 to UTF-8 isn't going to help much. Argh.
- encoding = "MacRoman";
- }
- }
- FileInputStream fis = new FileInputStream(file);
- InputStreamReader isr = new InputStreamReader(fis, encoding);
- BufferedReader reader = new BufferedReader(isr);
-
- StringBuffer buffer = new StringBuffer();
- String line = null;
- while ((line = reader.readLine()) != null) {
- buffer.append(line);
- buffer.append('\n');
- }
- reader.close();
- return buffer.toString();
- }
-}
\ No newline at end of file
diff --git a/app/src/processing/app/tools/InstallCommander.java b/app/src/processing/app/tools/InstallCommander.java
index 461a80dba..c3133de1b 100644
--- a/app/src/processing/app/tools/InstallCommander.java
+++ b/app/src/processing/app/tools/InstallCommander.java
@@ -80,30 +80,28 @@ public class InstallCommander implements Tool {
writer.println("#!/bin/sh");
String[] jarList = new String[] {
- "lib/pde.jar",
- "lib/antlr.jar",
- "lib/jna.jar",
- "lib/ant.jar",
- "lib/ant-launcher.jar",
+ "pde.jar",
+ "antlr.jar",
+ "jna.jar",
+ "ant.jar",
+ "ant-launcher.jar",
// extra libraries for new JDI setup
- "lib/org-netbeans-swing-outline.jar",
- "lib/com.ibm.icu_4.4.2.v20110823.jar",
- "lib/jdi.jar",
- "lib/jdimodel.jar",
- "lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar",
+ "org-netbeans-swing-outline.jar",
+ "com.ibm.icu_4.4.2.v20110823.jar",
+ "jdi.jar",
+ "jdimodel.jar",
+ "org.eclipse.osgi_3.8.1.v20120830-144521.jar",
"core/library/core.jar"
};
String classPath = PApplet.join(jarList, ":");
- String javaRoot = System.getProperty("javaroot");
+ //String javaRoot = System.getProperty("javaroot");
+ String javaRoot = Base.getContentFile(".").getCanonicalPath();
writer.println("cd \"" + javaRoot + "\" && " +
- "/usr/libexec/java_home " +
- "--request " +
- "--version 1.6 " +
- "--exec java " +
- "-cp " + classPath +
+ Base.getJavaPath() +
+ " -cp \"" + classPath + "\"" +
" processing.mode.java.Commander \"$@\"");
writer.flush();
writer.close();
diff --git a/app/src/processing/app/tools/SerialFixer.java b/app/src/processing/app/tools/SerialFixer.java
deleted file mode 100644
index 7065b53bc..000000000
--- a/app/src/processing/app/tools/SerialFixer.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2012 The Processing Foundation
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, version 2.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app.tools;
-
-import java.io.File;
-
-import javax.swing.JOptionPane;
-
-import processing.app.Base;
-import processing.app.Editor;
-import processing.core.PApplet;
-
-
-public class SerialFixer implements Tool {
- Editor editor;
-
-
- public String getMenuTitle() {
- return "Fix the Serial Library";
- }
-
-
- public void init(Editor editor) {
- this.editor = editor;
- }
-
-
- public void run() {
- final String primary =
- "Attempt to fix common serial port problems?";
- final String secondary =
- "Click “OK” to perform additional installation steps to enable " +
- "the Serial library. An administrator password will be required.";
-
- int result =
- JOptionPane.showConfirmDialog(editor,
- " " +
- " " +
- "" + primary + "" +
- "
+ * A more up-to-date version of the project seems to be
+ * here.
+ * If someone would like to help us update the encoder, that'd be great.
+ *
+ * Broken out as a separate project because the license (CC) probably isn't
+ * compatible with the rest of Processing and we don't want any confusion.
+ *
+ * Added JAI ImageIO to support lots of other image file formats [131008].
+ * Also copied the Processing TGA implementation.
+ *
+ * Added support for the gamma ('gama') atom [131008].
+ *
+ * A few more notes on the implementation:
+ *
+ *
The dialog box is super ugly. It's a hacked up version of the previous
+ * interface, but I'm too scared to pull that GUI layout code apart.
+ *
The 'None' compressor seems to have bugs, so just disabled it instead.
+ *
The 'pass through' option seems to be broken, so it's been removed.
+ * In its place is an option to use the same width/height as the originals.
+ *
When this new 'pass through' is set, there's some nastiness with how
+ * the 'final' width/height variables are passed to the movie maker.
+ * This is an easy fix but needs a couple minutes.
+ *
+ * A version of this function is in MovieMaker.java. Any fixes here
+ * should be applied over in MovieMaker as well.
+ *
+ * Known issue with RLE encoding and odd behavior in some apps:
+ * https://github.com/processing/processing/issues/2096
+ * Please help!
*/
protected PImage loadImageTGA(String filename) throws IOException {
InputStream is = createInput(filename);
@@ -5845,7 +5962,7 @@ public class PApplet extends Applet
header[2] image type code
2 (0x02) - Uncompressed, RGB images.
3 (0x03) - Uncompressed, black and white images.
- 10 (0x0A) - Runlength encoded RGB images.
+ 10 (0x0A) - Run-length encoded RGB images.
11 (0x0B) - Compressed, black and white images. (grayscale?)
header[16] is the bit depth (8, 24, 32)
@@ -6068,6 +6185,7 @@ public class PApplet extends Applet
public XML loadXML(String filename, String options) {
try {
return new XML(createReader(filename), options);
+// return new XML(createInput(filename), options);
} catch (Exception e) {
e.printStackTrace();
return null;
@@ -6121,6 +6239,7 @@ public class PApplet extends Applet
return new JSONObject(new StringReader(input));
}
+
/**
* @webref input:files
* @param filename name of a file in the data folder or a URL
@@ -6134,6 +6253,12 @@ public class PApplet extends Applet
return new JSONObject(createReader(filename));
}
+
+ static public JSONObject loadJSONObject(File file) {
+ return new JSONObject(createReader(file));
+ }
+
+
/**
* @webref output:files
* @see JSONObject
@@ -6156,6 +6281,7 @@ public class PApplet extends Applet
return new JSONArray(new StringReader(input));
}
+
/**
* @webref input:files
* @param filename name of a file in the data folder or a URL
@@ -6169,6 +6295,12 @@ public class PApplet extends Applet
return new JSONArray(createReader(filename));
}
+
+ static public JSONArray loadJSONArray(File file) {
+ return new JSONArray(createReader(file));
+ }
+
+
/**
* @webref output:files
* @see JSONObject
@@ -6214,22 +6346,28 @@ public class PApplet extends Applet
/**
- * @param options may contain "header", "tsv", "csv", or "bin" separated by commas
+ * Options may contain "header", "tsv", "csv", or "bin" separated by commas.
+ *
+ * Another option is "dictionary=filename.tsv", which allows users to
+ * specify a "dictionary" file that contains a mapping of the column titles
+ * and the data types used in the table file. This can be far more efficient
+ * (in terms of speed and memory usage) for loading and parsing tables. The
+ * dictionary file can only be tab separated values (.tsv) and its extension
+ * will be ignored. This option was added in Processing 2.0.2.
*/
public Table loadTable(String filename, String options) {
try {
-// String ext = checkExtension(filename);
-// if (ext != null) {
-// if (ext.equals("csv") || ext.equals("tsv") || ext.equals("bin")) {
-// if (options == null) {
-// options = ext;
-// } else {
-// options = ext + "," + options;
-// }
-// }
-// }
- return new Table(createInput(filename),
- Table.extensionOptions(true, filename, options));
+ String optionStr = Table.extensionOptions(true, filename, options);
+ String[] optionList = trim(split(optionStr, ','));
+
+ Table dictionary = null;
+ for (String opt : optionList) {
+ if (opt.startsWith("dictionary=")) {
+ dictionary = loadTable(opt.substring(opt.indexOf('=') + 1), "tsv");
+ return dictionary.typedParse(createInput(filename), optionStr);
+ }
+ }
+ return new Table(createInput(filename), optionStr);
} catch (IOException e) {
e.printStackTrace();
@@ -7674,13 +7812,39 @@ public class PApplet extends Applet
}
+ static File desktopFolder;
+
+ /** Not a supported function. For testing use only. */
+ static public File desktopFile(String what) {
+ if (desktopFolder == null) {
+ // Should work on Linux and OS X (on OS X, even with the localized version).
+ desktopFolder = new File(System.getProperty("user.home"), "Desktop");
+ if (!desktopFolder.exists()) {
+ if (platform == WINDOWS) {
+ FileSystemView filesys = FileSystemView.getFileSystemView();
+ desktopFolder = filesys.getHomeDirectory();
+ } else {
+ throw new UnsupportedOperationException("Could not find a suitable desktop foldder");
+ }
+ }
+ }
+ return new File(desktopFolder, what);
+ }
+
+
+ /** Not a supported function. For testing use only. */
+ static public String desktopPath(String what) {
+ return desktopFile(what).getAbsolutePath();
+ }
+
+
/**
* Return a full path to an item in the data folder.
*
* This is only available with applications, not applets or Android.
* On Windows and Linux, this is simply the data folder, which is located
* in the same directory as the EXE file and lib folders. On Mac OS X, this
- * is a path to the data folder buried inside Contents/Resources/Java.
+ * is a path to the data folder buried inside Contents/Java.
* For the latter point, that also means that the data folder should not be
* considered writable. Use sketchPath() for now, or inputPath() and
* outputPath() once they're available in the 2.0 release.
@@ -7707,11 +7871,12 @@ public class PApplet extends Applet
String jarPath =
getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
- if (jarPath.contains("Contents/Resources/Java/")) {
+ if (jarPath.contains("Contents/Java/")) {
// The path will be URL encoded (%20 for spaces) coming from above
// http://code.google.com/p/processing/issues/detail?id=1073
File containingFolder = new File(urlDecode(jarPath)).getParentFile();
File dataFolder = new File(containingFolder, "data");
+ System.out.println(dataFolder);
return new File(dataFolder, where);
}
// Windows, Linux, or when not using a Mac OS X .app file
@@ -7721,7 +7886,7 @@ public class PApplet extends Applet
/**
* On Windows and Linux, this is simply the data folder. On Mac OS X, this is
- * the path to the data folder buried inside Contents/Resources/Java
+ * the path to the data folder buried inside Contents/Java
*/
// public File inputFile(String where) {
// }
@@ -10074,15 +10239,21 @@ public class PApplet extends Applet
if (farm.isVisible()) {
Insets insets = farm.getInsets();
Dimension windowSize = farm.getSize();
- Rectangle newBounds =
- new Rectangle(insets.left, insets.top,
- windowSize.width - insets.left - insets.right,
- windowSize.height - insets.top - insets.bottom);
- Rectangle oldBounds = getBounds();
- if (!newBounds.equals(oldBounds)) {
- // the ComponentListener in PApplet will handle calling size()
- setBounds(newBounds);
- }
+ // JFrame (unlike java.awt.Frame) doesn't include the left/top
+ // insets for placement (though it does seem to need them for
+ // 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.
+ Rectangle newBounds =
+ new Rectangle(0, 0, //insets.left, insets.top,
+ windowSize.width - insets.left - insets.right,
+ windowSize.height - insets.top - insets.bottom);
+ Rectangle oldBounds = getBounds();
+ if (!newBounds.equals(oldBounds)) {
+ // the ComponentListener in PApplet will handle calling size()
+ setBounds(newBounds);
+ revalidate(); // let the layout manager do its work
+ }
}
}
}
@@ -10378,30 +10549,24 @@ public class PApplet extends Applet
displayDevice = environment.getDefaultScreenDevice();
}
- Frame frame = new Frame(displayDevice.getDefaultConfiguration());
- frame.setBackground(new Color(0xCC, 0xCC, 0xCC)); // default Processing gray
-// JFrame frame = new JFrame(displayDevice.getDefaultConfiguration());
- /*
- Frame frame = null;
- if (displayDevice != null) {
- frame = new Frame(displayDevice.getDefaultConfiguration());
- } else {
- frame = new Frame();
- }
- */
- //Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
-
- // remove the grow box by default
- // users who want it back can call frame.setResizable(true)
-// frame.setResizable(false);
- // moved later (issue #467)
+ // Using a JFrame fixes a Windows problem with Present mode. This might
+ // be our error, but usually this is the sort of crap we usually get from
+ // OS X. It's time for a turnaround: Redmond is thinking different too!
+ // https://github.com/processing/processing/issues/1955
+ Frame frame = new JFrame(displayDevice.getDefaultConfiguration());
+ // Default Processing gray, which will be replaced below if another
+ // color is specified on the command line (i.e. in the prefs).
+ final Color defaultGray = new Color(0xCC, 0xCC, 0xCC);
+ ((JFrame) frame).getContentPane().setBackground(defaultGray);
+ // Cannot call setResizable(false) until later due to OS X (issue #467)
final PApplet applet;
if (constructedApplet != null) {
applet = constructedApplet;
} else {
try {
- Class> c = Thread.currentThread().getContextClassLoader().loadClass(name);
+ Class> c =
+ Thread.currentThread().getContextClassLoader().loadClass(name);
applet = (PApplet) c.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
@@ -10499,9 +10664,12 @@ public class PApplet extends Applet
// japplemenubar.JAppleMenuBar.hide();
// }
+ // Tried to use this to fix the 'present' mode issue.
+ // Did not help, and the screenRect setup seems to work fine.
+ //frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setUndecorated(true);
if (backgroundColor != null) {
- frame.setBackground(backgroundColor);
+ ((JFrame) frame).getContentPane().setBackground(backgroundColor);
}
// if (exclusive) {
// displayDevice.setFullScreenWindow(frame);
@@ -10520,6 +10688,7 @@ public class PApplet extends Applet
} else {
frame.pack();
}
+
// insufficient, places the 100x100 sketches offset strangely
//frame.validate();
@@ -10597,14 +10766,18 @@ public class PApplet extends Applet
} else { // if not presenting
// can't do pack earlier cuz present mode don't like it
// (can't go full screen with a frame after calling pack)
- // frame.pack(); // get insets. get more.
- Insets insets = frame.getInsets();
+ // frame.pack();
+ // get insets. get more.
+ Insets insets = frame.getInsets();
int windowW = Math.max(applet.width, MIN_WINDOW_WIDTH) +
insets.left + insets.right;
int windowH = Math.max(applet.height, MIN_WINDOW_HEIGHT) +
insets.top + insets.bottom;
+ int contentW = Math.max(applet.width, MIN_WINDOW_WIDTH);
+ int contentH = Math.max(applet.height, MIN_WINDOW_HEIGHT);
+
frame.setSize(windowW, windowH);
if (location != null) {
@@ -10653,12 +10826,15 @@ public class PApplet extends Applet
// // this means no bg color unless specified
// backgroundColor = SystemColor.control;
// }
- frame.setBackground(backgroundColor);
+ ((JFrame) frame).getContentPane().setBackground(backgroundColor);
}
- int usableWindowH = windowH - insets.top - insets.bottom;
- applet.setBounds((windowW - applet.width)/2,
- insets.top + (usableWindowH - applet.height)/2,
+// int usableWindowH = windowH - insets.top - insets.bottom;
+// applet.setBounds((windowW - applet.width)/2,
+// insets.top + (usableWindowH - applet.height)/2,
+// applet.width, applet.height);
+ applet.setBounds((contentW - applet.width)/2,
+ (contentH - applet.height)/2,
applet.width, applet.height);
if (external) {
@@ -10679,6 +10855,21 @@ public class PApplet extends Applet
// all set for rockin
if (applet.displayable()) {
frame.setVisible(true);
+
+ // Linux doesn't deal with insets the same way. We get fake insets
+ // earlier, and then the window manager will slap its own insets
+ // onto things once the frame is realized on the screen. Awzm.
+ if (platform == LINUX) {
+ Insets irlInsets = frame.getInsets();
+ if (!irlInsets.equals(insets)) {
+ insets = irlInsets;
+ windowW = Math.max(applet.width, MIN_WINDOW_WIDTH) +
+ insets.left + insets.right;
+ windowH = Math.max(applet.height, MIN_WINDOW_HEIGHT) +
+ insets.top + insets.bottom;
+ frame.setSize(windowW, windowH);
+ }
+ }
}
}
diff --git a/core/src/processing/core/PConstants.java b/core/src/processing/core/PConstants.java
index f4030bb7e..162f936b8 100644
--- a/core/src/processing/core/PConstants.java
+++ b/core/src/processing/core/PConstants.java
@@ -92,10 +92,13 @@ public interface PConstants {
static public final int VERTEX = 0;
static public final int BEZIER_VERTEX = 1;
- static public final int QUAD_BEZIER_VERTEX = 2;
+ static public final int QUADRATIC_VERTEX = 2;
static public final int CURVE_VERTEX = 3;
static public final int BREAK = 4;
+ @Deprecated
+ static public final int QUAD_BEZIER_VERTEX = 2; // should not have been exposed
+
// useful goodness
/**
diff --git a/core/src/processing/core/PFont.java b/core/src/processing/core/PFont.java
index 6060fcfb9..cba1bf4d0 100644
--- a/core/src/processing/core/PFont.java
+++ b/core/src/processing/core/PFont.java
@@ -24,6 +24,9 @@
package processing.core;
import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.PathIterator;
import java.awt.image.*;
import java.io.*;
import java.util.Arrays;
@@ -683,6 +686,95 @@ public class PFont implements PConstants {
}
+ public PShape getShape(char ch) {
+ return getShape(ch, 0);
+ }
+
+
+ public PShape getShape(char ch, float detail) {
+ Font font = (Font) getNative();
+ if (font == null) {
+ throw new IllegalArgumentException("getShape() only works on fonts loaded with createFont()");
+ }
+
+ PShape s = new PShape(PShape.PATH);
+
+ // six element array received from the Java2D path iterator
+ float[] iterPoints = new float[6];
+ // array passed to createGylphVector
+ char[] textArray = new char[] { ch };
+
+ //Graphics2D graphics = (Graphics2D) this.getGraphics();
+ //FontRenderContext frc = graphics.getFontRenderContext();
+ @SuppressWarnings("deprecation")
+ FontRenderContext frc =
+ Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext();
+ GlyphVector gv = font.createGlyphVector(frc, textArray);
+ Shape shp = gv.getOutline();
+ // make everything into moveto and lineto
+ PathIterator iter = (detail == 0) ?
+ shp.getPathIterator(null) : // maintain curves
+ shp.getPathIterator(null, detail); // convert to line segments
+
+ int contours = 0;
+ //boolean outer = true;
+// boolean contour = false;
+ while (!iter.isDone()) {
+ int type = iter.currentSegment(iterPoints);
+ switch (type) {
+ case PathIterator.SEG_MOVETO: // 1 point (2 vars) in textPoints
+// System.out.println("moveto");
+// if (!contour) {
+ if (contours == 0) {
+ s.beginShape();
+ } else {
+ s.beginContour();
+// contour = true;
+ }
+ contours++;
+ s.vertex(iterPoints[0], iterPoints[1]);
+ break;
+
+ case PathIterator.SEG_LINETO: // 1 point
+// System.out.println("lineto");
+// PApplet.println(PApplet.subset(iterPoints, 0, 2));
+ s.vertex(iterPoints[0], iterPoints[1]);
+ break;
+
+ case PathIterator.SEG_QUADTO: // 2 points
+// System.out.println("quadto");
+// PApplet.println(PApplet.subset(iterPoints, 0, 4));
+ s.quadraticVertex(iterPoints[0], iterPoints[1],
+ iterPoints[2], iterPoints[3]);
+ break;
+
+ case PathIterator.SEG_CUBICTO: // 3 points
+// System.out.println("cubicto");
+// PApplet.println(iterPoints);
+ s.quadraticVertex(iterPoints[0], iterPoints[1],
+ iterPoints[2], iterPoints[3],
+ iterPoints[4], iterPoints[5]);
+ break;
+
+ case PathIterator.SEG_CLOSE:
+// System.out.println("close");
+ if (contours > 1) {
+// contours--;
+// if (contours == 0) {
+//// s.endShape();
+// } else {
+ s.endContour();
+ }
+ break;
+ }
+// PApplet.println(iterPoints);
+ iter.next();
+ }
+ s.endShape(CLOSE);
+ return s;
+ }
+
+
//////////////////////////////////////////////////////////////
diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java
index 5edf6b826..8ec72c89d 100644
--- a/core/src/processing/core/PGraphics.java
+++ b/core/src/processing/core/PGraphics.java
@@ -473,6 +473,11 @@ public class PGraphics extends PImage implements PConstants {
protected float backgroundR, backgroundG, backgroundB, backgroundA;
protected int backgroundRi, backgroundGi, backgroundBi, backgroundAi;
+
+ /** The current blending mode. */
+ protected int blendMode;
+
+
// ........................................................
/**
@@ -944,6 +949,8 @@ public class PGraphics extends PImage implements PConstants {
background(backgroundColor);
}
+ blendMode(BLEND);
+
settingsInited = true;
// defaultSettings() overlaps reapplySettings(), don't do both
//reapplySettings = false;
@@ -961,12 +968,11 @@ public class PGraphics extends PImage implements PConstants {
* called before defaultSettings(), so we should be safe.
*/
protected void reapplySettings() {
-// System.out.println("attempting reapplySettings()");
+ // This might be called by allocate... So if beginDraw() has never run,
+ // we don't want to reapply here, we actually just need to let
+ // defaultSettings() get called a little from inside beginDraw().
if (!settingsInited) return; // if this is the initial setup, no need to reapply
-// System.out.println(" doing reapplySettings");
-// new Exception().printStackTrace(System.out);
-
colorMode(colorMode, colorModeX, colorModeY, colorModeZ);
if (fill) {
// PApplet.println(" fill " + PApplet.hex(fillColor));
@@ -1013,6 +1019,8 @@ public class PGraphics extends PImage implements PConstants {
textAlign(textAlign, textAlignY);
background(backgroundColor);
+ blendMode(blendMode);
+
reapplySettings = false;
}
@@ -1216,6 +1224,9 @@ public class PGraphics extends PImage implements PConstants {
* @see PGraphics#textureWrap(int)
*/
public void textureMode(int mode) {
+ if (mode != IMAGE && mode != NORMAL) {
+ throw new RuntimeException("textureMode() only supports IMAGE and NORMAL");
+ }
this.textureMode = mode;
}
@@ -1827,7 +1838,15 @@ public class PGraphics extends PImage implements PConstants {
* @param mode the blending mode to use
*/
public void blendMode(int mode) {
- showMissingWarning("blendMode");
+ this.blendMode = mode;
+ blendModeImpl();
+ }
+
+
+ protected void blendModeImpl() {
+ if (blendMode != BLEND) {
+ showMissingWarning("blendMode");
+ }
}
@@ -5539,7 +5558,7 @@ public class PGraphics extends PImage implements PConstants {
* @see PGraphics#camera(float, float, float, float, float, float, float, float, float)
*/
public void printProjection() {
- showMethodWarning("printCamera");
+ showMethodWarning("printProjection");
}
@@ -7619,6 +7638,9 @@ public class PGraphics extends PImage implements PConstants {
* individual color components of a color supplied as an int value.
*/
static public int lerpColor(int c1, int c2, float amt, int mode) {
+ if (amt < 0) amt = 0;
+ if (amt > 1) amt = 1;
+
if (mode == RGB) {
float a1 = ((c1 >> 24) & 0xff);
float r1 = (c1 >> 16) & 0xff;
diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java
index e0095728a..62c58a659 100644
--- a/core/src/processing/core/PGraphicsJava2D.java
+++ b/core/src/processing/core/PGraphicsJava2D.java
@@ -52,7 +52,7 @@ import processing.data.XML;
* any way shape or form. Which just means "have fun, but don't complain
* if it breaks."
*/
-public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
+public class PGraphicsJava2D extends PGraphics {
BufferStrategy strategy;
BufferedImage bimage;
VolatileImage vimage;
@@ -263,13 +263,15 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
if (image == null || ((VolatileImage) image).validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
image = gc.createCompatibleVolatileImage(width, height);
g2 = (Graphics2D) image.getGraphics();
+ reapplySettings = true;
}
} else {
if (image == null) {
GraphicsConfiguration gc = parent.getGraphicsConfiguration();
image = gc.createCompatibleImage(width, height);
- System.out.println("created new image, type is " + image);
+ PApplet.debug("created new image, type is " + image);
g2 = (Graphics2D) image.getGraphics();
+ reapplySettings = true;
}
}
//g2 = (Graphics2D) image.getGraphics();
@@ -305,6 +307,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
// image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2 = bimage.createGraphics();
defaultComposite = g2.getComposite();
+ reapplySettings = true;
}
}
@@ -373,7 +376,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
PApplet.debug("PGraphicsJava2D.redraw() top of outer do { } block");
do {
PApplet.debug("PGraphicsJava2D.redraw() top of inner do { } block");
- System.out.println("strategy is " + strategy);
+ PApplet.debug("strategy is " + strategy);
Graphics bsg = strategy.getDrawGraphics();
if (vimage != null) {
bsg.drawImage(vimage, 0, 0, null);
@@ -691,8 +694,8 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
* @param mode the blending mode to use
*/
@Override
- public void blendMode(final int mode) {
- if (mode == BLEND) {
+ protected void blendModeImpl() {
+ if (blendMode == BLEND) {
g2.setComposite(defaultComposite);
} else {
@@ -702,7 +705,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public CompositeContext createContext(ColorModel srcColorModel,
ColorModel dstColorModel,
RenderingHints hints) {
- return new BlendingContext(mode);
+ return new BlendingContext(blendMode);
}
});
}
@@ -1244,15 +1247,25 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
// Image not ready yet, or an error
if (who.width <= 0 || who.height <= 0) return;
- if (getCache(who) == null) {
+ ImageCache cash = (ImageCache) getCache(who);
+
+ // Nuke the cache if the image was resized
+ if (cash != null) {
+ if (who.width != cash.image.getWidth() ||
+ who.height != cash.image.getHeight()) {
+ cash = null;
+ }
+ }
+
+ if (cash == null) {
//System.out.println("making new image cache");
- this.setCache(who, new ImageCache(who));
+ cash = new ImageCache(); //who);
+ setCache(who, cash);
who.updatePixels(); // mark the whole thing for update
who.modified = true;
}
- ImageCache cash = (ImageCache) getCache(who);
- // if image previously was tinted, or the color changed
+ // 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)) ||
@@ -1270,8 +1283,8 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
(int) x1, (int) y1, (int) x2, (int) y2,
u1, v1, u2, v2, null);
- // every few years I think "nah, Java2D couldn't possibly be that
- // f*king slow, why are we doing this by hand? then comes the affirmation.
+ // Every few years I think "nah, Java2D couldn't possibly be that f*king
+ // slow, why are we doing this by hand?" then comes the affirmation:
// Composite oldComp = null;
// if (false && tint) {
// oldComp = g2.getComposite();
@@ -1297,17 +1310,17 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
class ImageCache {
boolean tinted;
int tintedColor;
- int tintedPixels[]; // one row of tinted pixels
+ int[] tintedTemp; // one row of tinted pixels
BufferedImage image;
- public ImageCache(PImage source) {
-// this.source = source;
- // even if RGB, set the image type to ARGB, because the
- // image may have an alpha value for its tint().
-// int type = BufferedImage.TYPE_INT_ARGB;
- //System.out.println("making new buffered image");
-// image = new BufferedImage(source.width, source.height, type);
- }
+// public ImageCache(PImage source) {
+//// this.source = source;
+// // even if RGB, set the image type to ARGB, because the
+// // image may have an alpha value for its tint().
+//// int type = BufferedImage.TYPE_INT_ARGB;
+// //System.out.println("making new buffered image");
+//// image = new BufferedImage(source.width, source.height, type);
+// }
/**
* Update the pixels of the cache image. Already determined that the tint
@@ -1315,29 +1328,41 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
* with the update without further checks.
*/
public void update(PImage source, boolean tint, int tintColor) {
- int bufferType = BufferedImage.TYPE_INT_ARGB;
+ //int bufferType = BufferedImage.TYPE_INT_ARGB;
+ int targetType = ARGB;
boolean opaque = (tintColor & 0xFF000000) == 0xFF000000;
if (source.format == RGB) {
if (!tint || (tint && opaque)) {
- bufferType = BufferedImage.TYPE_INT_RGB;
+ //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);
+// 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);
}
WritableRaster wr = image.getRaster();
if (tint) {
- if (tintedPixels == null || tintedPixels.length != source.width) {
- tintedPixels = new int[source.width];
+ if (tintedTemp == null || tintedTemp.length != source.width) {
+ tintedTemp = new int[source.width];
}
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 (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;
@@ -1348,12 +1373,15 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
int g1 = (argb1 >> 8) & 0xff;
int b1 = (argb1) & 0xff;
- tintedPixels[x] = //0xFF000000 |
+ // 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, tintedPixels);
+ wr.setDataElements(0, y, source.width, 1, tintedTemp);
}
// could this be any slower?
// float[] scales = { tintR, tintG, tintB };
@@ -1361,16 +1389,17 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
// RescaleOp op = new RescaleOp(scales, offsets, null);
// op.filter(image, image);
- } else if (bufferType == BufferedImage.TYPE_INT_ARGB) {
+ //} else if (bufferType == BufferedImage.TYPE_INT_ARGB) {
+ } else if (targetType == ARGB) {
if (source.format == RGB &&
(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++) {
- tintedPixels[x] = hi | (source.pixels[index++] & 0xFFFFFF);
+ tintedTemp[x] = hi | (source.pixels[index++] & 0xFFFFFF);
}
- wr.setDataElements(0, y, source.width, 1, tintedPixels);
+ wr.setDataElements(0, y, source.width, 1, tintedTemp);
}
} else {
int index = 0;
@@ -1382,7 +1411,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
int r1 = (argb1 >> 16) & 0xff;
int g1 = (argb1 >> 8) & 0xff;
int b1 = (argb1) & 0xff;
- tintedPixels[x] = alpha |
+ tintedTemp[x] = alpha |
(((r2 * r1) & 0xff00) << 8) |
((g2 * g1) & 0xff00) |
(((b2 * b1) & 0xff00) >> 8);
@@ -1394,7 +1423,7 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
int r1 = (argb1 >> 16) & 0xff;
int g1 = (argb1 >> 8) & 0xff;
int b1 = (argb1) & 0xff;
- tintedPixels[x] =
+ tintedTemp[x] =
(((a2 * a1) & 0xff00) << 16) |
(((r2 * r1) & 0xff00) << 8) |
((g2 * g1) & 0xff00) |
@@ -1404,11 +1433,11 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
int lower = tintColor & 0xFFFFFF;
for (int x = 0; x < source.width; x++) {
int a1 = source.pixels[index++];
- tintedPixels[x] =
+ tintedTemp[x] =
(((a2 * a1) & 0xff00) << 16) | lower;
}
}
- wr.setDataElements(0, y, source.width, 1, tintedPixels);
+ wr.setDataElements(0, y, source.width, 1, tintedTemp);
}
}
// Not sure why ARGB images take the scales in this order...
@@ -1417,7 +1446,17 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
// RescaleOp op = new RescaleOp(scales, offsets, null);
// op.filter(image, image);
}
- } else {
+ } 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);
}
this.tinted = tint;
@@ -2288,18 +2327,32 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
protected WritableRaster getRaster() {
+ WritableRaster raster = null;
if (primarySurface) {
// 'offscreen' will probably be removed in the next release
if (useOffscreen) {
- return ((BufferedImage) offscreen).getRaster();
- }
- // when possible, we'll try VolatileImage
- if (image instanceof VolatileImage) {
- return ((VolatileImage) image).getSnapshot().getRaster();
+ raster = ((BufferedImage) offscreen).getRaster();
+ } else if (image instanceof VolatileImage) {
+ // when possible, we'll try VolatileImage
+ raster = ((VolatileImage) image).getSnapshot().getRaster();
}
}
- return ((BufferedImage) image).getRaster();
- //((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster();
+ if (raster == null) {
+ raster = ((BufferedImage) image).getRaster();
+ }
+
+ // On Raspberry Pi (and perhaps other platforms, the color buffer won't
+ // necessarily be the int array that we'd like. Need to convert it here.
+ // Not that this would probably mean getRaster() would need to work more
+ // like loadRaster/updateRaster because the pixels will need to be
+ // temporarily moved to (and later from) a buffer that's understood by
+ // the rest of the Processing source.
+ // https://github.com/processing/processing/issues/2010
+ if (raster.getTransferType() != DataBuffer.TYPE_INT) {
+ System.err.println("See https://github.com/processing/processing/issues/2010");
+ throw new RuntimeException("Pixel operations are not supported on this device.");
+ }
+ return raster;
}
@@ -2308,10 +2361,19 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
if ((pixels == null) || (pixels.length != width * height)) {
pixels = new int[width * height];
}
- //((BufferedImage) image).getRGB(0, 0, width, height, pixels, 0, width);
+
+ WritableRaster raster = getRaster();
+ raster.getDataElements(0, 0, width, height, pixels);
+ if (raster.getNumBands() == 3) {
+ // Java won't set the high bits when RGB, returns 0 for alpha
+ // https://github.com/processing/processing/issues/2030
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = 0xff000000 | pixels[i];
+ }
+ }
+ //((BufferedImage) image).getRGB(0, 0, width, height, pixels, 0, width);
// WritableRaster raster = ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster();
// WritableRaster raster = image.getRaster();
- getRaster().getDataElements(0, 0, width, height, pixels);
}
@@ -2377,8 +2439,12 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return 0;
//return ((BufferedImage) image).getRGB(x, y);
// WritableRaster raster = ((BufferedImage) (useOffscreen && primarySurface ? offscreen : image)).getRaster();
-// WritableRaster raster = image.getRaster();
- getRaster().getDataElements(x, y, getset);
+ WritableRaster raster = getRaster();
+ raster.getDataElements(x, y, getset);
+ if (raster.getNumBands() == 3) {
+ // https://github.com/processing/processing/issues/2030
+ return getset[0] | 0xff000000;
+ }
return getset[0];
}
@@ -2404,6 +2470,10 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
if (sourceWidth == target.width && sourceHeight == target.height) {
raster.getDataElements(sourceX, sourceY, sourceWidth, sourceHeight, target.pixels);
+ // https://github.com/processing/processing/issues/2030
+ if (raster.getNumBands() == 3) {
+ target.filter(OPAQUE);
+ }
} else {
// TODO optimize, incredibly inefficient to reallocate this much memory
@@ -2414,7 +2484,15 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
int sourceOffset = 0;
int targetOffset = targetY*target.width + targetX;
for (int y = 0; y < sourceHeight; y++) {
- System.arraycopy(temp, sourceOffset, target.pixels, targetOffset, sourceWidth);
+ if (raster.getNumBands() == 3) {
+ for (int i = 0; i < sourceWidth; i++) {
+ // Need to set the high bits for this feller
+ // https://github.com/processing/processing/issues/2030
+ target.pixels[targetOffset + i] = 0xFF000000 | temp[sourceOffset + i];
+ }
+ } else {
+ System.arraycopy(temp, sourceOffset, target.pixels, targetOffset, sourceWidth);
+ }
sourceOffset += sourceWidth;
targetOffset += target.width;
}
diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java
index 153c5fe47..e3994c91e 100644
--- a/core/src/processing/core/PImage.java
+++ b/core/src/processing/core/PImage.java
@@ -54,7 +54,7 @@ import javax.imageio.metadata.*;
*
* @webref image
* @usage Web & Application
- * @instanceName img any object of type PImage
+ * @instanceName pimg any object of type PImage
* @see PApplet#loadImage(String)
* @see PApplet#imageMode(int)
* @see PApplet#createImage(int, int, int)
diff --git a/core/src/processing/core/PMatrix.java b/core/src/processing/core/PMatrix.java
index 53f7fa54b..2670eb5ce 100644
--- a/core/src/processing/core/PMatrix.java
+++ b/core/src/processing/core/PMatrix.java
@@ -97,6 +97,8 @@ public interface PMatrix {
/**
* Apply another matrix to the left of this one.
*/
+ public void preApply(PMatrix left);
+
public void preApply(PMatrix2D left);
public void preApply(PMatrix3D left);
diff --git a/core/src/processing/core/PMatrix2D.java b/core/src/processing/core/PMatrix2D.java
index d5616b58d..1ee6b0a88 100644
--- a/core/src/processing/core/PMatrix2D.java
+++ b/core/src/processing/core/PMatrix2D.java
@@ -247,6 +247,15 @@ public class PMatrix2D implements PMatrix {
/**
* Apply another matrix to the left of this one.
*/
+ public void preApply(PMatrix source) {
+ if (source instanceof PMatrix2D) {
+ preApply((PMatrix2D) source);
+ } else if (source instanceof PMatrix3D) {
+ preApply((PMatrix3D) source);
+ }
+ }
+
+
public void preApply(PMatrix2D left) {
preApply(left.m00, left.m01, left.m02,
left.m10, left.m11, left.m12);
diff --git a/core/src/processing/core/PMatrix3D.java b/core/src/processing/core/PMatrix3D.java
index deeb23b45..f75cb1227 100644
--- a/core/src/processing/core/PMatrix3D.java
+++ b/core/src/processing/core/PMatrix3D.java
@@ -369,6 +369,15 @@ public final class PMatrix3D implements PMatrix /*, PConstants*/ {
/**
* Apply another matrix to the left of this one.
*/
+ public void preApply(PMatrix source) {
+ if (source instanceof PMatrix2D) {
+ preApply((PMatrix2D) source);
+ } else if (source instanceof PMatrix3D) {
+ preApply((PMatrix3D) source);
+ }
+ }
+
+
public void preApply(PMatrix3D left) {
preApply(left.m00, left.m01, left.m02, left.m03,
left.m10, left.m11, left.m12, left.m13,
diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java
index e5eaa28fd..8420f72f6 100644
--- a/core/src/processing/core/PShape.java
+++ b/core/src/processing/core/PShape.java
@@ -166,6 +166,10 @@ public class PShape implements PConstants {
protected int emissiveColor;
protected float shininess;
+ protected int sphereDetailU, sphereDetailV;
+ protected int rectMode;
+ protected int ellipseMode;
+
/** Temporary toggle for whether styles should be honored. */
protected boolean style = true;
@@ -510,10 +514,12 @@ public class PShape implements PConstants {
image = null;
}
+
// TODO unapproved
protected void solid(boolean solid) {
}
+
/**
* @webref shape:vertex
* @brief Starts a new contour
@@ -535,8 +541,18 @@ public class PShape implements PConstants {
return;
}
openContour = true;
+ beginContourImpl();
}
+
+ protected void beginContourImpl() {
+ if (vertexCodes.length == vertexCodeCount) {
+ vertexCodes = PApplet.expand(vertexCodes);
+ }
+ vertexCodes[vertexCodeCount++] = BREAK;
+ }
+
+
/**
* @webref shape:vertex
* @brief Ends a contour
@@ -557,28 +573,64 @@ public class PShape implements PConstants {
PGraphics.showWarning("Need to call beginContour() first.");
return;
}
+ endContourImpl();
openContour = false;
}
- public void vertex(float x, float y) {
+
+ protected void endContourImpl() {
}
+
+ public void vertex(float x, float y) {
+ if (vertices == null) {
+ vertices = new float[10][2];
+ } else if (vertices.length == vertexCount) {
+ vertices = (float[][]) PApplet.expand(vertices);
+ }
+ vertices[vertexCount++] = new float[] { x, y };
+
+ if (vertexCodes == null) {
+ vertexCodes = new int[10];
+ } else if (vertexCodes.length == vertexCodeCount) {
+ vertexCodes = PApplet.expand(vertexCodes);
+ }
+ vertexCodes[vertexCodeCount++] = VERTEX;
+
+ if (x > width) {
+ width = x;
+ }
+ if (y > height) {
+ height = y;
+ }
+ }
+
+
public void vertex(float x, float y, float u, float v) {
}
+
public void vertex(float x, float y, float z) {
}
+
public void vertex(float x, float y, float z, float u, float v) {
}
+
public void normal(float nx, float ny, float nz) {
}
+ /**
+ * @webref pshape:method
+ * @brief Starts the creation of a new PShape
+ * @see PApplet#endShape()
+ */
public void beginShape() {
beginShape(POLYGON);
}
+
public void beginShape(int kind) {
this.kind = kind;
openShape = true;
@@ -587,12 +639,13 @@ public class PShape implements PConstants {
/**
* @webref pshape:method
* @brief Finishes the creation of a new PShape
- * @see PApplet#createShape()
+ * @see PApplet#beginShape()
*/
public void endShape() {
endShape(OPEN);
}
+
public void endShape(int mode) {
if (family == GROUP) {
PGraphics.showWarning("Cannot end GROUP shape");
@@ -1073,24 +1126,70 @@ public class PShape implements PConstants {
public void bezierDetail(int detail) {
}
+
public void bezierVertex(float x2, float y2,
float x3, float y3,
float x4, float y4) {
+ if (vertices == null) {
+ vertices = new float[10][];
+ } else if (vertexCount + 2 >= vertices.length) {
+ vertices = (float[][]) PApplet.expand(vertices);
+ }
+ vertices[vertexCount++] = new float[] { x2, y2 };
+ vertices[vertexCount++] = new float[] { x3, y3 };
+ vertices[vertexCount++] = new float[] { x4, y4 };
+
+ // vertexCodes must be allocated because a vertex() call is required
+ if (vertexCodes.length == vertexCodeCount) {
+ vertexCodes = PApplet.expand(vertexCodes);
+ }
+ vertexCodes[vertexCodeCount++] = BEZIER_VERTEX;
+
+ if (x4 > width) {
+ width = x4;
+ }
+ if (y4 > height) {
+ height = y4;
+ }
}
+
public void bezierVertex(float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4) {
}
+
public void quadraticVertex(float cx, float cy,
float x3, float y3) {
+ if (vertices == null) {
+ vertices = new float[10][];
+ } else if (vertexCount + 1 >= vertices.length) {
+ vertices = (float[][]) PApplet.expand(vertices);
+ }
+ vertices[vertexCount++] = new float[] { cx, cy };
+ vertices[vertexCount++] = new float[] { x3, y3 };
+
+ // vertexCodes must be allocated because a vertex() call is required
+ if (vertexCodes.length == vertexCodeCount) {
+ vertexCodes = PApplet.expand(vertexCodes);
+ }
+ vertexCodes[vertexCodeCount++] = QUADRATIC_VERTEX;
+
+ if (x3 > width) {
+ width = x3;
+ }
+ if (y3 > height) {
+ height = y3;
+ }
}
+
public void quadraticVertex(float cx, float cy, float cz,
float x3, float y3, float z3) {
}
+
///////////////////////////////////////////////////////////
//
@@ -1550,23 +1649,12 @@ public class PShape implements PConstants {
case VERTEX:
g.vertex(vertices[index][X], vertices[index][Y]);
-// cx = vertices[index][X];
-// cy = vertices[index][Y];
index++;
break;
- case QUAD_BEZIER_VERTEX:
+ case QUADRATIC_VERTEX:
g.quadraticVertex(vertices[index+0][X], vertices[index+0][Y],
- vertices[index+1][X], vertices[index+1][Y]);
-// float x1 = vertices[index+0][X];
-// float y1 = vertices[index+0][Y];
-// float x2 = vertices[index+1][X];
-// float y2 = vertices[index+1][Y];
-// g.bezierVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f),
-// x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f),
-// x2, y2);
-// cx = vertices[index+1][X];
-// cy = vertices[index+1][Y];
+ vertices[index+1][X], vertices[index+1][Y]);
index += 2;
break;
@@ -1574,8 +1662,6 @@ public class PShape implements PConstants {
g.bezierVertex(vertices[index+0][X], vertices[index+0][Y],
vertices[index+1][X], vertices[index+1][Y],
vertices[index+2][X], vertices[index+2][Y]);
-// cx = vertices[index+2][X];
-// cy = vertices[index+2][Y];
index += 3;
break;
@@ -1598,13 +1684,10 @@ public class PShape implements PConstants {
case VERTEX:
g.vertex(vertices[index][X], vertices[index][Y], vertices[index][Z]);
-// cx = vertices[index][X];
-// cy = vertices[index][Y];
-// cz = vertices[index][Z];
index++;
break;
- case QUAD_BEZIER_VERTEX:
+ case QUADRATIC_VERTEX:
g.quadraticVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z],
vertices[index+1][X], vertices[index+1][Y], vertices[index+0][Z]);
index += 2;
@@ -1904,6 +1987,7 @@ public class PShape implements PConstants {
return getVertex(index, null);
}
+
/**
* @param vec PVector to assign the data to
*/
@@ -1911,9 +1995,14 @@ public class PShape implements PConstants {
if (vec == null) {
vec = new PVector();
}
- vec.x = vertices[index][X];
- vec.y = vertices[index][Y];
- vec.z = vertices[index][Z];
+ float[] vert = vertices[index];
+ vec.x = vert[X];
+ vec.y = vert[Y];
+ if (vert.length > 2) {
+ vec.z = vert[Z];
+ } else {
+ vec.z = 0; // in case this isn't a new vector
+ }
return vec;
}
diff --git a/core/src/processing/core/PShapeOBJ.java b/core/src/processing/core/PShapeOBJ.java
index 0296bc1ba..c64031cc5 100644
--- a/core/src/processing/core/PShapeOBJ.java
+++ b/core/src/processing/core/PShapeOBJ.java
@@ -1,6 +1,7 @@
package processing.core;
import java.io.BufferedReader;
+import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
@@ -22,17 +23,21 @@ public class PShapeOBJ extends PShape {
* Initializes a new OBJ Object with the given filename.
*/
public PShapeOBJ(PApplet parent, String filename) {
- this(parent, parent.createReader(filename));
+ this(parent, parent.createReader(filename), getBasePath(parent, filename));
}
-
public PShapeOBJ(PApplet parent, BufferedReader reader) {
+ this(parent, reader, "");
+ }
+
+ public PShapeOBJ(PApplet parent, BufferedReader reader, String basePath) {
ArrayList faces = new ArrayList();
ArrayList materials = new ArrayList();
ArrayList coords = new ArrayList();
ArrayList normals = new ArrayList();
ArrayList texcoords = new ArrayList();
- parseOBJ(parent, reader, faces, materials, coords, normals, texcoords);
+ parseOBJ(parent, basePath, reader,
+ faces, materials, coords, normals, texcoords);
// The OBJ geometry is stored with each face in a separate child shape.
parent = null;
@@ -147,7 +152,7 @@ public class PShapeOBJ extends PShape {
}
- static protected void parseOBJ(PApplet parent,
+ static protected void parseOBJ(PApplet parent, String path,
BufferedReader reader,
ArrayList faces,
ArrayList materials,
@@ -218,9 +223,14 @@ public class PShapeOBJ extends PShape {
// Object name is ignored, for now.
} else if (parts[0].equals("mtllib")) {
if (parts[1] != null) {
- BufferedReader mreader = parent.createReader(parts[1]);
+ String fn = parts[1];
+ if (fn.indexOf(File.separator) == -1 && !path.equals("")) {
+ // Relative file name, adding the base path.
+ fn = path + File.separator + fn;
+ }
+ BufferedReader mreader = parent.createReader(fn);
if (mreader != null) {
- parseMTL(parent, mreader, materials, mtlTable);
+ parseMTL(parent, path, mreader, materials, mtlTable);
}
}
} else if (parts[0].equals("g")) {
@@ -308,7 +318,7 @@ public class PShapeOBJ extends PShape {
}
- static protected void parseMTL(PApplet parent,
+ static protected void parseMTL(PApplet parent, String path,
BufferedReader reader,
ArrayList materials,
Hashtable materialsHash) {
@@ -330,6 +340,10 @@ public class PShapeOBJ extends PShape {
} else if (parts[0].equals("map_Kd") && parts.length > 1) {
// Loading texture map.
String texname = parts[1];
+ if (texname.indexOf(File.separator) == -1 && !path.equals("")) {
+ // Relative file name, adding the base path.
+ texname = path + File.separator + texname;
+ }
currentMtl.kdMap = parent.loadImage(texname);
} else if (parts[0].equals("Ka") && parts.length > 3) {
// The ambient color of the material
@@ -395,6 +409,18 @@ public class PShapeOBJ extends PShape {
}
+ static protected String getBasePath(PApplet parent, String filename) {
+ // Obtaining the path
+ File file = new File(parent.dataPath(filename));
+ if (!file.exists()) {
+ file = parent.sketchFile(filename);
+ }
+ String absolutePath = file.getAbsolutePath();
+ return absolutePath.substring(0,
+ absolutePath.lastIndexOf(File.separator));
+ }
+
+
// Stores a material defined in an MTL file.
static protected class OBJMaterial {
String name;
diff --git a/core/src/processing/core/PShapeSVG.java b/core/src/processing/core/PShapeSVG.java
index 671114ee5..1be0b30d6 100644
--- a/core/src/processing/core/PShapeSVG.java
+++ b/core/src/processing/core/PShapeSVG.java
@@ -915,7 +915,7 @@ public class PShapeSVG extends PShape {
float x2, float y2) {
//System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
// parsePathCode(BEZIER_VERTEX);
- parsePathCode(QUAD_BEZIER_VERTEX);
+ parsePathCode(QUADRATIC_VERTEX);
// x1/y1 already covered by last moveto, lineto, or curveto
parsePathVertex(cx, cy);
parsePathVertex(x2, y2);
diff --git a/core/src/processing/core/PVector.java b/core/src/processing/core/PVector.java
index 725c208b1..ca25eb1db 100644
--- a/core/src/processing/core/PVector.java
+++ b/core/src/processing/core/PVector.java
@@ -926,9 +926,9 @@ public class PVector implements Serializable {
static public float angleBetween(PVector v1, PVector v2) {
// We get NaN if we pass in a zero vector which can cause problems
- // Zero seems like a reasonable angle between a (0,0) vector and something else
- if (v1.x == 0 && v1.y == 0) return 0.0f;
- if (v2.x == 0 && v2.y == 0) return 0.0f;
+ // Zero seems like a reasonable angle between a (0,0,0) vector and something else
+ if (v1.x == 0 && v1.y == 0 && v1.z == 0 ) return 0.0f;
+ if (v2.x == 0 && v2.y == 0 && v2.z == 0 ) return 0.0f;
double dot = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
double v1mag = Math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z);
@@ -994,4 +994,4 @@ public class PVector implements Serializable {
result = 31 * result + Float.floatToIntBits(z);
return result;
}
-}
\ No newline at end of file
+}
diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java
index 7207a179a..794ca2713 100644
--- a/core/src/processing/data/FloatDict.java
+++ b/core/src/processing/data/FloatDict.java
@@ -427,6 +427,7 @@ public class FloatDict {
* @webref floatlist:method
* @brief Return the largest value
*/
+ // The index of the entry that has the max value. Reference above is incorrect.
public int maxIndex() {
checkMinMax("maxIndex");
// Will still return NaN if there is 1 or more entries, and they're all NaN
@@ -453,12 +454,14 @@ public class FloatDict {
}
+ /** The key for a max value. */
public String maxKey() {
checkMinMax("maxKey");
return keys[maxIndex()];
}
+ /** The max value. */
public float maxValue() {
checkMinMax("maxValue");
return values[maxIndex()];
@@ -515,7 +518,7 @@ public class FloatDict {
}
- protected void swap(int a, int b) {
+ public void swap(int a, int b) {
String tkey = keys[a];
float tvalue = values[a];
keys[a] = keys[b];
@@ -680,6 +683,25 @@ public class FloatDict {
}
+ /**
+ * Sum all of the values in this dictionary, then return a new FloatDict of
+ * each key, divided by the total sum. The total for all values will be ~1.0.
+ * @return a Dict with the original keys, mapped to their pct of the total
+ */
+ public FloatDict getPercent() {
+ double sum = 0;
+ for (float value : valueArray()) {
+ sum += value;
+ }
+ FloatDict outgoing = new FloatDict();
+ for (int i = 0; i < size(); i++) {
+ double percent = value(i) / sum;
+ outgoing.set(key(i), (float) percent);
+ }
+ return outgoing;
+ }
+
+
/** Returns a duplicate copy of this object. */
public FloatDict copy() {
FloatDict outgoing = new FloatDict(count);
diff --git a/core/src/processing/data/FloatList.java b/core/src/processing/data/FloatList.java
index e386c9303..9921cb326 100644
--- a/core/src/processing/data/FloatList.java
+++ b/core/src/processing/data/FloatList.java
@@ -16,6 +16,8 @@ import processing.core.PApplet;
* a sorted copy, use list.copy().sort().
*
* @webref data:composite
+ * @see IntList
+ * @see StringList
*/
public class FloatList implements Iterable {
int count;
@@ -299,7 +301,7 @@ public class FloatList implements Iterable {
if (index < 0) {
throw new IllegalArgumentException("insert() index cannot be negative: it was " + index);
}
- if (index >= values.length) {
+ if (index >= data.length) {
throw new IllegalArgumentException("insert() index " + index + " is past the end of this list");
}
@@ -531,6 +533,15 @@ public class FloatList implements Iterable {
}
+ public float sum() {
+ double outgoing = 0;
+ for (int i = 0; i < count; i++) {
+ outgoing += data[i];
+ }
+ return (float) outgoing;
+ }
+
+
/**
* Sorts the array in place.
*
@@ -575,17 +586,18 @@ public class FloatList implements Iterable {
// }
- public void subset(int start) {
- subset(start, count - start);
- }
+// public void subset(int start) {
+// subset(start, count - start);
+// }
- public void subset(int start, int num) {
- for (int i = 0; i < num; i++) {
- data[i] = data[i+start];
- }
- count = num;
- }
+// public void subset(int start, int num) {
+// for (int i = 0; i < num; i++) {
+// data[i] = data[i+start];
+// }
+// count = num;
+// }
+
/**
* @webref floatlist:method
@@ -705,6 +717,52 @@ public class FloatList implements Iterable {
}
+ /**
+ * Returns a normalized version of this array. Called getPercent() for
+ * consistency with the Dict classes. It's a getter method because it needs
+ * to returns a new list (because IntList/Dict can't do percentages or
+ * normalization in place on int values).
+ */
+ public FloatList getPercent() {
+ double sum = 0;
+ for (float value : array()) {
+ sum += value;
+ }
+ FloatList outgoing = new FloatList(count);
+ for (int i = 0; i < count; i++) {
+ double percent = data[i] / sum;
+ outgoing.set(i, (float) percent);
+ }
+ return outgoing;
+ }
+
+
+ public FloatList getSubset(int start) {
+ return getSubset(start, count - start);
+ }
+
+
+ public FloatList getSubset(int start, int num) {
+ float[] subset = new float[num];
+ System.arraycopy(data, start, subset, 0, num);
+ return new FloatList(subset);
+ }
+
+
+ public String join(String separator) {
+ if (count == 0) {
+ return "";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(data[0]);
+ for (int i = 1; i < count; i++) {
+ sb.append(separator);
+ sb.append(data[i]);
+ }
+ return sb.toString();
+ }
+
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -718,4 +776,4 @@ public class FloatList implements Iterable {
sb.append(" ]");
return sb.toString();
}
-}
\ No newline at end of file
+}
diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java
index 23e4fc48f..44efea215 100644
--- a/core/src/processing/data/IntDict.java
+++ b/core/src/processing/data/IntDict.java
@@ -88,6 +88,7 @@ public class IntDict {
if (pieces.length == 2) {
keys[count] = pieces[0];
values[count] = PApplet.parseInt(pieces[1]);
+ indices.put(pieces[0], count);
count++;
}
}
@@ -470,7 +471,7 @@ public class IntDict {
}
- // return the key for the maximum value
+ // return the key corresponding to the maximum value
public String maxKey() {
checkMinMax("maxKey");
return keys[maxIndex()];
@@ -526,7 +527,7 @@ public class IntDict {
}
- protected void swap(int a, int b) {
+ public void swap(int a, int b) {
String tkey = keys[a];
int tvalue = values[a];
keys[a] = keys[b];
@@ -621,6 +622,25 @@ public class IntDict {
}
+ /**
+ * Sum all of the values in this dictionary, then return a new FloatDict of
+ * each key, divided by the total sum. The total for all values will be ~1.0.
+ * @return a Dict with the original keys, mapped to their pct of the total
+ */
+ public FloatDict getPercent() {
+ double sum = 0;
+ for (int value : valueArray()) {
+ sum += value;
+ }
+ FloatDict outgoing = new FloatDict();
+ for (int i = 0; i < size(); i++) {
+ double percent = value(i) / sum;
+ outgoing.set(key(i), (float) percent);
+ }
+ return outgoing;
+ }
+
+
/** Returns a duplicate copy of this object. */
public IntDict copy() {
IntDict outgoing = new IntDict(count);
diff --git a/core/src/processing/data/IntList.java b/core/src/processing/data/IntList.java
index 1c1e81569..1b8860fcc 100644
--- a/core/src/processing/data/IntList.java
+++ b/core/src/processing/data/IntList.java
@@ -21,6 +21,8 @@ import processing.core.PApplet;
* a sorted copy, use list.copy().sort().
*
* @webref data:composite
+ * @see FloatList
+ * @see StringList
*/
public class IntList implements Iterable {
protected int count;
@@ -58,6 +60,21 @@ public class IntList implements Iterable {
}
+ static public IntList fromRange(int stop) {
+ return fromRange(0, stop);
+ }
+
+
+ static public IntList fromRange(int start, int stop) {
+ int count = stop - start;
+ IntList newbie = new IntList(count);
+ for (int i = 0; i < count; i++) {
+ newbie.set(i, start+i);
+ }
+ return newbie;
+ }
+
+
/**
* Improve efficiency by removing allocated but unused entries from the
* internal array used to store the data. Set to private, though it could
@@ -74,7 +91,7 @@ public class IntList implements Iterable {
/**
* Get the length of the list.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Get the length of the list
*/
public int size() {
@@ -98,7 +115,7 @@ public class IntList implements Iterable {
/**
* Remove all entries from the list.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Remove all entries from the list
*/
public void clear() {
@@ -109,7 +126,7 @@ public class IntList implements Iterable {
/**
* Get an entry at a particular index.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Get an entry at a particular index
*/
public int get(int index) {
@@ -122,7 +139,7 @@ public class IntList implements Iterable {
* the list, it'll expand the list to accommodate, and fill the intermediate
* entries with 0s.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Set the entry at a particular index
*/
public void set(int index, int what) {
@@ -140,7 +157,7 @@ public class IntList implements Iterable {
/**
* Remove an element from the specified index
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Remove an element from the specified index
*/
public int remove(int index) {
@@ -193,7 +210,7 @@ public class IntList implements Iterable {
/**
* Add a new entry to the list.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Add a new entry to the list
*/
public void append(int value) {
@@ -253,7 +270,7 @@ public class IntList implements Iterable {
if (index < 0) {
throw new IllegalArgumentException("insert() index cannot be negative: it was " + index);
}
- if (index >= values.length) {
+ if (index >= data.length) {
throw new IllegalArgumentException("insert() index " + index + " is past the end of this list");
}
@@ -355,7 +372,7 @@ public class IntList implements Iterable {
// }
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Check if a number is a part of the list
*/
public boolean hasValue(int value) {
@@ -372,15 +389,18 @@ public class IntList implements Iterable {
}
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Add one to a value
*/
public void increment(int index) {
+ if (count <= index) {
+ resize(index + 1);
+ }
data[index]++;
}
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Add to a value
*/
public void add(int index, int amount) {
@@ -388,7 +408,7 @@ public class IntList implements Iterable {
}
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Subtract from a value
*/
public void sub(int index, int amount) {
@@ -396,7 +416,7 @@ public class IntList implements Iterable {
}
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Multiply a value
*/
public void mult(int index, int amount) {
@@ -404,7 +424,7 @@ public class IntList implements Iterable {
}
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Divide a value
*/
public void div(int index, int amount) {
@@ -423,7 +443,7 @@ public class IntList implements Iterable {
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Return the smallest value
*/
public int min() {
@@ -453,7 +473,7 @@ public class IntList implements Iterable {
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Return the largest value
*/
public int max() {
@@ -482,10 +502,19 @@ public class IntList implements Iterable {
}
+ public int sum() {
+ int outgoing = 0;
+ for (int i = 0; i < count; i++) {
+ outgoing += data[i];
+ }
+ return outgoing;
+ }
+
+
/**
* Sorts the array in place.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Sorts the array, lowest to highest
*/
public void sort() {
@@ -496,7 +525,7 @@ public class IntList implements Iterable {
/**
* Reverse sort, orders values from highest to lowest.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Reverse sort, orders values from highest to lowest
*/
public void sortReverse() {
@@ -539,7 +568,7 @@ public class IntList implements Iterable {
// }
/**
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Reverse sort, orders values by first digit
*/
public void reverse() {
@@ -557,7 +586,7 @@ public class IntList implements Iterable {
* Randomize the order of the list elements. Note that this does not
* obey the randomSeed() function in PApplet.
*
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Randomize the order of the list elements
*/
public void shuffle() {
@@ -632,7 +661,7 @@ public class IntList implements Iterable {
* Create a new array with a copy of all the values.
*
* @return an array sized by the length of the list with each of the values.
- * @webref floatlist:method
+ * @webref intlist:method
* @brief Create a new array with a copy of all the values
*/
public int[] array() {
@@ -696,17 +725,49 @@ public class IntList implements Iterable {
// }
+ /**
+ * Returns a normalized version of this array. Called getPercent() for
+ * consistency with the Dict classes. It's a getter method because it needs
+ * to returns a new list (because IntList/Dict can't do percentages or
+ * normalization in place on int values).
+ */
+ public FloatList getPercent() {
+ double sum = 0;
+ for (float value : array()) {
+ sum += value;
+ }
+ FloatList outgoing = new FloatList(count);
+ for (int i = 0; i < count; i++) {
+ double percent = data[i] / sum;
+ outgoing.set(i, (float) percent);
+ }
+ return outgoing;
+ }
+
+
public IntList getSubset(int start) {
return getSubset(start, count - start);
}
public IntList getSubset(int start, int num) {
- IntList outgoing = new IntList(num);
- for (int i = 0; i < num; i++) {
- System.arraycopy(data, start, outgoing.data, 0, num);
+ int[] subset = new int[num];
+ System.arraycopy(data, start, subset, 0, num);
+ return new IntList(subset);
+ }
+
+
+ public String join(String separator) {
+ if (count == 0) {
+ return "";
}
- return outgoing;
+ StringBuilder sb = new StringBuilder();
+ sb.append(data[0]);
+ for (int i = 1; i < count; i++) {
+ sb.append(separator);
+ sb.append(data[i]);
+ }
+ return sb.toString();
}
@@ -723,4 +784,4 @@ public class IntList implements Iterable {
sb.append(" ]");
return sb.toString();
}
-}
\ No newline at end of file
+}
diff --git a/core/src/processing/data/JSONArray.java b/core/src/processing/data/JSONArray.java
index 75d39eba8..0e665c805 100644
--- a/core/src/processing/data/JSONArray.java
+++ b/core/src/processing/data/JSONArray.java
@@ -294,6 +294,20 @@ public class JSONArray {
}
+ /**
+ * Get the optional string associated with an index.
+ * The defaultValue is returned if the key is not found.
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return A String value.
+ */
+ public String getString(int index, String defaultValue) {
+ Object object = this.opt(index);
+ return JSONObject.NULL.equals(object) ? defaultValue : object.toString();
+ }
+
+
/**
* Get the int value associated with an index.
*
@@ -318,6 +332,23 @@ public class JSONArray {
}
+ /**
+ * Get the optional int value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public int getInt(int index, int defaultValue) {
+ try {
+ return getInt(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the long value associated with an index.
*
@@ -338,10 +369,27 @@ public class JSONArray {
}
+ /**
+ * Get the optional long value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public long getLong(int index, long defaultValue) {
+ try {
+ return this.getLong(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get a value from an index as a float. JSON uses 'double' values
* internally, so this is simply getDouble() cast to a float.
- *
+ *
* @webref jsonarray:method
* @brief Gets the float value associated with an index
* @param index must be between 0 and length() - 1
@@ -354,6 +402,15 @@ public class JSONArray {
}
+ public float getFloat(int index, float defaultValue) {
+ try {
+ return getFloat(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the double value associated with an index.
*
@@ -374,6 +431,24 @@ public class JSONArray {
}
+ /**
+ * Get the optional double value associated with an index.
+ * The defaultValue is returned if there is no value for the index,
+ * or if the value is not a number and cannot be converted to a number.
+ *
+ * @param index subscript
+ * @param defaultValue The default value.
+ * @return The value.
+ */
+ public double getDouble(int index, double defaultValue) {
+ try {
+ return this.getDouble(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the boolean value associated with an index.
* The string values "true" and "false" are converted to boolean.
@@ -403,9 +478,27 @@ public class JSONArray {
}
+ /**
+ * Get the optional boolean value associated with an index.
+ * It returns the defaultValue if there is no value at that index or if
+ * it is not a Boolean or the String "true" or "false" (case insensitive).
+ *
+ * @param index The index must be between 0 and length() - 1.
+ * @param defaultValue A boolean default.
+ * @return The truth.
+ */
+ public boolean getBoolean(int index, boolean defaultValue) {
+ try {
+ return getBoolean(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the JSONArray associated with an index.
- *
+ *
* @webref jsonobject:method
* @brief Gets the JSONArray associated with an index value
* @param index must be between 0 and length() - 1
@@ -425,9 +518,18 @@ public class JSONArray {
}
+ public JSONArray getJSONArray(int index, JSONArray defaultValue) {
+ try {
+ return getJSONArray(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the JSONObject associated with an index.
- *
+ *
* @webref jsonobject:method
* @brief Gets the JSONObject associated with an index value
* @param index the index value of the object to get
@@ -447,9 +549,18 @@ public class JSONArray {
}
- /**
- * Get this entire array as a String array.
- *
+ public JSONObject getJSONObject(int index, JSONObject defaultValue) {
+ try {
+ return getJSONObject(index);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
+ /**
+ * Get this entire array as a String array.
+ *
* @webref jsonarray:method
* @brief Gets the entire array as an array of Strings
* @see JSONArray#getIntArray()
@@ -463,9 +574,9 @@ public class JSONArray {
}
- /**
- * Get this entire array as an int array. Everything must be an int.
- *
+ /**
+ * Get this entire array as an int array. Everything must be an int.
+ *
* @webref jsonarray:method
* @brief Gets the entire array as array of ints
* @see JSONArray#getStringArray()
@@ -533,24 +644,6 @@ public class JSONArray {
//
//
// /**
-// * Get the optional boolean value associated with an index.
-// * It returns the defaultValue if there is no value at that index or if
-// * it is not a Boolean or the String "true" or "false" (case insensitive).
-// *
-// * @param index The index must be between 0 and length() - 1.
-// * @param defaultValue A boolean default.
-// * @return The truth.
-// */
-// public boolean optBoolean(int index, boolean defaultValue) {
-// try {
-// return this.getBoolean(index);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-//
-//
-// /**
// * Get the optional double value associated with an index.
// * NaN is returned if there is no value for the index,
// * or if the value is not a number and cannot be converted to a number.
@@ -564,24 +657,6 @@ public class JSONArray {
//
//
// /**
-// * Get the optional double value associated with an index.
-// * The defaultValue is returned if there is no value for the index,
-// * or if the value is not a number and cannot be converted to a number.
-// *
-// * @param index subscript
-// * @param defaultValue The default value.
-// * @return The value.
-// */
-// public double optDouble(int index, double defaultValue) {
-// try {
-// return this.getDouble(index);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-//
-//
-// /**
// * Get the optional int value associated with an index.
// * Zero is returned if there is no value for the index,
// * or if the value is not a number and cannot be converted to a number.
@@ -595,49 +670,6 @@ public class JSONArray {
//
//
// /**
-// * Get the optional int value associated with an index.
-// * The defaultValue is returned if there is no value for the index,
-// * or if the value is not a number and cannot be converted to a number.
-// * @param index The index must be between 0 and length() - 1.
-// * @param defaultValue The default value.
-// * @return The value.
-// */
-// public int optInt(int index, int defaultValue) {
-// try {
-// return this.getInt(index);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-//
-//
-// /**
-// * Get the optional JSONArray associated with an index.
-// * @param index subscript
-// * @return A JSONArray value, or null if the index has no value,
-// * or if the value is not a JSONArray.
-// */
-// public JSONArray optJSONArray(int index) {
-// Object o = this.opt(index);
-// return o instanceof JSONArray ? (JSONArray)o : null;
-// }
-//
-//
-// /**
-// * Get the optional JSONObject associated with an index.
-// * Null is returned if the key is not found, or null if the index has
-// * no value, or if the value is not a JSONObject.
-// *
-// * @param index The index must be between 0 and length() - 1.
-// * @return A JSONObject value.
-// */
-// public JSON optJSONObject(int index) {
-// Object o = this.opt(index);
-// return o instanceof JSON ? (JSON)o : null;
-// }
-//
-//
-// /**
// * Get the optional long value associated with an index.
// * Zero is returned if there is no value for the index,
// * or if the value is not a number and cannot be converted to a number.
@@ -651,23 +683,6 @@ public class JSONArray {
//
//
// /**
-// * Get the optional long value associated with an index.
-// * The defaultValue is returned if there is no value for the index,
-// * or if the value is not a number and cannot be converted to a number.
-// * @param index The index must be between 0 and length() - 1.
-// * @param defaultValue The default value.
-// * @return The value.
-// */
-// public long optLong(int index, long defaultValue) {
-// try {
-// return this.getLong(index);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-//
-//
-// /**
// * Get the optional string value associated with an index. It returns an
// * empty string if there is no value at that index. If the value
// * is not a string and is not null, then it is coverted to a string.
@@ -677,22 +692,6 @@ public class JSONArray {
// */
// public String optString(int index) {
// return this.optString(index, "");
-// }
-//
-//
-// /**
-// * Get the optional string associated with an index.
-// * The defaultValue is returned if the key is not found.
-// *
-// * @param index The index must be between 0 and length() - 1.
-// * @param defaultValue The default value.
-// * @return A String value.
-// */
-// public String optString(int index, String defaultValue) {
-// Object object = this.opt(index);
-// return JSON.NULL.equals(object)
-// ? defaultValue
-// : object.toString();
// }
@@ -1052,15 +1051,14 @@ public class JSONArray {
* @param index must be between 0 and length() - 1
* @return true if the value at the index is null, or if there is no value.
*/
- // TODO not sure on this one
- protected boolean isNull(int index) {
+ public boolean isNull(int index) {
return JSONObject.NULL.equals(this.opt(index));
}
/**
* Remove an index and close the hole.
- *
+ *
* @webref jsonarray:method
* @brief Removes an element
* @param index the index value of the element to be removed
@@ -1145,6 +1143,7 @@ public class JSONArray {
}
}
+
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
@@ -1157,6 +1156,7 @@ public class JSONArray {
return this.write(writer, -1, 0);
}
+
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
@@ -1182,9 +1182,10 @@ public class JSONArray {
if (length == 1) {
JSONObject.writeValue(writer, this.myArrayList.get(0),
- thisFactor, indent);
+ indentFactor, indent);
+// thisFactor, indent);
} else if (length != 0) {
- final int newindent = indent + thisFactor;
+ final int newIndent = indent + thisFactor;
for (int i = 0; i < length; i += 1) {
if (commanate) {
@@ -1193,9 +1194,11 @@ public class JSONArray {
if (indentFactor != -1) {
writer.write('\n');
}
- JSONObject.indent(writer, newindent);
+ JSONObject.indent(writer, newIndent);
+// JSONObject.writeValue(writer, this.myArrayList.get(i),
+// thisFactor, newIndent);
JSONObject.writeValue(writer, this.myArrayList.get(i),
- thisFactor, newindent);
+ indentFactor, newIndent);
commanate = true;
}
if (indentFactor != -1) {
diff --git a/core/src/processing/data/JSONObject.java b/core/src/processing/data/JSONObject.java
index 156938575..165b099cd 100644
--- a/core/src/processing/data/JSONObject.java
+++ b/core/src/processing/data/JSONObject.java
@@ -573,6 +573,20 @@ public class JSONObject {
}
+ /**
+ * Get an optional string associated with a key.
+ * It returns the defaultValue if there is no such key.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return A string which is the value.
+ */
+ public String getString(String key, String defaultValue) {
+ Object object = this.opt(key);
+ return NULL.equals(object) ? defaultValue : object.toString();
+ }
+
+
/**
* Gets the int value associated with a key
*
@@ -598,6 +612,25 @@ public class JSONObject {
}
+ /**
+ * Get an optional int value associated with a key,
+ * or the default if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public int getInt(String key, int defaultValue) {
+ try {
+ return this.getInt(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the long value associated with a key.
*
@@ -617,6 +650,26 @@ public class JSONObject {
}
}
+
+ /**
+ * Get an optional long value associated with a key,
+ * or the default if there is no such key or if the value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public long getLong(String key, long defaultValue) {
+ try {
+ return this.getLong(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* @webref jsonobject:method
* @brief Gets the float value associated with a key
@@ -630,6 +683,15 @@ public class JSONObject {
}
+ public float getFloat(String key, float defaultValue) {
+ try {
+ return getFloat(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the double value associated with a key.
* @param key A key string.
@@ -649,6 +711,25 @@ public class JSONObject {
}
+ /**
+ * Get an optional double associated with a key, or the
+ * defaultValue if there is no such key or if its value is not a number.
+ * If the value is a string, an attempt will be made to evaluate it as
+ * a number.
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return An object which is the value.
+ */
+ public double getDouble(String key, double defaultValue) {
+ try {
+ return this.getDouble(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the boolean value associated with a key.
*
@@ -676,6 +757,24 @@ public class JSONObject {
}
+ /**
+ * Get an optional boolean associated with a key.
+ * It returns the defaultValue if there is no such key, or if it is not
+ * a Boolean or the String "true" or "false" (case insensitive).
+ *
+ * @param key A key string.
+ * @param defaultValue The default.
+ * @return The truth.
+ */
+ public boolean getBoolean(String key, boolean defaultValue) {
+ try {
+ return this.getBoolean(key);
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+
/**
* Get the JSONArray value associated with a key.
*
@@ -807,7 +906,7 @@ public class JSONObject {
* @return true if there is no value associated with the key or if
* the value is the JSONObject.NULL object.
*/
- protected boolean isNull(String key) {
+ public boolean isNull(String key) {
return JSONObject.NULL.equals(this.opt(key));
}
@@ -910,24 +1009,6 @@ public class JSONObject {
// }
-// /**
-// * Get an optional boolean associated with a key.
-// * It returns the defaultValue if there is no such key, or if it is not
-// * a Boolean or the String "true" or "false" (case insensitive).
-// *
-// * @param key A key string.
-// * @param defaultValue The default.
-// * @return The truth.
-// */
-// private boolean optBoolean(String key, boolean defaultValue) {
-// try {
-// return this.getBoolean(key);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-
-
// /**
// * Get an optional double associated with a key,
// * or NaN if there is no such key or if its value is not a number.
@@ -942,25 +1023,6 @@ public class JSONObject {
// }
-// /**
-// * Get an optional double associated with a key, or the
-// * defaultValue if there is no such key or if its value is not a number.
-// * If the value is a string, an attempt will be made to evaluate it as
-// * a number.
-// *
-// * @param key A key string.
-// * @param defaultValue The default.
-// * @return An object which is the value.
-// */
-// private double optDouble(String key, double defaultValue) {
-// try {
-// return this.getDouble(key);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-
-
// /**
// * Get an optional int value associated with a key,
// * or zero if there is no such key or if the value is not a number.
@@ -975,25 +1037,6 @@ public class JSONObject {
// }
-// /**
-// * Get an optional int value associated with a key,
-// * or the default if there is no such key or if the value is not a number.
-// * If the value is a string, an attempt will be made to evaluate it as
-// * a number.
-// *
-// * @param key A key string.
-// * @param defaultValue The default.
-// * @return An object which is the value.
-// */
-// private int optInt(String key, int defaultValue) {
-// try {
-// return this.getInt(key);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-
-
// /**
// * Get an optional JSONArray associated with a key.
// * It returns null if there is no such key, or if its value is not a
@@ -1036,25 +1079,6 @@ public class JSONObject {
// }
-// /**
-// * Get an optional long value associated with a key,
-// * or the default if there is no such key or if the value is not a number.
-// * If the value is a string, an attempt will be made to evaluate it as
-// * a number.
-// *
-// * @param key A key string.
-// * @param defaultValue The default.
-// * @return An object which is the value.
-// */
-// public long optLong(String key, long defaultValue) {
-// try {
-// return this.getLong(key);
-// } catch (Exception e) {
-// return defaultValue;
-// }
-// }
-
-
// /**
// * Get an optional string associated with a key.
// * It returns an empty string if there is no such key. If the value is not
@@ -1068,20 +1092,6 @@ public class JSONObject {
// }
-// /**
-// * Get an optional string associated with a key.
-// * It returns the defaultValue if there is no such key.
-// *
-// * @param key A key string.
-// * @param defaultValue The default.
-// * @return A string which is the value.
-// */
-// public String optString(String key, String defaultValue) {
-// Object object = this.opt(key);
-// return NULL.equals(object) ? defaultValue : object.toString();
-// }
-
-
private void populateMap(Object bean) {
Class klass = bean.getClass();
@@ -1780,9 +1790,10 @@ public class JSONObject {
if (actualFactor > 0) {
writer.write(' ');
}
- writeValue(writer, this.map.get(key), actualFactor, indent);
+ //writeValue(writer, this.map.get(key), actualFactor, indent);
+ writeValue(writer, this.map.get(key), indentFactor, indent);
} else if (length != 0) {
- final int newindent = indent + actualFactor;
+ final int newIndent = indent + actualFactor;
while (keys.hasNext()) {
Object key = keys.next();
if (commanate) {
@@ -1791,14 +1802,14 @@ public class JSONObject {
if (indentFactor != -1) {
writer.write('\n');
}
- indent(writer, newindent);
+ indent(writer, newIndent);
writer.write(quote(key.toString()));
writer.write(':');
if (actualFactor > 0) {
writer.write(' ');
}
- writeValue(writer, this.map.get(key), actualFactor,
- newindent);
+ //writeValue(writer, this.map.get(key), actualFactor, newIndent);
+ writeValue(writer, this.map.get(key), indentFactor, newIndent);
commanate = true;
}
if (indentFactor != -1) {
diff --git a/core/src/processing/data/StringDict.java b/core/src/processing/data/StringDict.java
index 5fb533616..ed284b10b 100644
--- a/core/src/processing/data/StringDict.java
+++ b/core/src/processing/data/StringDict.java
@@ -316,7 +316,7 @@ public class StringDict {
}
- protected void swap(int a, int b) {
+ public void swap(int a, int b) {
String tkey = keys[a];
String tvalue = values[a];
keys[a] = keys[b];
diff --git a/core/src/processing/data/StringList.java b/core/src/processing/data/StringList.java
index bd71a0867..a407265a9 100644
--- a/core/src/processing/data/StringList.java
+++ b/core/src/processing/data/StringList.java
@@ -15,6 +15,8 @@ import processing.core.PApplet;
* a sorted copy, use list.copy().sort().
*
* @webref data:composite
+ * @see IntList
+ * @see FloatList
*/
public class StringList implements Iterable {
int count;
@@ -646,11 +648,9 @@ public class StringList implements Iterable {
public StringList getSubset(int start, int num) {
- StringList outgoing = new StringList(num);
- for (int i = 0; i < num; i++) {
- System.arraycopy(data, start, outgoing.data, 0, num);
- }
- return outgoing;
+ String[] subset = new String[num];
+ System.arraycopy(data, start, subset, 0, num);
+ return new StringList(subset);
}
@@ -688,6 +688,26 @@ public class StringList implements Iterable {
// }
+ public String join(String separator) {
+ if (count == 0) {
+ return "";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(data[0]);
+ for (int i = 1; i < count; i++) {
+ sb.append(separator);
+ sb.append(data[i]);
+ }
+ return sb.toString();
+ }
+
+
+// static public StringList split(String value, char delim) {
+// String[] array = PApplet.split(value, delim);
+// return new StringList(array);
+// }
+
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/core/src/processing/data/Table.java b/core/src/processing/data/Table.java
index 61ae3e3cb..8dd7b73a6 100644
--- a/core/src/processing/data/Table.java
+++ b/core/src/processing/data/Table.java
@@ -60,6 +60,7 @@ import processing.core.PConstants;
*/
public class Table {
protected int rowCount;
+ protected int allocCount;
// protected boolean skipEmptyRows = true;
// protected boolean skipCommentLines = true;
@@ -91,6 +92,10 @@ public class Table {
protected RowIterator rowIterator;
+ // 0 for doubling each time, otherwise the number of rows to increment on
+ // each expansion.
+ protected int expandIncrement;
+
/**
* Creates a new, empty table. Use addRow() to add additional rows.
@@ -115,6 +120,7 @@ public class Table {
*/
public Table(File file, String options) throws IOException {
// uses createInput() to handle .gz (and eventually .bz2) files
+ init();
parse(PApplet.createInput(file),
extensionOptions(true, file.getName(), options));
}
@@ -142,9 +148,23 @@ public class Table {
* @throws IOException
*/
public Table(InputStream input, String options) throws IOException {
+ init();
parse(input, options);
}
+
+ public Table(Iterable rows) {
+ init();
+ boolean typed = false;
+ for (TableRow row : rows) {
+ if (!typed) {
+ setColumnTypes(row.getColumnTypes());
+ }
+ addRow(row);
+ }
+ }
+
+
/**
* @nowebref
*/
@@ -206,6 +226,14 @@ public class Table {
}
+ public Table typedParse(InputStream input, String options) throws IOException {
+ Table table = new Table();
+ table.setColumnTypes(this);
+ table.parse(input, options);
+ return table;
+ }
+
+
protected void init() {
columns = new Object[0];
columnTypes = new int[0];
@@ -268,7 +296,7 @@ public class Table {
protected void parse(InputStream input, String options) throws IOException {
- init();
+ //init();
boolean awfulCSV = false;
boolean header = false;
@@ -280,7 +308,7 @@ public class Table {
String[] opts = null;
if (options != null) {
- opts = PApplet.splitTokens(options, " ,");
+ opts = PApplet.trim(PApplet.split(options, ','));
for (String opt : opts) {
if (opt.equals("tsv")) {
extension = "tsv";
@@ -298,6 +326,8 @@ public class Table {
header = true;
} else if (opt.startsWith(sheetParam)) {
worksheet = opt.substring(sheetParam.length());
+ } else if (opt.startsWith("dictionary=")) {
+ // ignore option, this is only handled by PApplet
} else {
throw new IllegalArgumentException("'" + opt + "' is not a valid option for loading a Table");
}
@@ -335,21 +365,22 @@ public class Table {
setRowCount(10);
}
//int prev = 0; //-1;
- while ((line = reader.readLine()) != null) {
- if (row == getRowCount()) {
- setRowCount(row << 1);
- }
- if (row == 0 && header) {
- setColumnTitles(tsv ? PApplet.split(line, '\t') : splitLineCSV(line));
- header = false;
- } else {
- setRow(row, tsv ? PApplet.split(line, '\t') : splitLineCSV(line));
- row++;
- }
+ try {
+ while ((line = reader.readLine()) != null) {
+ if (row == getRowCount()) {
+ setRowCount(row << 1);
+ }
+ if (row == 0 && header) {
+ setColumnTitles(tsv ? PApplet.split(line, '\t') : splitLineCSV(line));
+ header = false;
+ } else {
+ setRow(row, tsv ? PApplet.split(line, '\t') : splitLineCSV(line));
+ row++;
+ }
- /*
- // this is problematic unless we're going to calculate rowCount first
- if (row % 10000 == 0) {
+ // this is problematic unless we're going to calculate rowCount first
+ if (row % 10000 == 0) {
+ /*
if (row < rowCount) {
int pct = (100 * row) / rowCount;
if (pct != prev) { // also prevents "0%" from showing up
@@ -357,13 +388,17 @@ public class Table {
prev = pct;
}
}
- try {
- Thread.sleep(5);
- } catch (InterruptedException e) {
- e.printStackTrace();
+ */
+ try {
+ // Sleep this thread so that the GC can catch up
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
}
}
- */
+ } catch (Exception e) {
+ throw new RuntimeException("Error reading table on line " + row, e);
}
// shorten or lengthen based on what's left
if (row != getRowCount()) {
@@ -882,7 +917,7 @@ public class Table {
throw new IllegalArgumentException("No extension specified for saving this Table");
}
- String[] opts = PApplet.splitTokens(options, ", ");
+ String[] opts = PApplet.trim(PApplet.split(options, ','));
// Only option for save is the extension, so we can safely grab the last
extension = opts[opts.length - 1];
boolean found = false;
@@ -1524,6 +1559,14 @@ public class Table {
}
+ public void setColumnTypes(int[] types) {
+ ensureColumn(types.length - 1);
+ for (int col = 0; col < types.length; col++) {
+ setColumnType(col, types[col]);
+ }
+ }
+
+
/**
* Set the titles (and if a second column is present) the data types for
* this table based on a file loaded separately. This will look for the
@@ -1533,6 +1576,7 @@ public class Table {
* @param dictionary
*/
public void setColumnTypes(final Table dictionary) {
+ ensureColumn(dictionary.getRowCount() - 1);
int titleCol = 0;
int typeCol = 1;
if (dictionary.hasColumnTitles()) {
@@ -1580,6 +1624,11 @@ public class Table {
}
+ public int[] getColumnTypes() {
+ return columnTypes;
+ }
+
+
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -1703,6 +1752,7 @@ public class Table {
return getRowCount() - 1;
}
+
/**
* @webref table:method
* @brief Removes all rows from a table
@@ -1745,6 +1795,7 @@ public class Table {
rowCount = newCount;
}
+
/**
* @webref table:method
* @brief Adds a row to a table
@@ -1752,10 +1803,12 @@ public class Table {
* @see Table#clearRows()
*/
public TableRow addRow() {
+ //if (rowIncrement == 0) {
setRowCount(rowCount + 1);
return new RowPointer(this, rowCount - 1);
}
+
/**
* @param source a reference to the original row to be duplicated
*/
@@ -1789,6 +1842,7 @@ public class Table {
return new RowPointer(this, row);
}
+
/**
* @nowebref
*/
@@ -1805,35 +1859,35 @@ public class Table {
case INT: {
int[] intTemp = new int[rowCount+1];
System.arraycopy(columns[col], 0, intTemp, 0, insert);
- System.arraycopy(columns[col], insert, intTemp, insert+1, (rowCount - insert) + 1);
+ System.arraycopy(columns[col], insert, intTemp, insert+1, rowCount - insert);
columns[col] = intTemp;
break;
}
case LONG: {
long[] longTemp = new long[rowCount+1];
System.arraycopy(columns[col], 0, longTemp, 0, insert);
- System.arraycopy(columns[col], insert, longTemp, insert+1, (rowCount - insert) + 1);
+ System.arraycopy(columns[col], insert, longTemp, insert+1, rowCount - insert);
columns[col] = longTemp;
break;
}
case FLOAT: {
float[] floatTemp = new float[rowCount+1];
System.arraycopy(columns[col], 0, floatTemp, 0, insert);
- System.arraycopy(columns[col], insert, floatTemp, insert+1, (rowCount - insert) + 1);
+ System.arraycopy(columns[col], insert, floatTemp, insert+1, rowCount - insert);
columns[col] = floatTemp;
break;
}
case DOUBLE: {
double[] doubleTemp = new double[rowCount+1];
System.arraycopy(columns[col], 0, doubleTemp, 0, insert);
- System.arraycopy(columns[col], insert, doubleTemp, insert+1, (rowCount - insert) + 1);
+ System.arraycopy(columns[col], insert, doubleTemp, insert+1, rowCount - insert);
columns[col] = doubleTemp;
break;
}
case STRING: {
String[] stringTemp = new String[rowCount+1];
System.arraycopy(columns[col], 0, stringTemp, 0, insert);
- System.arraycopy(columns[col], insert, stringTemp, insert+1, (rowCount - insert) + 1);
+ System.arraycopy(columns[col], insert, stringTemp, insert+1, rowCount - insert);
columns[col] = stringTemp;
break;
}
@@ -2204,6 +2258,10 @@ public class Table {
public int getColumnType(int column) {
return table.getColumnType(column);
}
+
+ public int[] getColumnTypes() {
+ return table.getColumnTypes();
+ }
}
@@ -3576,7 +3634,119 @@ public class Table {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- // TODO maybe these aren't needed. better to use getStringList().getUnique()?
+ public void sort(String columnName) {
+ sort(getColumnIndex(columnName), false);
+ }
+
+
+ public void sort(int column) {
+ sort(column, false);
+ }
+
+
+ public void sortReverse(String columnName) {
+ sort(getColumnIndex(columnName), true);
+ }
+
+
+ public void sortReverse(int column) {
+ sort(column, true);
+ }
+
+
+ protected void sort(final int column, final boolean reverse) {
+ final int[] order = IntList.fromRange(getRowCount()).array();
+ Sort s = new Sort() {
+
+ @Override
+ public int size() {
+ return getRowCount();
+ }
+
+ @Override
+ public float compare(int index1, int index2) {
+ int a = reverse ? order[index2] : order[index1];
+ int b = reverse ? order[index1] : order[index2];
+
+ switch (getColumnType(column)) {
+ case INT:
+ return getInt(a, column) - getInt(b, column);
+ case LONG:
+ return getLong(a, column) - getLong(b, column);
+ case FLOAT:
+ return getFloat(a, column) - getFloat(b, column);
+ case DOUBLE:
+ return (float) (getDouble(a, column) - getDouble(b, column));
+ case STRING:
+ return getString(a, column).compareToIgnoreCase(getString(b, column));
+ case CATEGORY:
+ return getInt(a, column) - getInt(b, column);
+ default:
+ throw new IllegalArgumentException("Invalid column type: " + getColumnType(column));
+ }
+ }
+
+ @Override
+ public void swap(int a, int b) {
+ int temp = order[a];
+ order[a] = order[b];
+ order[b] = temp;
+ }
+
+ };
+ s.run();
+
+ //Object[] newColumns = new Object[getColumnCount()];
+ for (int col = 0; col < getColumnCount(); col++) {
+ switch (getColumnType(col)) {
+ case INT:
+ case CATEGORY:
+ int[] oldInt = (int[]) columns[col];
+ int[] newInt = new int[rowCount];
+ for (int row = 0; row < getRowCount(); row++) {
+ newInt[row] = oldInt[order[row]];
+ }
+ columns[col] = newInt;
+ break;
+ case LONG:
+ long[] oldLong = (long[]) columns[col];
+ long[] newLong = new long[rowCount];
+ for (int row = 0; row < getRowCount(); row++) {
+ newLong[row] = oldLong[order[row]];
+ }
+ columns[col] = newLong;
+ break;
+ case FLOAT:
+ float[] oldFloat = (float[]) columns[col];
+ float[] newFloat = new float[rowCount];
+ for (int row = 0; row < getRowCount(); row++) {
+ newFloat[row] = oldFloat[order[row]];
+ }
+ columns[col] = newFloat;
+ break;
+ case DOUBLE:
+ double[] oldDouble = (double[]) columns[col];
+ double[] newDouble = new double[rowCount];
+ for (int row = 0; row < getRowCount(); row++) {
+ newDouble[row] = oldDouble[order[row]];
+ }
+ columns[col] = newDouble;
+ break;
+ case STRING:
+ String[] oldString = (String[]) columns[col];
+ String[] newString = new String[rowCount];
+ for (int row = 0; row < getRowCount(); row++) {
+ newString[row] = oldString[order[row]];
+ }
+ columns[col] = newString;
+ break;
+ }
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
public String[] getUnique(String columnName) {
return getUnique(getColumnIndex(columnName));
diff --git a/core/src/processing/data/TableRow.java b/core/src/processing/data/TableRow.java
index 299d6eea4..7107ee693 100644
--- a/core/src/processing/data/TableRow.java
+++ b/core/src/processing/data/TableRow.java
@@ -36,7 +36,7 @@ public interface TableRow {
* @param columnName title of the column to reference
*/
public int getInt(String columnName);
-
+
public long getLong(int column);
public long getLong(String columnName);
@@ -52,7 +52,7 @@ public interface TableRow {
* @param columnName title of the column to reference
*/
public float getFloat(String columnName);
-
+
public double getDouble(int column);
public double getDouble(String columnName);
@@ -107,4 +107,6 @@ public interface TableRow {
public int getColumnCount();
public int getColumnType(String columnName);
public int getColumnType(int column);
+
+ public int[] getColumnTypes();
}
diff --git a/core/src/processing/data/XML.java b/core/src/processing/data/XML.java
index b345465e3..5860eafc2 100644
--- a/core/src/processing/data/XML.java
+++ b/core/src/processing/data/XML.java
@@ -82,7 +82,9 @@ public class XML implements Serializable {
/**
- * Advanced users only; see loadXML() in PApplet.
+ * Advanced users only; use loadXML() in PApplet. This is not a supported
+ * function and is subject to change. It is available simply for users that
+ * would like to handle the exceptions in a particular way.
*
* @nowebref
*/
@@ -92,7 +94,7 @@ public class XML implements Serializable {
/**
- * Advanced users only; see loadXML() in PApplet.
+ * Advanced users only; use loadXML() in PApplet.
*
* @nowebref
*/
@@ -109,19 +111,31 @@ public class XML implements Serializable {
/**
- * Shouldn't be part of main p5 reference, this is for advanced users.
- * Note that while it doesn't accept anything but UTF-8, this is preserved
- * so that we have some chance of implementing that in the future.
+ * Unlike the loadXML() method in PApplet, this version works with files
+ * that are not in UTF-8 format.
*
* @nowebref
*/
public XML(InputStream input, String options) throws IOException, ParserConfigurationException, SAXException {
- this(PApplet.createReader(input), options);
+ //this(PApplet.createReader(input), options); // won't handle non-UTF8
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ try {
+ // Prevent 503 errors from www.w3.org
+ factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ } catch (IllegalArgumentException e) {
+ // ignore this; Android doesn't like it
+ }
+
+ factory.setExpandEntityReferences(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.parse(new InputSource(input));
+ node = document.getDocumentElement();
}
/**
- * Advanced users only; see loadXML() in PApplet.
+ * Advanced users only; use loadXML() in PApplet.
*
* @nowebref
*/
@@ -131,11 +145,17 @@ public class XML implements Serializable {
/**
- * Advanced users only; see loadXML() in PApplet.
+ * Advanced users only; use loadXML() in PApplet.
+ *
+ * Added extra code to handle \u2028 (Unicode NLF), which is sometimes
+ * inserted by web browsers (Safari?) and not distinguishable from a "real"
+ * LF (or CRLF) in some text editors (i.e. TextEdit on OS X). Only doing
+ * this for XML (and not all Reader objects) because LFs are essential.
+ * https://github.com/processing/processing/issues/2100
*
* @nowebref
*/
- public XML(Reader reader, String options) throws IOException, ParserConfigurationException, SAXException {
+ public XML(final Reader reader, String options) throws IOException, ParserConfigurationException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Prevent 503 errors from www.w3.org
@@ -164,17 +184,24 @@ public class XML implements Serializable {
// builder = new SAXBuilder();
// builder.setValidation(validating);
-// print(dataPath("1broke.html"), System.out);
+ Document document = builder.parse(new InputSource(new Reader() {
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ int count = reader.read(cbuf, off, len);
+ for (int i = 0; i < count; i++) {
+ if (cbuf[off+i] == '\u2028') {
+ cbuf[off+i] = '\n';
+ }
+ }
+ return count;
+ }
-// Document document = builder.parse(dataPath("1_alt.html"));
- Document document = builder.parse(new InputSource(reader));
+ @Override
+ public void close() throws IOException {
+ reader.close();
+ }
+ }));
node = document.getDocumentElement();
-// name = node.getNodeName();
-
-// NodeList nodeList = document.getDocumentElement().getChildNodes();
-// for (int i = 0; i < nodeList.getLength(); i++) {
-// }
-// print(createWriter("data/1_alt_reparse.html"), document.getDocumentElement(), 0);
}
@@ -810,6 +837,12 @@ public class XML implements Serializable {
}
+ public String getContent(String defaultValue) {
+ String s = node.getTextContent();
+ return (s != null) ? s : defaultValue;
+ }
+
+
/**
* @webref xml:method
* @brief Gets the content of an element as an int
diff --git a/core/src/processing/opengl/ColorVert.glsl b/core/src/processing/opengl/ColorVert.glsl
index 5a03b41a0..3736ffd2e 100644
--- a/core/src/processing/opengl/ColorVert.glsl
+++ b/core/src/processing/opengl/ColorVert.glsl
@@ -20,15 +20,15 @@
#define PROCESSING_COLOR_SHADER
-uniform mat4 transform;
+uniform mat4 transformMatrix;
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
varying vec4 vertColor;
void main() {
- gl_Position = transform * vertex;
+ gl_Position = transformMatrix * position;
vertColor = color;
}
\ No newline at end of file
diff --git a/core/src/processing/opengl/LightVert.glsl b/core/src/processing/opengl/LightVert.glsl
index 6e5829fe2..bfbb6a8d3 100644
--- a/core/src/processing/opengl/LightVert.glsl
+++ b/core/src/processing/opengl/LightVert.glsl
@@ -20,8 +20,8 @@
#define PROCESSING_LIGHT_SHADER
-uniform mat4 modelview;
-uniform mat4 transform;
+uniform mat4 modelviewMatrix;
+uniform mat4 transformMatrix;
uniform mat3 normalMatrix;
uniform int lightCount;
@@ -33,7 +33,7 @@ uniform vec3 lightSpecular[8];
uniform vec3 lightFalloff[8];
uniform vec2 lightSpot[8];
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
@@ -75,10 +75,10 @@ float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine)
void main() {
// Vertex in clip coordinates
- gl_Position = transform * vertex;
+ gl_Position = transformMatrix * position;
// Vertex in eye coordinates
- vec3 ecVertex = vec3(modelview * vertex);
+ vec3 ecVertex = vec3(modelviewMatrix * position);
// Normal vector in eye coordinates
vec3 ecNormal = normalize(normalMatrix * normal);
diff --git a/core/src/processing/opengl/LineStroker.java b/core/src/processing/opengl/LineStroker.java
index 75f6374cb..ee6b20910 100644
--- a/core/src/processing/opengl/LineStroker.java
+++ b/core/src/processing/opengl/LineStroker.java
@@ -312,7 +312,8 @@ public class LineStroker {
return ncoords / 2;
}
- private static final long ROUND_JOIN_THRESHOLD = 1000L;
+ //private static final long ROUND_JOIN_THRESHOLD = 1000L;
+ private static final long ROUND_JOIN_THRESHOLD = 100000000L;
private static final long ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000L;
diff --git a/core/src/processing/opengl/LineVert.glsl b/core/src/processing/opengl/LineVert.glsl
index 52f334b28..d16f4d519 100644
--- a/core/src/processing/opengl/LineVert.glsl
+++ b/core/src/processing/opengl/LineVert.glsl
@@ -20,14 +20,14 @@
#define PROCESSING_LINE_SHADER
-uniform mat4 modelview;
-uniform mat4 projection;
+uniform mat4 modelviewMatrix;
+uniform mat4 projectionMatrix;
uniform vec4 viewport;
uniform int perspective;
uniform vec3 scale;
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
attribute vec4 direction;
@@ -45,20 +45,20 @@ vec4 windowToClipVector(vec2 window, vec4 viewport, float clip_w) {
}
void main() {
- vec4 posp = modelview * vertex;
+ vec4 posp = modelviewMatrix * position;
// Moving vertices slightly toward the camera
// to avoid depth-fighting with the fill triangles.
// Discussed here:
// http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848
posp.xyz = posp.xyz * scale;
- vec4 clipp = projection * posp;
+ vec4 clipp = projectionMatrix * posp;
float thickness = direction.w;
if (thickness != 0.0) {
- vec4 posq = posp + modelview * vec4(direction.xyz, 0);
+ vec4 posq = posp + modelviewMatrix * vec4(direction.xyz, 0);
posq.xyz = posq.xyz * scale;
- vec4 clipq = projection * posq;
+ vec4 clipq = projectionMatrix * posq;
vec3 window_p = clipToWindow(clipp, viewport);
vec3 window_q = clipToWindow(clipq, viewport);
diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java
index e5677804d..f1e43fcd1 100644
--- a/core/src/processing/opengl/PGL.java
+++ b/core/src/processing/opengl/PGL.java
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2011-12 Ben Fry and Casey Reas
+ Copyright (c) 2011-13 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -23,115 +23,80 @@
package processing.opengl;
-import java.awt.BorderLayout;
-import java.awt.Canvas;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Shape;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.PathIterator;
-import java.nio.Buffer;
+import processing.core.PApplet;
+import processing.core.PGraphics;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.media.opengl.GL;
-import javax.media.opengl.GL2;
-import javax.media.opengl.GL2ES2;
-import javax.media.opengl.GLAutoDrawable;
-import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLCapabilitiesImmutable;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
-import javax.media.opengl.GLEventListener;
-import javax.media.opengl.GLException;
-import javax.media.opengl.GLFBODrawable;
-import javax.media.opengl.GLProfile;
-import javax.media.opengl.awt.GLCanvas;
-import javax.media.opengl.glu.GLU;
-import javax.media.opengl.glu.GLUtessellator;
-import javax.media.opengl.glu.GLUtessellatorCallbackAdapter;
-
-import processing.core.PApplet;
-import processing.core.PConstants;
-import processing.event.KeyEvent;
-import processing.event.MouseEvent;
-
-import com.jogamp.newt.awt.NewtCanvasAWT;
-import com.jogamp.newt.event.InputEvent;
-import com.jogamp.newt.opengl.GLWindow;
-import com.jogamp.opengl.FBObject;
/**
- * Processing-OpenGL abstraction layer.
+ * Processing-OpenGL abstraction layer. Needs to be implemented by subclasses
+ * using specific OpenGL-Java bindings.
+ *
+ * It includes a full GLES 2.0 interface.
*
- * Warnings are suppressed for static access because presumably on Android,
- * the GL2 vs GL distinctions are necessary, whereas on desktop they are not.
*/
-@SuppressWarnings("static-access")
-public class PGL {
- ///////////////////////////////////////////////////////////
+public abstract class PGL {
+ // ........................................................
- // Public members to access the underlying GL objects and context
+ // Basic fields
- /** Basic GL functionality, common to all profiles */
- public static GL gl;
+ /** The PGraphics object using this interface */
+ protected PGraphicsOpenGL pg;
- /** GLU interface **/
- public static GLU glu;
+ /** OpenGL thread */
+ protected static Thread glThread;
- /** The rendering context (holds rendering state info) */
- public static GLContext context;
+ /** ID of the GL context associated to the surface **/
+ protected static int glContext;
- /** The canvas where OpenGL rendering takes place */
- public static Canvas canvas;
-
- /** Selected GL profile */
- public static GLProfile profile;
-
- ///////////////////////////////////////////////////////////
+ // ........................................................
// Parameters
+ protected static boolean USE_FBOLAYER_BY_DEFAULT = false;
+ protected static int REQUESTED_DEPTH_BITS = 24;
+ protected static int REQUESTED_STENCIL_BITS = 8;
+ protected static int REQUESTED_ALPHA_BITS = 8;
+
/** Switches between the use of regular and direct buffers. */
- protected static final boolean USE_DIRECT_BUFFERS = true;
- protected static final int MIN_DIRECT_BUFFER_SIZE = 1;
+ protected static boolean USE_DIRECT_BUFFERS = true;
+ protected static int MIN_DIRECT_BUFFER_SIZE = 1;
/** This flag enables/disables a hack to make sure that anything drawn
* in setup will be maintained even a renderer restart (e.g.: smooth change).
* See the code and comments involving this constant in
* PGraphicsOpenGL.endDraw().
*/
- protected static final boolean SAVE_SURFACE_TO_PIXELS_HACK = true;
+ protected static boolean SAVE_SURFACE_TO_PIXELS_HACK = true;
/** Enables/disables mipmap use. */
- protected static final boolean MIPMAPS_ENABLED = true;
+ protected static boolean MIPMAPS_ENABLED = true;
/** Initial sizes for arrays of input and tessellated data. */
- protected static final int DEFAULT_IN_VERTICES = 64;
- protected static final int DEFAULT_IN_EDGES = 128;
- protected static final int DEFAULT_IN_TEXTURES = 64;
- protected static final int DEFAULT_TESS_VERTICES = 64;
- protected static final int DEFAULT_TESS_INDICES = 128;
+ protected static int DEFAULT_IN_VERTICES = 64;
+ protected static int DEFAULT_IN_EDGES = 128;
+ protected static int DEFAULT_IN_TEXTURES = 64;
+ protected static int DEFAULT_TESS_VERTICES = 64;
+ protected static int DEFAULT_TESS_INDICES = 128;
/** Maximum lights by default is 8, the minimum defined by OpenGL. */
- protected static final int MAX_LIGHTS = 8;
+ protected static int MAX_LIGHTS = 8;
/** Maximum index value of a tessellated vertex. GLES restricts the vertex
* indices to be of type unsigned short. Since Java only supports signed
* shorts as primitive type we have 2^15 = 32768 as the maximum number of
* vertices that can be referred to within a single VBO.
*/
- protected static final int MAX_VERTEX_INDEX = 32767;
- protected static final int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1;
+ protected static int MAX_VERTEX_INDEX = 32767;
+ protected static int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1;
/** Count of tessellated fill, line or point vertices that will
* trigger a flush in the immediate mode. It doesn't necessarily
@@ -139,98 +104,183 @@ public class PGL {
* be effectively much large since the renderer uses offsets to
* refer to vertices beyond the MAX_VERTEX_INDEX limit.
*/
- protected static final int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1;
+ protected static int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1;
/** Minimum/maximum dimensions of a texture used to hold font data. */
- protected static final int MIN_FONT_TEX_SIZE = 256;
- protected static final int MAX_FONT_TEX_SIZE = 1024;
+ protected static int MIN_FONT_TEX_SIZE = 256;
+ protected static int MAX_FONT_TEX_SIZE = 1024;
/** Minimum stroke weight needed to apply the full path stroking
* algorithm that properly generates caps and joins.
*/
- protected static final float MIN_CAPS_JOINS_WEIGHT = 2f;
+ protected static float MIN_CAPS_JOINS_WEIGHT = 2f;
/** Maximum length of linear paths to be stroked with the
* full algorithm that generates accurate caps and joins.
*/
- protected static final int MAX_CAPS_JOINS_LENGTH = 5000;
+ protected static int MAX_CAPS_JOINS_LENGTH = 5000;
/** Minimum array size to use arrayCopy method(). */
- protected static final int MIN_ARRAYCOPY_SIZE = 2;
+ protected static int MIN_ARRAYCOPY_SIZE = 2;
/** Factor used to displace the stroke vertices towards the camera in
* order to make sure the lines are always on top of the fill geometry */
- protected static final float STROKE_DISPLACEMENT = 0.999f;
+ protected static float STROKE_DISPLACEMENT = 0.999f;
- /** Time that the Processing's animation thread will wait for JOGL's rendering
- * thread to be done with a single frame.
- */
- protected static final int DRAW_TIMEOUT_MILLIS = 500;
+ // ........................................................
- /** JOGL's windowing toolkit */
- // The two windowing toolkits available to use in JOGL:
- protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing
- protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html
+ // FBO layer
- /** OS-specific configuration */
- protected static int WINDOW_TOOLKIT;
- protected static int EVENTS_TOOLKIT;
- protected static boolean USE_FBOLAYER_BY_DEFAULT;
- protected static boolean USE_JOGL_FBOLAYER;
- protected static int REQUESTED_DEPTH_BITS = 24;
- protected static int REQUESTED_STENCIL_BITS = 8;
- protected static int REQUESTED_ALPHA_BITS = 8;
- static {
- if (PApplet.platform == PConstants.WINDOWS) {
- // Using AWT on Windows because NEWT displays a black background while
- // initializing, and the cursor functions don't work. GLWindow has some
- // functions for basic cursor handling (hide/show):
- // GLWindow.setPointerVisible(false);
- // but apparently nothing to set the cursor icon:
- // https://jogamp.org/bugzilla/show_bug.cgi?id=409
- WINDOW_TOOLKIT = AWT;
- EVENTS_TOOLKIT = AWT;
- USE_FBOLAYER_BY_DEFAULT = false;
- USE_JOGL_FBOLAYER = false;
- REQUESTED_DEPTH_BITS = 24;
- REQUESTED_STENCIL_BITS = 8;
- REQUESTED_ALPHA_BITS = 8;
- } else if (PApplet.platform == PConstants.MACOSX) {
- // Note: with the JOGL jars included in the 2.0 release (jogl-2.0-b993,
- // gluegen-1.0-b671), the JOGL FBO layer seems incompatible with NEWT.
- WINDOW_TOOLKIT = AWT;
- EVENTS_TOOLKIT = AWT;
- USE_FBOLAYER_BY_DEFAULT = true;
- USE_JOGL_FBOLAYER = true;
- REQUESTED_DEPTH_BITS = 24;
- REQUESTED_STENCIL_BITS = 8;
- REQUESTED_ALPHA_BITS = 8;
- } else if (PApplet.platform == PConstants.LINUX) {
- WINDOW_TOOLKIT = AWT;
- EVENTS_TOOLKIT = AWT;
- USE_FBOLAYER_BY_DEFAULT = false;
- USE_JOGL_FBOLAYER = false;
- REQUESTED_DEPTH_BITS = 24;
- REQUESTED_STENCIL_BITS = 8;
- REQUESTED_ALPHA_BITS = 8;
- } else if (PApplet.platform == PConstants.OTHER) {
- WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi?
- EVENTS_TOOLKIT = NEWT;
- USE_FBOLAYER_BY_DEFAULT = false;
- USE_JOGL_FBOLAYER = false;
- REQUESTED_DEPTH_BITS = 24;
- REQUESTED_STENCIL_BITS = 8;
- REQUESTED_ALPHA_BITS = 8;
- }
- }
+ protected static boolean fboLayerRequested = false;
+ protected static boolean fboLayerCreated = false;
+ protected static boolean fboLayerInUse = false;
+ protected static boolean firstFrame = true;
+ protected static int reqNumSamples;
+ protected static int numSamples;
+ protected static IntBuffer glColorFbo;
+ protected static IntBuffer glMultiFbo;
+ protected static IntBuffer glColorBuf;
+ protected static IntBuffer glColorTex;
+ protected static IntBuffer glDepthStencil;
+ protected static IntBuffer glDepth;
+ protected static IntBuffer glStencil;
+ protected static int fboWidth, fboHeight;
+ protected static int backTex, frontTex;
+
+ /** Flags used to handle the creation of a separate front texture */
+ protected boolean usingFrontTex = false;
+ protected boolean needSepFrontTex = false;
+
+ // ........................................................
+
+ // Texture rendering
+
+ protected static boolean loadedTex2DShader = false;
+ protected static int tex2DShaderProgram;
+ protected static int tex2DVertShader;
+ protected static int tex2DFragShader;
+ protected static int tex2DShaderContext;
+ protected static int texGeoVBO;
+ protected static int tex2DVertLoc;
+ protected static int tex2DTCoordLoc;
+ protected static int tex2DSamplerLoc;
+
+ protected static boolean loadedTexRectShader = false;
+ protected static int texRectShaderProgram;
+ protected static int texRectVertShader;
+ protected static int texRectFragShader;
+ protected static int texRectShaderContext;
+ protected static int texRectVertLoc;
+ protected static int texRectTCoordLoc;
+ protected static int texRectSamplerLoc;
+
+ protected static float[] texCoords = {
+ // X, Y, U, V
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ +1.0f, -1.0f, 1.0f, 0.0f,
+ -1.0f, +1.0f, 0.0f, 1.0f,
+ +1.0f, +1.0f, 1.0f, 1.0f
+ };
+ protected static FloatBuffer texData;
+
+ protected static final String SHADER_PREPROCESSOR_DIRECTIVE =
+ "#ifdef GL_ES\n" +
+ "precision mediump float;\n" +
+ "precision mediump int;\n" +
+ "#endif\n";
+
+ protected static String[] texVertShaderSource = {
+ "attribute vec2 position;",
+ "attribute vec2 texCoord;",
+ "varying vec2 vertTexCoord;",
+ "void main() {",
+ " gl_Position = vec4(position, 0, 1);",
+ " vertTexCoord = texCoord;",
+ "}"
+ };
+
+ protected static String[] tex2DFragShaderSource = {
+ SHADER_PREPROCESSOR_DIRECTIVE,
+ "uniform sampler2D texMap;",
+ "varying vec2 vertTexCoord;",
+ "void main() {",
+ " gl_FragColor = texture2D(texMap, vertTexCoord.st);",
+ "}"
+ };
+
+ protected static String[] texRectFragShaderSource = {
+ SHADER_PREPROCESSOR_DIRECTIVE,
+ "uniform sampler2DRect texMap;",
+ "varying vec2 vertTexCoord;",
+ "void main() {",
+ " gl_FragColor = texture2DRect(texMap, vertTexCoord.st);",
+ "}"
+ };
+
+ /** Which texturing targets are enabled */
+ protected static boolean[] texturingTargets = { false, false };
+
+ /** Used to keep track of which textures are bound to each target */
+ protected static int maxTexUnits;
+ protected static int activeTexUnit = 0;
+ protected static int[][] boundTextures;
+
+ // ........................................................
+
+ // Framerate handling
+
+ protected float targetFps = 60;
+ protected float currentFps = 60;
+ protected boolean setFps = false;
+
+ // ........................................................
+
+ // Utility buffers
+
+ protected ByteBuffer byteBuffer;
+ protected IntBuffer intBuffer;
+ protected IntBuffer viewBuffer;
+
+ protected IntBuffer colorBuffer;
+ protected FloatBuffer depthBuffer;
+ protected ByteBuffer stencilBuffer;
+
+ // ........................................................
+
+ // Error messages
+
+ protected static final String WIKI =
+ " Read http://wiki.processing.org/w/OpenGL_Issues for help.";
+
+ protected static final String FRAMEBUFFER_ERROR =
+ "Framebuffer error (%1$s), rendering will probably not work as expected" + WIKI;
+
+ protected static final String MISSING_FBO_ERROR =
+ "Framebuffer objects are not supported by this hardware (or driver)" + WIKI;
+
+ protected static final String MISSING_GLSL_ERROR =
+ "GLSL shaders are not supported by this hardware (or driver)" + WIKI;
+
+ protected static final String MISSING_GLFUNC_ERROR =
+ "GL function %1$s is not available on this hardware (or driver)" + WIKI;
+
+ protected static final String UNSUPPORTED_GLPROF_ERROR =
+ "Unsupported OpenGL profile.";
+
+ protected static final String TEXUNIT_ERROR =
+ "Number of texture units not supported by this hardware (or driver)" + WIKI;
+
+ // ........................................................
+
+ // Constants
/** Size of different types in bytes */
- protected static final int SIZEOF_SHORT = Short.SIZE / 8;
- protected static final int SIZEOF_INT = Integer.SIZE / 8;
- protected static final int SIZEOF_FLOAT = Float.SIZE / 8;
- protected static final int SIZEOF_BYTE = Byte.SIZE / 8;
- protected static final int SIZEOF_INDEX = SIZEOF_SHORT;
- protected static final int INDEX_TYPE = GL.GL_UNSIGNED_SHORT;
+ protected static int SIZEOF_SHORT = Short.SIZE / 8;
+ protected static int SIZEOF_INT = Integer.SIZE / 8;
+ protected static int SIZEOF_FLOAT = Float.SIZE / 8;
+ protected static int SIZEOF_BYTE = Byte.SIZE / 8;
+ protected static int SIZEOF_INDEX = SIZEOF_SHORT;
+ protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT
/** Machine Epsilon for float precision. */
protected static float FLOAT_EPS = Float.MIN_VALUE;
@@ -253,202 +303,17 @@ public class PGL {
protected static boolean BIG_ENDIAN =
ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
- protected static final String SHADER_PREPROCESSOR_DIRECTIVE =
- "#ifdef GL_ES\n" +
- "precision mediump float;\n" +
- "precision mediump int;\n" +
- "#endif\n";
- /** OpenGL thread */
- protected static Thread glThread;
-
- /** The PGraphics object using this interface */
- protected PGraphicsOpenGL pg;
-
- /** The capabilities of the OpenGL rendering surface */
- protected static GLCapabilitiesImmutable capabilities;
-
- /** The rendering surface */
- protected static GLDrawable drawable;
-
- /** GLES2 functionality (shaders, etc) */
- protected static GL2ES2 gl2;
-
- /** GL2 desktop functionality (blit framebuffer, map buffer range,
- * multisampled renerbuffers) */
- protected static GL2 gl2x;
-
- /** The AWT-OpenGL canvas */
- protected static GLCanvas canvasAWT;
-
- /** The NEWT-OpenGL canvas */
- protected static NewtCanvasAWT canvasNEWT;
-
- /** The NEWT window */
- protected static GLWindow window;
-
- /** The listener that fires the frame rendering in Processing */
- protected static PGLListener listener;
-
- /** This countdown latch is used to maintain the synchronization between
- * Processing's drawing thread and JOGL's rendering thread */
- protected CountDownLatch drawLatch;
-
- /** Desired target framerate */
- protected float targetFps = 60;
- protected float currentFps = 60;
- protected boolean setFps = false;
- protected int fcount, lastm;
- protected int fint = 3;
-
- /** Which texturing targets are enabled */
- protected static boolean[] texturingTargets = { false, false };
-
- /** Used to keep track of which textures are bound to each target */
- protected static int maxTexUnits;
- protected static int activeTexUnit = 0;
- protected static int[][] boundTextures;
-
- ///////////////////////////////////////////////////////////
-
- // FBO layer
-
- protected static boolean fboLayerRequested = false;
- protected static boolean fboLayerCreated = false;
- protected static boolean fboLayerInUse = false;
- protected static boolean firstFrame = true;
- protected static int reqNumSamples;
- protected static int numSamples;
- protected static IntBuffer glColorFbo;
- protected static IntBuffer glMultiFbo;
- protected static IntBuffer glColorBuf;
- protected static IntBuffer glColorTex;
- protected static IntBuffer glDepthStencil;
- protected static IntBuffer glDepth;
- protected static IntBuffer glStencil;
- protected static int fboWidth, fboHeight;
- protected static int backTex, frontTex;
-
- /** Back (== draw, current frame) buffer */
- protected static FBObject backFBO;
- /** Sink buffer, used in the multisampled case */
- protected static FBObject sinkFBO;
- /** Front (== read, previous frame) buffer */
- protected static FBObject frontFBO;
- protected static FBObject.TextureAttachment backTexAttach;
- protected static FBObject.TextureAttachment frontTexAttach;
-
- /** Flags used to handle the creation of a separte front texture */
- protected boolean usingFrontTex = false;
- protected boolean needSepFrontTex = false;
-
- /** Flag used to do request final display() call to make sure that the
- * buffers are properly swapped.
- */
- protected boolean prevCanDraw = false;
-
- ///////////////////////////////////////////////////////////
-
- // Texture rendering
-
- protected static boolean loadedTex2DShader = false;
- protected static int tex2DShaderProgram;
- protected static int tex2DVertShader;
- protected static int tex2DFragShader;
- protected static GLContext tex2DShaderContext;
- protected static int tex2DVertLoc;
- protected static int tex2DTCoordLoc;
-
- protected static boolean loadedTexRectShader = false;
- protected static int texRectShaderProgram;
- protected static int texRectVertShader;
- protected static int texRectFragShader;
- protected static GLContext texRectShaderContext;
- protected static int texRectVertLoc;
- protected static int texRectTCoordLoc;
-
- protected static float[] texCoords = {
- // X, Y, U, V
- -1.0f, -1.0f, 0.0f, 0.0f,
- +1.0f, -1.0f, 1.0f, 0.0f,
- -1.0f, +1.0f, 0.0f, 1.0f,
- +1.0f, +1.0f, 1.0f, 1.0f
- };
- protected static FloatBuffer texData;
-
- protected static String texVertShaderSource =
- "attribute vec2 inVertex;" +
- "attribute vec2 inTexcoord;" +
- "varying vec2 vertTexcoord;" +
- "void main() {" +
- " gl_Position = vec4(inVertex, 0, 1);" +
- " vertTexcoord = inTexcoord;" +
- "}";
-
- protected static String tex2DFragShaderSource =
- SHADER_PREPROCESSOR_DIRECTIVE +
- "uniform sampler2D textureSampler;" +
- "varying vec2 vertTexcoord;" +
- "void main() {" +
- " gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" +
- "}";
-
- protected static String texRectFragShaderSource =
- SHADER_PREPROCESSOR_DIRECTIVE +
- "uniform sampler2DRect textureSampler;" +
- "varying vec2 vertTexcoord;" +
- "void main() {" +
- " gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" +
- "}";
-
- ///////////////////////////////////////////////////////////
-
- // Utilities
-
- protected ByteBuffer byteBuffer;
- protected IntBuffer intBuffer;
-
- protected IntBuffer colorBuffer;
- protected FloatBuffer depthBuffer;
- protected ByteBuffer stencilBuffer;
-
- protected float[] projMatrix;
- protected float[] mvMatrix;
-
- ///////////////////////////////////////////////////////////
-
- // Error messages
-
- protected static final String FRAMEBUFFER_ERROR =
- "Framebuffer error (%1$s), rendering will probably not work as expected";
-
- protected static final String MISSING_FBO_ERROR =
- "Framebuffer objects are not supported by this hardware (or driver)";
-
- protected static final String MISSING_GLSL_ERROR =
- "GLSL shaders are not supported by this hardware (or driver)";
-
- protected static final String MISSING_GLFUNC_ERROR =
- "GL function %1$s is not available on this hardware (or driver)";
-
- protected static final String TEXUNIT_ERROR =
- "Number of texture units not supported by this hardware (or driver)";
-
-
- ///////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////
// Initialization, finalization
- public PGL() {
- }
+ public PGL() { }
public PGL(PGraphicsOpenGL pg) {
this.pg = pg;
- if (glu == null) {
- glu = new GLU();
- }
if (glColorTex == null) {
glColorTex = allocateIntBuffer(2);
glColorFbo = allocateIntBuffer(1);
@@ -465,151 +330,20 @@ public class PGL {
byteBuffer = allocateByteBuffer(1);
intBuffer = allocateIntBuffer(1);
+ viewBuffer = allocateIntBuffer(4);
}
- protected void setFps(float fps) {
- if (!setFps || targetFps != fps) {
- if (60 < fps) {
- // Disables v-sync
- gl.setSwapInterval(0);
- } else if (30 < fps) {
- gl.setSwapInterval(1);
- } else {
- gl.setSwapInterval(2);
- }
- targetFps = currentFps = fps;
- setFps = true;
- }
- }
+ protected abstract void setFps(float fps);
- protected void initSurface(int antialias) {
- if (profile == null) {
- profile = GLProfile.getDefault();
- }
- GLCapabilities reqCaps = new GLCapabilities(profile);
- reqCaps.setDepthBits(REQUESTED_DEPTH_BITS);
- reqCaps.setStencilBits(REQUESTED_STENCIL_BITS);
- reqCaps.setAlphaBits(REQUESTED_ALPHA_BITS);
- initSurface(antialias, reqCaps, null);
- }
+ protected abstract void initSurface(int antialias);
- protected void initSurface(int antialias, GLCapabilities reqCaps,
- GLContext sharedCtx) {
- if (profile == null) {
- profile = GLProfile.getDefault();
- } else {
- // Restarting...
- if (canvasAWT != null) {
- canvasAWT.removeGLEventListener(listener);
- pg.parent.removeListeners(canvasAWT);
- pg.parent.remove(canvasAWT);
- } else if (canvasNEWT != null) {
- window.removeGLEventListener(listener);
- pg.parent.remove(canvasNEWT);
- }
- sinkFBO = backFBO = frontFBO = null;
- }
+ protected abstract void reinitSurface();
- // Setting up the desired capabilities;
- GLCapabilities caps = reqCaps == null ? new GLCapabilities(profile) :
- reqCaps;
- caps.setBackgroundOpaque(true);
- caps.setOnscreen(true);
- if (USE_FBOLAYER_BY_DEFAULT) {
- if (USE_JOGL_FBOLAYER) {
- caps.setPBuffer(false);
- caps.setFBO(true);
- if (1 < antialias) {
- caps.setSampleBuffers(true);
- caps.setNumSamples(antialias);
- } else {
- caps.setSampleBuffers(false);
- }
- fboLayerRequested = false;
- } else {
- caps.setPBuffer(false);
- caps.setFBO(false);
- caps.setSampleBuffers(false);
- fboLayerRequested = 1 < antialias;
- }
- } else {
- if (1 < antialias) {
- caps.setSampleBuffers(true);
- caps.setNumSamples(antialias);
- } else {
- caps.setSampleBuffers(false);
- }
- fboLayerRequested = false;
- }
- caps.setDepthBits(REQUESTED_DEPTH_BITS);
- caps.setStencilBits(REQUESTED_STENCIL_BITS);
- caps.setAlphaBits(REQUESTED_ALPHA_BITS);
- reqNumSamples = qualityToSamples(antialias);
- if (WINDOW_TOOLKIT == AWT) {
- if (sharedCtx == null) {
- canvasAWT = new GLCanvas(caps);
- } else {
- canvasAWT = new GLCanvas(caps, sharedCtx);
- }
- canvasAWT.setBounds(0, 0, pg.width, pg.height);
- canvasAWT.setBackground(new Color(pg.backgroundColor, true));
- canvasAWT.setFocusable(true);
-
- pg.parent.setLayout(new BorderLayout());
- pg.parent.add(canvasAWT, BorderLayout.CENTER);
- canvasAWT.requestFocusInWindow();
-
- pg.parent.removeListeners(pg.parent);
- pg.parent.addListeners(canvasAWT);
-
- canvas = canvasAWT;
- canvasNEWT = null;
-
- listener = new PGLListener();
- canvasAWT.addGLEventListener(listener);
- } else if (WINDOW_TOOLKIT == NEWT) {
- window = GLWindow.create(caps);
- if (sharedCtx != null) {
- window.setSharedContext(sharedCtx);
- }
- canvasNEWT = new NewtCanvasAWT(window);
- canvasNEWT.setBounds(0, 0, pg.width, pg.height);
- canvasNEWT.setBackground(new Color(pg.backgroundColor, true));
- canvasNEWT.setFocusable(true);
-
- pg.parent.setLayout(new BorderLayout());
- pg.parent.add(canvasNEWT, BorderLayout.CENTER);
- canvasNEWT.requestFocusInWindow();
-
- if (EVENTS_TOOLKIT == NEWT) {
- NEWTMouseListener mouseListener = new NEWTMouseListener();
- window.addMouseListener(mouseListener);
- NEWTKeyListener keyListener = new NEWTKeyListener();
- window.addKeyListener(keyListener);
- NEWTWindowListener winListener = new NEWTWindowListener();
- window.addWindowListener(winListener);
- } else if (EVENTS_TOOLKIT == AWT) {
- pg.parent.removeListeners(canvasNEWT);
- pg.parent.addListeners(canvasNEWT);
- }
-
- canvas = canvasNEWT;
- canvasAWT = null;
-
- listener = new PGLListener();
- window.addGLEventListener(listener);
- }
-
- fboLayerCreated = false;
- fboLayerInUse = false;
- firstFrame = true;
-
- setFps = false;
- }
+ protected abstract void registerListeners();
protected void deleteSurface() {
@@ -623,75 +357,36 @@ public class PGL {
deleteRenderbuffers(1, glStencil);
}
- if (canvasAWT != null) {
- canvasAWT.removeGLEventListener(listener);
- pg.parent.removeListeners(canvasAWT);
- } else if (canvasNEWT != null) {
- window.removeGLEventListener(listener);
- }
-
fboLayerCreated = false;
fboLayerInUse = false;
firstFrame = false;
-
- GLProfile.shutdown();
}
- protected int getReadFramebuffer() {
- if (fboLayerInUse) {
- return glColorFbo.get(0);
- } else if (capabilities.isFBO()) {
- return context.getDefaultReadFramebuffer();
- } else {
- return 0;
- }
+ protected int getReadFramebuffer() {
+ return fboLayerInUse ? glColorFbo.get(0) : 0;
}
- protected int getDrawFramebuffer() {
- if (fboLayerInUse) {
- if (1 < numSamples) {
- return glMultiFbo.get(0);
- } else {
- return glColorFbo.get(0);
- }
- } else if (capabilities.isFBO()) {
- return context.getDefaultDrawFramebuffer();
- } else {
- return 0;
- }
+ protected int getDrawFramebuffer() {
+ if (fboLayerInUse) return 1 < numSamples ? glMultiFbo.get(0) :
+ glColorFbo.get(0);
+ else return 0;
}
- protected int getDefaultDrawBuffer() {
- if (fboLayerInUse) {
- return COLOR_ATTACHMENT0;
- } else if (capabilities.isFBO()) {
- return GL.GL_COLOR_ATTACHMENT0;
- } else if (capabilities.getDoubleBuffered()) {
- return GL.GL_BACK;
- } else {
- return GL.GL_FRONT;
- }
+ protected int getDefaultDrawBuffer() {
+ return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT;
}
- protected int getDefaultReadBuffer() {
- if (fboLayerInUse) {
- return COLOR_ATTACHMENT0;
- } else if (capabilities.isFBO()) {
- return GL.GL_COLOR_ATTACHMENT0;
- } else if (capabilities.getDoubleBuffered()) {
- return GL.GL_BACK;
- } else {
- return GL.GL_FRONT;
- }
+ protected int getDefaultReadBuffer() {
+ return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT;
}
protected boolean isFBOBacked() {
- return fboLayerInUse || capabilities.isFBO();
+ return fboLayerInUse;
}
@@ -705,25 +400,17 @@ public class PGL {
}
- protected int getDepthBits() {
- if (USE_JOGL_FBOLAYER) {
- return capabilities.getDepthBits();
- } else {
- intBuffer.rewind();
- getIntegerv(DEPTH_BITS, intBuffer);
- return intBuffer.get(0);
- }
+ protected int getDepthBits() {
+ intBuffer.rewind();
+ getIntegerv(DEPTH_BITS, intBuffer);
+ return intBuffer.get(0);
}
- protected int getStencilBits() {
- if (USE_JOGL_FBOLAYER) {
- return capabilities.getStencilBits();
- } else {
- intBuffer.rewind();
- getIntegerv(STENCIL_BITS, intBuffer);
- return intBuffer.get(0);
- }
+ protected int getStencilBits() {
+ intBuffer.rewind();
+ getIntegerv(STENCIL_BITS, intBuffer);
+ return intBuffer.get(0);
}
@@ -742,64 +429,33 @@ public class PGL {
protected Texture wrapBackTexture(Texture texture) {
- if (texture == null || changedBackTex) {
- if (USE_JOGL_FBOLAYER) {
- texture = new Texture();
- texture.init(pg.width, pg.height,
- backTexAttach.getName(), TEXTURE_2D, RGBA,
- backTexAttach.getWidth(), backTexAttach.getHeight(),
- backTexAttach.minFilter, backTexAttach.magFilter,
- backTexAttach.wrapS, backTexAttach.wrapT);
- texture.invertedY(true);
- texture.colorBuffer(true);
- pg.setCache(pg, texture);
- } else {
- texture = new Texture();
- texture.init(pg.width, pg.height,
- glColorTex.get(backTex), TEXTURE_2D, RGBA,
- fboWidth, fboHeight, NEAREST, NEAREST,
- CLAMP_TO_EDGE, CLAMP_TO_EDGE);
- texture.invertedY(true);
- texture.colorBuffer(true);
- pg.setCache(pg, texture);
- }
+ if (texture == null) {
+ texture = new Texture();
+ texture.init(pg.width, pg.height,
+ glColorTex.get(backTex), TEXTURE_2D, RGBA,
+ fboWidth, fboHeight, NEAREST, NEAREST,
+ CLAMP_TO_EDGE, CLAMP_TO_EDGE);
+ texture.invertedY(true);
+ texture.colorBuffer(true);
+ pg.setCache(pg, texture);
} else {
- if (USE_JOGL_FBOLAYER) {
- texture.glName = backTexAttach.getName();
- } else {
- texture.glName = glColorTex.get(backTex);
- }
+ texture.glName = glColorTex.get(backTex);
}
return texture;
}
- protected Texture wrapFrontTexture(Texture texture) {
- if (texture == null || changedFrontTex) {
- if (USE_JOGL_FBOLAYER) {
- texture = new Texture();
- texture.init(pg.width, pg.height,
- backTexAttach.getName(), TEXTURE_2D, RGBA,
- frontTexAttach.getWidth(), frontTexAttach.getHeight(),
- frontTexAttach.minFilter, frontTexAttach.magFilter,
- frontTexAttach.wrapS, frontTexAttach.wrapT);
- texture.invertedY(true);
- texture.colorBuffer(true);
- } else {
- texture = new Texture();
- texture.init(pg.width, pg.height,
- glColorTex.get(frontTex), TEXTURE_2D, RGBA,
- fboWidth, fboHeight, NEAREST, NEAREST,
- CLAMP_TO_EDGE, CLAMP_TO_EDGE);
- texture.invertedY(true);
- texture.colorBuffer(true);
- }
+ protected Texture wrapFrontTexture(Texture texture) {
+ if (texture == null) {
+ texture = new Texture();
+ texture.init(pg.width, pg.height,
+ glColorTex.get(frontTex), TEXTURE_2D, RGBA,
+ fboWidth, fboHeight, NEAREST, NEAREST,
+ CLAMP_TO_EDGE, CLAMP_TO_EDGE);
+ texture.invertedY(true);
+ texture.colorBuffer(true);
} else {
- if (USE_JOGL_FBOLAYER) {
- texture.glName = frontTexAttach.getName();
- } else {
- texture.glName = glColorTex.get(frontTex);
- }
+ texture.glName = glColorTex.get(frontTex);
}
return texture;
}
@@ -807,44 +463,23 @@ public class PGL {
protected void bindFrontTexture() {
usingFrontTex = true;
- if (USE_JOGL_FBOLAYER) {
- if (!texturingIsEnabled(TEXTURE_2D)) {
- enableTexturing(TEXTURE_2D);
- }
- bindTexture(TEXTURE_2D, frontTexAttach.getName());
- } else {
- if (!texturingIsEnabled(TEXTURE_2D)) {
- enableTexturing(TEXTURE_2D);
- }
- bindTexture(TEXTURE_2D, glColorTex.get(frontTex));
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
}
+ bindTexture(TEXTURE_2D, glColorTex.get(frontTex));
}
protected void unbindFrontTexture() {
- if (USE_JOGL_FBOLAYER) {
- if (textureIsBound(TEXTURE_2D, frontTexAttach.getName())) {
- // We don't want to unbind another texture
- // that might be bound instead of this one.
- if (!texturingIsEnabled(TEXTURE_2D)) {
- enableTexturing(TEXTURE_2D);
- bindTexture(TEXTURE_2D, 0);
- disableTexturing(TEXTURE_2D);
- } else {
- bindTexture(TEXTURE_2D, 0);
- }
- }
- } else {
- if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) {
- // We don't want to unbind another texture
- // that might be bound instead of this one.
- if (!texturingIsEnabled(TEXTURE_2D)) {
- enableTexturing(TEXTURE_2D);
- bindTexture(TEXTURE_2D, 0);
- disableTexturing(TEXTURE_2D);
- } else {
- bindTexture(TEXTURE_2D, 0);
- }
+ if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) {
+ // We don't want to unbind another texture
+ // that might be bound instead of this one.
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ bindTexture(TEXTURE_2D, 0);
+ disableTexturing(TEXTURE_2D);
+ } else {
+ bindTexture(TEXTURE_2D, 0);
}
}
}
@@ -852,19 +487,12 @@ public class PGL {
protected void syncBackTexture() {
if (usingFrontTex) needSepFrontTex = true;
- if (USE_JOGL_FBOLAYER) {
- if (1 < numSamples) {
- backFBO.syncSamplingSink(gl);
- backFBO.bind(gl);
- }
- } else {
- if (1 < numSamples) {
- bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0));
- bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0));
- blitFramebuffer(0, 0, fboWidth, fboHeight,
- 0, 0, fboWidth, fboHeight,
- COLOR_BUFFER_BIT, NEAREST);
- }
+ if (1 < numSamples) {
+ bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0));
+ bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0));
+ blitFramebuffer(0, 0, fboWidth, fboHeight,
+ 0, 0, fboWidth, fboHeight,
+ COLOR_BUFFER_BIT, NEAREST);
}
}
@@ -899,8 +527,8 @@ public class PGL {
boolean multisample = 1 < numSamples;
boolean packed = ext.indexOf("packed_depth_stencil") != -1;
- int depthBits = getDepthBits();
- int stencilBits = getStencilBits();
+ int depthBits = PApplet.min(REQUESTED_DEPTH_BITS, getDepthBits());
+ int stencilBits = PApplet.min(REQUESTED_STENCIL_BITS, getStencilBits());
genTextures(2, glColorTex);
for (int i = 0; i < 2; i++) {
@@ -1027,10 +655,6 @@ public class PGL {
protected void beginDraw(boolean clear0) {
- if (!setFps) setFps(targetFps);
-
- if (USE_JOGL_FBOLAYER) return;
-
if (needFBOLayer(clear0)) {
if (!fboLayerCreated) createFBOLayer();
@@ -1081,112 +705,44 @@ public class PGL {
protected void endDraw(boolean clear0) {
- if (isFBOBacked()) {
- if (USE_JOGL_FBOLAYER) {
- if (!clear0 && isFBOBacked() && !isMultisampled()) {
- // Draw the back texture into the front texture, which will be used as
- // back texture in the next frame. Otherwise flickering will occur if
- // the sketch uses "incremental drawing" (background() not called).
- frontFBO.bind(gl);
- gl.glDisable(GL.GL_BLEND);
- drawTexture(TEXTURE_2D, backTexAttach.getName(),
- backTexAttach.getWidth(), backTexAttach.getHeight(),
- pg.width, pg.height,
- 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height);
- backFBO.bind(gl);
- }
- } else if (fboLayerInUse) {
- syncBackTexture();
+ if (fboLayerInUse) {
+ syncBackTexture();
- // Draw the contents of the back texture to the screen framebuffer.
- bindFramebuffer(FRAMEBUFFER, 0);
+ // Draw the contents of the back texture to the screen framebuffer.
+ bindFramebuffer(FRAMEBUFFER, 0);
- clearDepth(1);
- clearColor(0, 0, 0, 0);
- clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
+ clearDepth(1);
+ clearColor(0, 0, 0, 0);
+ clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
- // Render current back texture to screen, without blending.
- disable(BLEND);
- drawTexture(TEXTURE_2D, glColorTex.get(backTex),
- fboWidth, fboHeight, pg.width, pg.height,
- 0, 0, pg.width, pg.height,
- 0, 0, pg.width, pg.height);
+ // Render current back texture to screen, without blending.
+ disable(BLEND);
+ drawTexture(TEXTURE_2D, glColorTex.get(backTex),
+ fboWidth, fboHeight, pg.width, pg.height,
+ 0, 0, pg.width, pg.height,
+ 0, 0, pg.width, pg.height);
- // Swapping front and back textures.
- int temp = frontTex;
- frontTex = backTex;
- backTex = temp;
- }
- }
-
- // call (gl)finish() only if the rendering of each frame is taking too long,
- // to make sure that commands are not accumulating in the GL command queue.
- fcount += 1;
- int m = pg.parent.millis();
- if (m - lastm > 1000 * fint) {
- currentFps = (float)(fcount) / fint;
- fcount = 0;
- lastm = m;
- }
- if (currentFps < targetFps/2) {
- finish();
+ // Swapping front and back textures.
+ int temp = frontTex;
+ frontTex = backTex;
+ backTex = temp;
}
}
- protected void requestFocus() {
- if (canvas != null) {
- canvas.requestFocus();
- }
- }
+ protected abstract boolean canDraw();
- protected boolean canDraw() {
- return pg.initialized && pg.parent.isDisplayable();
- }
+ protected abstract void requestFocus();
- protected void requestDraw() {
- boolean canDraw = pg.parent.canDraw();
- if (pg.initialized && (canDraw || prevCanDraw)) {
- try {
- drawLatch = new CountDownLatch(1);
- if (WINDOW_TOOLKIT == AWT) {
- canvasAWT.display();
- } else if (WINDOW_TOOLKIT == NEWT) {
- window.display();
- }
- try {
- drawLatch.await(DRAW_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- if (canDraw) prevCanDraw = true;
- else prevCanDraw = false;
- } catch (GLException e) {
- // Unwrap GLException so that only the causing exception is shown.
- Throwable tr = e.getCause();
- if (tr instanceof RuntimeException) {
- throw (RuntimeException)tr;
- } else {
- throw new RuntimeException(tr);
- }
- }
- }
- }
+ protected abstract void requestDraw();
- protected void swapBuffers() {
- if (WINDOW_TOOLKIT == AWT) {
- canvasAWT.swapBuffers();
- } else if (WINDOW_TOOLKIT == NEWT) {
- window.swapBuffers();
- }
- }
+ protected abstract void swapBuffers();
- protected boolean threadIsCurrent() {
+ protected boolean threadIsCurrent() {
return Thread.currentThread() == glThread;
}
@@ -1196,55 +752,10 @@ public class PGL {
}
- protected void beginGL() {
- if (projMatrix == null) {
- projMatrix = new float[16];
- }
- gl2x.glMatrixMode(GL2.GL_PROJECTION);
- projMatrix[ 0] = pg.projection.m00;
- projMatrix[ 1] = pg.projection.m10;
- projMatrix[ 2] = pg.projection.m20;
- projMatrix[ 3] = pg.projection.m30;
- projMatrix[ 4] = pg.projection.m01;
- projMatrix[ 5] = pg.projection.m11;
- projMatrix[ 6] = pg.projection.m21;
- projMatrix[ 7] = pg.projection.m31;
- projMatrix[ 8] = pg.projection.m02;
- projMatrix[ 9] = pg.projection.m12;
- projMatrix[10] = pg.projection.m22;
- projMatrix[11] = pg.projection.m32;
- projMatrix[12] = pg.projection.m03;
- projMatrix[13] = pg.projection.m13;
- projMatrix[14] = pg.projection.m23;
- projMatrix[15] = pg.projection.m33;
- gl2x.glLoadMatrixf(projMatrix, 0);
-
- if (mvMatrix == null) {
- mvMatrix = new float[16];
- }
- gl2x.glMatrixMode(GL2.GL_MODELVIEW);
- mvMatrix[ 0] = pg.modelview.m00;
- mvMatrix[ 1] = pg.modelview.m10;
- mvMatrix[ 2] = pg.modelview.m20;
- mvMatrix[ 3] = pg.modelview.m30;
- mvMatrix[ 4] = pg.modelview.m01;
- mvMatrix[ 5] = pg.modelview.m11;
- mvMatrix[ 6] = pg.modelview.m21;
- mvMatrix[ 7] = pg.modelview.m31;
- mvMatrix[ 8] = pg.modelview.m02;
- mvMatrix[ 9] = pg.modelview.m12;
- mvMatrix[10] = pg.modelview.m22;
- mvMatrix[11] = pg.modelview.m32;
- mvMatrix[12] = pg.modelview.m03;
- mvMatrix[13] = pg.modelview.m13;
- mvMatrix[14] = pg.modelview.m23;
- mvMatrix[15] = pg.modelview.m33;
- gl2x.glLoadMatrixf(mvMatrix, 0);
- }
+ protected void beginGL() { }
- protected void endGL() {
- }
+ protected void endGL() { }
///////////////////////////////////////////////////////////
@@ -1258,144 +769,7 @@ public class PGL {
protected int getCurrentContext() {
- return context.hashCode();
- }
-
-
- ///////////////////////////////////////////////////////////
-
- // Tessellator interface
-
-
- protected Tessellator createTessellator(TessellatorCallback callback) {
- return new Tessellator(callback);
- }
-
-
- protected class Tessellator {
- protected GLUtessellator tess;
- protected TessellatorCallback callback;
- protected GLUCallback gluCallback;
-
- public Tessellator(TessellatorCallback callback) {
- this.callback = callback;
- tess = GLU.gluNewTess();
- gluCallback = new GLUCallback();
-
- GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback);
- GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback);
- GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback);
- GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback);
- GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback);
- }
-
- public void beginPolygon() {
- GLU.gluTessBeginPolygon(tess, null);
- }
-
- public void endPolygon() {
- GLU.gluTessEndPolygon(tess);
- }
-
- public void setWindingRule(int rule) {
- GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule);
- }
-
- public void beginContour() {
- GLU.gluTessBeginContour(tess);
- }
-
- public void endContour() {
- GLU.gluTessEndContour(tess);
- }
-
- public void addVertex(double[] v) {
- GLU.gluTessVertex(tess, v, 0, v);
- }
-
- protected class GLUCallback extends GLUtessellatorCallbackAdapter {
- @Override
- public void begin(int type) {
- callback.begin(type);
- }
-
- @Override
- public void end() {
- callback.end();
- }
-
- @Override
- public void vertex(Object data) {
- callback.vertex(data);
- }
-
- @Override
- public void combine(double[] coords, Object[] data,
- float[] weight, Object[] outData) {
- callback.combine(coords, data, weight, outData);
- }
-
- @Override
- public void error(int errnum) {
- callback.error(errnum);
- }
- }
- }
-
- protected String tessError(int err) {
- return glu.gluErrorString(err);
- }
-
- protected interface TessellatorCallback {
- public void begin(int type);
- public void end();
- public void vertex(Object data);
- public void combine(double[] coords, Object[] data,
- float[] weight, Object[] outData);
- public void error(int errnum);
- }
-
-
- ///////////////////////////////////////////////////////////
-
- // FontOutline interface
-
-
- protected final static boolean SHAPE_TEXT_SUPPORTED = true;
-
- protected final static int SEG_MOVETO = PathIterator.SEG_MOVETO;
- protected final static int SEG_LINETO = PathIterator.SEG_LINETO;
- protected final static int SEG_QUADTO = PathIterator.SEG_QUADTO;
- protected final static int SEG_CUBICTO = PathIterator.SEG_CUBICTO;
- protected final static int SEG_CLOSE = PathIterator.SEG_CLOSE;
-
- protected FontOutline createFontOutline(char ch, Object font) {
- return new FontOutline(ch, font);
- }
-
- protected class FontOutline {
- PathIterator iter;
-
- public FontOutline(char ch, Object font) {
- char textArray[] = new char[] { ch };
- Graphics2D graphics = (Graphics2D) pg.parent.getGraphics();
- FontRenderContext frc = graphics.getFontRenderContext();
- GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray);
- Shape shp = gv.getOutline();
- iter = shp.getPathIterator(null);
- }
-
- public boolean isDone() {
- return iter.isDone();
- }
-
- public int currentSegment(float coords[]) {
- return iter.currentSegment(coords);
- }
-
- public void next() {
- iter.next();
- }
+ return glContext;
}
@@ -1405,7 +779,7 @@ public class PGL {
protected boolean contextIsCurrent(int other) {
- return other == -1 || other == context.hashCode();
+ return other == -1 || other == glContext;
}
@@ -1459,7 +833,7 @@ public class PGL {
protected void initTexture(int target, int format, int width, int height,
- int initColor) {
+ int initColor) {
int[] glcolor = new int[16 * 16];
Arrays.fill(glcolor, javaToNativeARGB(initColor));
IntBuffer texels = PGL.allocateDirectIntBuffer(16 * 16);
@@ -1492,17 +866,23 @@ public class PGL {
}
- protected void drawTexture(int target, int id, int width, int height,
- int X0, int Y0, int X1, int Y1) {
+ /**
+ * Not an approved function, this will change or be removed in the future.
+ */
+ public void drawTexture(int target, int id, int width, int height,
+ int X0, int Y0, int X1, int Y1) {
drawTexture(target, id, width, height, width, height,
X0, Y0, X1, Y1, X0, Y0, X1, Y1);
}
- protected void drawTexture(int target, int id,
- int texW, int texH, int scrW, int scrH,
- int texX0, int texY0, int texX1, int texY1,
- int scrX0, int scrY0, int scrX1, int scrY1) {
+ /**
+ * Not an approved function, this will change or be removed in the future.
+ */
+ public void drawTexture(int target, int id,
+ int texW, int texH, int scrW, int scrH,
+ int texX0, int texY0, int texX1, int texY1,
+ int scrX0, int scrY0, int scrX1, int scrY1) {
if (target == TEXTURE_2D) {
drawTexture2D(id, texW, texH, scrW, scrH,
texX0, texY0, texX1, texY1,
@@ -1515,27 +895,39 @@ public class PGL {
}
- protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH,
- int texX0, int texY0, int texX1, int texY1,
- int scrX0, int scrY0, int scrX1, int scrY1) {
- if (!loadedTex2DShader ||
- tex2DShaderContext.hashCode() != context.hashCode()) {
- tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource);
- tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource);
+ protected void initTex2DShader() {
+ if (!loadedTex2DShader || tex2DShaderContext != glContext) {
+ String vertSource = PApplet.join(texVertShaderSource, "\n");
+ String fragSource = PApplet.join(tex2DFragShaderSource, "\n");
+ tex2DVertShader = createShader(VERTEX_SHADER, vertSource);
+ tex2DFragShader = createShader(FRAGMENT_SHADER, fragSource);
if (0 < tex2DVertShader && 0 < tex2DFragShader) {
tex2DShaderProgram = createProgram(tex2DVertShader, tex2DFragShader);
}
if (0 < tex2DShaderProgram) {
- tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "inVertex");
- tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord");
+ tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "position");
+ tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "texCoord");
+ tex2DSamplerLoc = getUniformLocation(tex2DShaderProgram, "texMap");
}
loadedTex2DShader = true;
- tex2DShaderContext = context;
+ tex2DShaderContext = glContext;
+
+ genBuffers(1, intBuffer);
+ texGeoVBO = intBuffer.get(0);
+ bindBuffer(ARRAY_BUFFER, texGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
}
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
}
+ }
+
+
+ protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH,
+ int texX0, int texY0, int texX1, int texY1,
+ int scrX0, int scrY0, int scrX1, int scrY1) {
+ initTex2DShader();
if (0 < tex2DShaderProgram) {
// The texture overwrites anything drawn earlier.
@@ -1549,6 +941,11 @@ public class PGL {
boolean depthMask = getDepthWriteMask();
depthMask(false);
+ // Making sure that the viewport matches the provided screen dimensions
+ viewBuffer.rewind();
+ getIntegerv(VIEWPORT, viewBuffer);
+ viewport(0, 0, scrW, scrH);
+
useProgram(tex2DShaderProgram);
enableVertexAttribArray(tex2DVertLoc);
@@ -1587,18 +984,19 @@ public class PGL {
enabledTex = true;
}
bindTexture(TEXTURE_2D, id);
-
- bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+ uniform1i(tex2DSamplerLoc, 0);
texData.position(0);
- vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
- texData);
- texData.position(2);
- vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
- texData);
+ bindBuffer(PGL.ARRAY_BUFFER, texGeoVBO);
+ bufferData(PGL.ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, PGL.STATIC_DRAW);
+
+ vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
+ vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 2 * SIZEOF_FLOAT);
drawArrays(TRIANGLE_STRIP, 0, 4);
+ bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+
bindTexture(TEXTURE_2D, 0);
if (enabledTex) {
disableTexturing(TEXTURE_2D);
@@ -1615,6 +1013,35 @@ public class PGL {
disable(DEPTH_TEST);
}
depthMask(depthMask);
+
+ viewport(viewBuffer.get(0), viewBuffer.get(1),
+ viewBuffer.get(2),viewBuffer.get(3));
+ }
+ }
+
+
+ protected void initTexRectShader() {
+ if (!loadedTexRectShader || texRectShaderContext != glContext) {
+ String vertSource = PApplet.join(texVertShaderSource, "\n");
+ String fragSource = PApplet.join(texRectFragShaderSource, "\n");
+ texRectVertShader = createShader(VERTEX_SHADER, vertSource);
+ texRectFragShader = createShader(FRAGMENT_SHADER, fragSource);
+ if (0 < texRectVertShader && 0 < texRectFragShader) {
+ texRectShaderProgram = createProgram(texRectVertShader,
+ texRectFragShader);
+ }
+ if (0 < texRectShaderProgram) {
+ texRectVertLoc = getAttribLocation(texRectShaderProgram, "position");
+ texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "texCoord");
+ texRectSamplerLoc = getUniformLocation(texRectShaderProgram, "texMap");
+ }
+ loadedTexRectShader = true;
+ texRectShaderContext = glContext;
+
+ genBuffers(1, intBuffer);
+ texGeoVBO = intBuffer.get(0);
+ bindBuffer(ARRAY_BUFFER, texGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
}
}
@@ -1622,21 +1049,7 @@ public class PGL {
protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
- if (!loadedTexRectShader ||
- texRectShaderContext.hashCode() != context.hashCode()) {
- texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource);
- texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource);
- if (0 < texRectVertShader && 0 < texRectFragShader) {
- texRectShaderProgram = createProgram(texRectVertShader,
- texRectFragShader);
- }
- if (0 < texRectShaderProgram) {
- texRectVertLoc = getAttribLocation(texRectShaderProgram, "inVertex");
- texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord");
- }
- loadedTexRectShader = true;
- texRectShaderContext = context;
- }
+ initTexRectShader();
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
@@ -1654,6 +1067,11 @@ public class PGL {
boolean depthMask = getDepthWriteMask();
depthMask(false);
+ // Making sure that the viewport matches the provided screen dimensions
+ viewBuffer.rewind();
+ getIntegerv(VIEWPORT, viewBuffer);
+ viewport(0, 0, scrW, scrH);
+
useProgram(texRectShaderProgram);
enableVertexAttribArray(texRectVertLoc);
@@ -1692,18 +1110,19 @@ public class PGL {
enabledTex = true;
}
bindTexture(TEXTURE_RECTANGLE, id);
-
- bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+ uniform1i(texRectSamplerLoc, 0);
texData.position(0);
- vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
- texData);
- texData.position(2);
- vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
- texData);
+ bindBuffer(PGL.ARRAY_BUFFER, texGeoVBO);
+ bufferData(PGL.ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, PGL.STATIC_DRAW);
+
+ vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
+ vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 2 * SIZEOF_FLOAT);
drawArrays(TRIANGLE_STRIP, 0, 4);
+ bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+
bindTexture(TEXTURE_RECTANGLE, 0);
if (enabledTex) {
disableTexturing(TEXTURE_RECTANGLE);
@@ -1720,6 +1139,9 @@ public class PGL {
disable(DEPTH_TEST);
}
depthMask(depthMask);
+
+ viewport(viewBuffer.get(0), viewBuffer.get(1),
+ viewBuffer.get(2),viewBuffer.get(3));
}
}
@@ -1771,14 +1193,13 @@ public class PGL {
* endian) to Java ARGB.
*/
protected static int nativeToJavaARGB(int color) {
- if (BIG_ENDIAN) { // RGBA to ARGB
- return (color & 0xff000000) |
- ((color >> 8) & 0x00ffffff);
+ if (PGL.BIG_ENDIAN) { // RGBA to ARGB
+ return (color >>> 8) | ((color << 24) & 0xFF000000);
+ // equivalent to
+ // ((color >> 8) & 0x00FFFFFF) | ((color << 24) & 0xFF000000)
} else { // ABGR to ARGB
- return (color & 0xff000000) |
- ((color << 16) & 0xff0000) |
- (color & 0xff00) |
- ((color >> 16) & 0xff);
+ return ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16) |
+ (color & 0xFF00FF00);
}
}
@@ -1793,51 +1214,35 @@ public class PGL {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
- if (BIG_ENDIAN) { // RGBA to ARGB
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = (pixels[yindex] & 0xff000000) |
- ((pixels[yindex] >> 8) & 0x00ffffff);
- pixels[yindex] = (temp & 0xff000000) |
- ((temp >> 8) & 0x00ffffff);
- index++;
- yindex++;
- }
- } else { // ABGR to ARGB
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = (pixels[yindex] & 0xff000000) |
- ((pixels[yindex] << 16) & 0xff0000) |
- (pixels[yindex] & 0xff00) |
- ((pixels[yindex] >> 16) & 0xff);
- pixels[yindex] = (temp & 0xff000000) |
- ((temp << 16) & 0xff0000) |
- (temp & 0xff00) |
- ((temp >> 16) & 0xff);
- index++;
- yindex++;
+ for (int x = 0; x < width; x++) {
+ int pixy = pixels[yindex];
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ pixels[index] = (pixy >>> 8) | ((pixy << 24) & 0xFF000000);
+ pixels[yindex] = (pixi >>> 8) | ((pixi << 24) & 0xFF000000);
+ } else { // ABGR to ARGB
+ pixels[index] = ((pixy & 0xFF) << 16) | ((pixy & 0xFF0000) >> 16) |
+ (pixy & 0xFF00FF00);
+ pixels[yindex] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
+ (pixi & 0xFF00FF00);
}
+ index++;
+ yindex++;
}
yindex -= width * 2;
}
- // Flips image
- if ((height % 2) == 1) {
+ if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
- if (BIG_ENDIAN) { // RGBA to ARGB
- for (int x = 0; x < width; x++) {
- pixels[index] = (pixels[index] & 0xff000000) |
- ((pixels[index] >> 8) & 0x00ffffff);
- index++;
- }
- } else { // ABGR to ARGB
- for (int x = 0; x < width; x++) {
- pixels[index] = (pixels[index] & 0xff000000) |
- ((pixels[index] << 16) & 0xff0000) |
- (pixels[index] & 0xff00) |
- ((pixels[index] >> 16) & 0xff);
- index++;
+ for (int x = 0; x < width; x++) {
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ pixels[index] = (pixi >>> 8) | ((pixi << 24) & 0xFF000000);
+ } else { // ABGR to ARGB
+ pixels[index] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
+ (pixi & 0xFF00FF00);
}
+ index++;
}
}
}
@@ -1850,11 +1255,10 @@ public class PGL {
*/
protected static int nativeToJavaRGB(int color) {
if (BIG_ENDIAN) { // RGBA to ARGB
- return ((color << 8) & 0xffffff00) | 0xff;
+ return (color >>> 8) | 0xFF000000;
} else { // ABGR to ARGB
- return 0xff000000 | ((color << 16) & 0xff0000) |
- (color & 0xff00) |
- ((color >> 16) & 0xff);
+ return ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16) |
+ (color & 0xFF00FF00) | 0xFF000000;
}
}
@@ -1870,45 +1274,35 @@ public class PGL {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
- if (BIG_ENDIAN) { // RGBA to ARGB
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff);
- pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff);
- index++;
- yindex++;
- }
- } else { // ABGR to ARGB
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
- (pixels[yindex] & 0xff00) |
- ((pixels[yindex] >> 16) & 0xff);
- pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
- (temp & 0xff00) |
- ((temp >> 16) & 0xff);
- index++;
- yindex++;
+ for (int x = 0; x < width; x++) {
+ int pixy = pixels[yindex];
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ pixels[index] = (pixy >>> 8) | 0xFF000000;
+ pixels[yindex] = (pixi >>> 8) | 0xFF000000;
+ } else { // ABGR to ARGB
+ pixels[index] = ((pixy & 0xFF) << 16) | ((pixy & 0xFF0000) >> 16) |
+ (pixy & 0xFF00FF00) | 0xFF000000;
+ pixels[yindex] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
+ (pixi & 0xFF00FF00) | 0xFF000000;
}
+ index++;
+ yindex++;
}
yindex -= width * 2;
}
- // Flips image
- if ((height % 2) == 1) {
+ if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
- if (BIG_ENDIAN) { // RGBA to ARGB
- for (int x = 0; x < width; x++) {
- pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff);
- index++;
- }
- } else { // ABGR to ARGB
- for (int x = 0; x < width; x++) {
- pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
- (pixels[index] & 0xff00) |
- ((pixels[index] >> 16) & 0xff);
- index++;
+ for (int x = 0; x < width; x++) {
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ pixels[index] = (pixi >>> 8) | 0xFF000000;
+ } else { // ABGR to ARGB
+ pixels[index] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
+ (pixi & 0xFF00FF00) | 0xFF000000;
}
+ index++;
}
}
}
@@ -1920,13 +1314,10 @@ public class PGL {
*/
protected static int javaToNativeARGB(int color) {
if (BIG_ENDIAN) { // ARGB to RGBA
- return ((color >> 24) & 0xff) |
- ((color << 8) & 0xffffff00);
+ return ((color >> 24) & 0xFF) | ((color << 8) & 0xFFFFFF00);
} else { // ARGB to ABGR
- return (color & 0xff000000) |
- ((color << 16) & 0xff0000) |
- (color & 0xff00) |
- ((color >> 16) & 0xff);
+ return (color & 0xFF000000) | ((color << 16) & 0xFF0000) |
+ (color & 0xFF00) | ((color >> 16) & 0xFF);
}
}
@@ -1941,52 +1332,35 @@ public class PGL {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
- if (BIG_ENDIAN) { // ARGB to RGBA
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = ((pixels[yindex] >> 24) & 0xff) |
- ((pixels[yindex] << 8) & 0xffffff00);
- pixels[yindex] = ((temp >> 24) & 0xff) |
- ((temp << 8) & 0xffffff00);
- index++;
- yindex++;
- }
-
- } else { // ARGB to ABGR
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = (pixels[yindex] & 0xff000000) |
- ((pixels[yindex] << 16) & 0xff0000) |
- (pixels[yindex] & 0xff00) |
- ((pixels[yindex] >> 16) & 0xff);
- pixels[yindex] = (temp & 0xff000000) |
- ((temp << 16) & 0xff0000) |
- (temp & 0xff00) |
- ((temp >> 16) & 0xff);
- index++;
- yindex++;
+ for (int x = 0; x < width; x++) {
+ int pixy = pixels[yindex];
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ pixels[index] = ((pixy >> 24) & 0xFF) | ((pixy << 8) & 0xFFFFFF00);
+ pixels[yindex] = ((pixi >> 24) & 0xFF) | ((pixi << 8) & 0xFFFFFF00);
+ } else { // ARGB to ABGR
+ pixels[index] = (pixy & 0xFF000000) | ((pixy << 16) & 0xFF0000) |
+ (pixy & 0xFF00) | ((pixy >> 16) & 0xFF);
+ pixels[yindex] = (pixi & 0xFF000000) | ((pixi << 16) & 0xFF0000) |
+ (pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
+ index++;
+ yindex++;
}
yindex -= width * 2;
}
- // Flips image
- if ((height % 2) == 1) {
+ if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
- if (BIG_ENDIAN) { // ARGB to RGBA
- for (int x = 0; x < width; x++) {
- pixels[index] = ((pixels[index] >> 24) & 0xff) |
- ((pixels[index] << 8) & 0xffffff00);
- index++;
- }
- } else { // ARGB to ABGR
- for (int x = 0; x < width; x++) {
- pixels[index] = (pixels[index] & 0xff000000) |
- ((pixels[index] << 16) & 0xff0000) |
- (pixels[index] & 0xff00) |
- ((pixels[index] >> 16) & 0xff);
- index++;
+ for (int x = 0; x < width; x++) {
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ pixels[index] = ((pixi >> 24) & 0xFF) | ((pixi << 8) & 0xFFFFFF00);
+ } else { // ARGB to ABGR
+ pixels[index] = (pixi & 0xFF000000) | ((pixi << 16) & 0xFF0000) |
+ (pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
+ index++;
}
}
}
@@ -1997,12 +1371,11 @@ public class PGL {
* BGRA on little endian), setting alpha component to opaque (255).
*/
protected static int javaToNativeRGB(int color) {
- if (BIG_ENDIAN) { // ARGB to RGBA
- return ((color << 8) & 0xffffff00) | 0xff;
- } else { // ARGB to ABGR
- return 0xff000000 | ((color << 16) & 0xff0000) |
- (color & 0xff00) |
- ((color >> 16) & 0xff);
+ if (BIG_ENDIAN) { // ARGB to RGB
+ return 0xFF | ((color << 8) & 0xFFFFFF00);
+ } else { // ARGB to BGR
+ return 0xFF000000 | ((color << 16) & 0xFF0000) |
+ (color & 0xFF00) | ((color >> 16) & 0xFF);
}
}
@@ -2018,51 +1391,102 @@ public class PGL {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
- if (BIG_ENDIAN) { // ARGB to RGBA
- for (int x = 0; x < width; x++) {
- int temp = pixels[index];
- pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff;
- pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff;
- index++;
- yindex++;
- }
-
- } else {
- for (int x = 0; x < width; x++) { // ARGB to ABGR
- int temp = pixels[index];
- pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
- (pixels[yindex] & 0xff00) |
- ((pixels[yindex] >> 16) & 0xff);
- pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
- (temp & 0xff00) |
- ((temp >> 16) & 0xff);
- index++;
- yindex++;
+ for (int x = 0; x < width; x++) {
+ int pixy = pixels[yindex];
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // ARGB to RGB
+ pixels[index] = 0xFF | ((pixy << 8) & 0xFFFFFF00);
+ pixels[yindex] = 0xFF | ((pixi << 8) & 0xFFFFFF00);
+ } else { // ARGB to BGR
+ pixels[index] = 0xFF000000 | ((pixy << 16) & 0xFF0000) |
+ (pixy & 0xFF00) | ((pixy >> 16) & 0xFF);
+ pixels[yindex] = 0xFF000000 | ((pixi << 16) & 0xFF0000) |
+ (pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
+ index++;
+ yindex++;
}
yindex -= width * 2;
}
- // Flips image
- if ((height % 2) == 1) { // ARGB to RGBA
+ if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
- if (BIG_ENDIAN) {
- for (int x = 0; x < width; x++) {
- pixels[index] = ((pixels[index] << 8) & 0xffffff00) | 0xff;
- index++;
- }
- } else { // ARGB to ABGR
- for (int x = 0; x < width; x++) {
- pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
- (pixels[index] & 0xff00) |
- ((pixels[index] >> 16) & 0xff);
- index++;
+ for (int x = 0; x < width; x++) {
+ int pixi = pixels[index];
+ if (BIG_ENDIAN) { // ARGB to RGB
+ pixels[index] = 0xFF | ((pixi << 8) & 0xFFFFFF00);
+ } else { // ARGB to BGR
+ pixels[index] = 0xFF000000 | ((pixi << 16) & 0xFF0000) |
+ (pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
+ index++;
}
}
}
+ protected String[] loadVertexShader(String filename) {
+ return pg.parent.loadStrings(filename);
+ }
+
+
+ protected String[] loadFragmentShader(String filename) {
+ return pg.parent.loadStrings(filename);
+ }
+
+
+ protected String[] loadFragmentShader(URL url) {
+ try {
+ return PApplet.loadStrings(url.openStream());
+ } catch (IOException e) {
+ PGraphics.showException("Cannot load fragment shader " + url.getFile());
+ }
+ return null;
+ }
+
+
+ protected String[] loadVertexShader(URL url) {
+ try {
+ return PApplet.loadStrings(url.openStream());
+ } catch (IOException e) {
+ PGraphics.showException("Cannot load vertex shader " + url.getFile());
+ }
+ return null;
+ }
+
+
+ protected String[] loadVertexShader(String filename, int version) {
+ return loadVertexShader(filename);
+ }
+
+
+ protected String[] loadFragmentShader(String filename, int version) {
+ return loadFragmentShader(filename);
+ }
+
+
+ protected String[] loadFragmentShader(URL url, int version) {
+ return loadFragmentShader(url);
+ }
+
+
+ protected String[] loadVertexShader(URL url, int version) {
+ return loadVertexShader(url);
+ }
+
+
+ protected String[] convertFragmentSource(String[] fragSrc0,
+ int version0, int version1) {
+ return fragSrc0;
+ }
+
+
+ protected String[] convertVertexSource(String[] vertSrc0,
+ int version0, int version1) {
+ return vertSrc0;
+ }
+
+
protected int createShader(int shaderType, String source) {
int shader = createShader(shaderType);
if (shader != 0) {
@@ -2165,13 +1589,21 @@ public class PGL {
protected boolean hasFBOs() {
- return context.hasBasicFBOSupport();
+ // FBOs might still be available through extensions.
+ int major = getGLVersion()[0];
+ if (major < 2) {
+ String ext = getString(EXTENSIONS);
+ return ext.indexOf("_framebuffer_object") != -1 &&
+ ext.indexOf("_vertex_shader") != -1 &&
+ ext.indexOf("_shader_objects") != -1 &&
+ ext.indexOf("_shading_language") != -1;
+ } else {
+ return true;
+ }
}
protected boolean hasShaders() {
- if (context.hasGLSL()) return true;
-
// GLSL might still be available through extensions. For instance,
// GLContext.hasGLSL() gives false for older intel integrated chipsets on
// OSX, where OpenGL is 1.4 but shaders are available.
@@ -2182,19 +1614,76 @@ public class PGL {
ext.indexOf("_vertex_shader") != -1 &&
ext.indexOf("_shader_objects") != -1 &&
ext.indexOf("_shading_language") != -1;
+ } else {
+ return true;
}
+ }
- return false;
+
+ protected boolean hasNpotTexSupport() {
+ int major = getGLVersion()[0];
+ if (major < 3) {
+ String ext = getString(EXTENSIONS);
+ return -1 < ext.indexOf("_texture_non_power_of_two");
+ } else {
+ return true;
+ }
+ }
+
+
+ protected boolean hasAutoMipmapGenSupport() {
+ int major = getGLVersion()[0];
+ if (major < 3) {
+ String ext = getString(EXTENSIONS);
+ return -1 < ext.indexOf("_generate_mipmap");
+ } else {
+ return true;
+ }
+ }
+
+
+ protected boolean hasFboMultisampleSupport() {
+ int major = getGLVersion()[0];
+ if (major < 3) {
+ String ext = getString(EXTENSIONS);
+ return -1 < ext.indexOf("_framebuffer_multisample");
+ } else {
+ return true;
+ }
+ }
+
+
+ protected boolean hasPackedDepthStencilSupport() {
+ int major = getGLVersion()[0];
+ if (major < 3) {
+ String ext = getString(EXTENSIONS);
+ return -1 < ext.indexOf("_packed_depth_stencil");
+ } else {
+ return true;
+ }
+ }
+
+
+ protected boolean hasAnisoSamplingSupport() {
+ int major = getGLVersion()[0];
+ if (major < 3) {
+ String ext = getString(EXTENSIONS);
+ return -1 < ext.indexOf("_texture_filter_anisotropic");
+ } else {
+ return true;
+ }
}
protected int maxSamples() {
+ intBuffer.rewind();
getIntegerv(MAX_SAMPLES, intBuffer);
return intBuffer.get(0);
}
protected int getMaxTexUnits() {
+ intBuffer.rewind();
getIntegerv(MAX_TEXTURE_IMAGE_UNITS, intBuffer);
return intBuffer.get(0);
}
@@ -2554,269 +2043,81 @@ public class PGL {
}
+ // TODO: the next three functions shouldn't be here...
+
+ protected int getFontAscent(Object font) {
+ return 0;
+ }
+
+
+ protected int getFontDescent(Object font) {
+ return 0;
+ }
+
+
+ protected int getTextWidth(Object font, char buffer[], int start, int stop) {
+ return 0;
+ }
+
+
+ protected Object getDerivedFont(Object font, float size) {
+ return null;
+ }
+
+
///////////////////////////////////////////////////////////
- // Event listeners
- protected boolean changedFrontTex = false;
- protected boolean changedBackTex = false;
+ // Tessellator interface
- protected class PGLListener implements GLEventListener {
- public PGLListener() {}
- @Override
- public void display(GLAutoDrawable glDrawable) {
- drawable = glDrawable;
- context = glDrawable.getContext();
+ protected abstract Tessellator createTessellator(TessellatorCallback callback);
- glThread = Thread.currentThread();
- gl = context.getGL();
- gl2 = gl.getGL2ES2();
- try {
- gl2x = gl.getGL2();
- } catch (javax.media.opengl.GLException e) {
- gl2x = null;
- }
-
- if (USE_JOGL_FBOLAYER && capabilities.isFBO()) {
- // The onscreen drawing surface is backed by an FBO layer.
- GLFBODrawable fboDrawable = null;
-
- if (WINDOW_TOOLKIT == AWT) {
- GLCanvas glCanvas = (GLCanvas)glDrawable;
- fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable();
- } else {
- GLWindow glWindow = (GLWindow)glDrawable;
- fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable();
- }
-
- if (fboDrawable != null) {
- backFBO = fboDrawable.getFBObject(GL.GL_BACK);
- if (1 < numSamples) {
- if (needSepFrontTex) {
- // When using multisampled FBO, the back buffer is the MSAA
- // surface so it cannot be read from. The sink buffer contains
- // the readable 2D texture.
- // In this case, we create an auxiliary "front" buffer that it is
- // swapped with the sink buffer at the beginning of each frame.
- // In this way, we always have a readable copy of the previous
- // frame in the front texture, while the back is synchronized
- // with the contents of the MSAA back buffer when requested.
- if (frontFBO == null) {
- // init
- frontFBO = new FBObject();
- frontFBO.reset(gl, pg.width, pg.height);
- frontFBO.attachTexture2D(gl, 0, true);
- sinkFBO = backFBO.getSamplingSinkFBO();
- changedFrontTex = changedBackTex = true;
- } else {
- // swap
- FBObject temp = sinkFBO;
- sinkFBO = frontFBO;
- frontFBO = temp;
- backFBO.setSamplingSink(sinkFBO);
- changedFrontTex = changedBackTex = false;
- }
- backTexAttach = (FBObject.TextureAttachment) sinkFBO.
- getColorbuffer(0);
- frontTexAttach = (FBObject.TextureAttachment)frontFBO.
- getColorbuffer(0);
- } else {
- // Default setting (to save resources): the front and back
- // textures are the same.
- sinkFBO = backFBO.getSamplingSinkFBO();
- backTexAttach = (FBObject.TextureAttachment) sinkFBO.
- getColorbuffer(0);
- frontTexAttach = backTexAttach;
- }
-
- } else {
- // w/out multisampling, rendering is done on the back buffer.
- frontFBO = fboDrawable.getFBObject(GL.GL_FRONT);
-
- backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK);
- frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT);
- }
- }
- }
-
- pg.parent.handleDraw();
- drawLatch.countDown();
- }
-
- @Override
- public void dispose(GLAutoDrawable adrawable) {
- }
-
- @Override
- public void init(GLAutoDrawable adrawable) {
- drawable = adrawable;
- context = adrawable.getContext();
- capabilities = adrawable.getChosenGLCapabilities();
- gl = context.getGL();
-
- if (!hasFBOs()) {
- throw new RuntimeException(MISSING_FBO_ERROR);
- }
- if (!hasShaders()) {
- throw new RuntimeException(MISSING_GLSL_ERROR);
- }
- if (USE_JOGL_FBOLAYER && capabilities.isFBO()) {
- int maxs = maxSamples();
- numSamples = PApplet.min(capabilities.getNumSamples(), maxs);
- }
- }
-
- @Override
- public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) {
- drawable = adrawable;
- context = adrawable.getContext();
- }
+ protected interface Tessellator {
+ public void beginPolygon();
+ public void endPolygon();
+ public void setWindingRule(int rule);
+ public void beginContour();
+ public void endContour();
+ public void addVertex(double[] v);
}
- protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent,
- int peAction) {
- int modifiers = nativeEvent.getModifiers();
- int peModifiers = modifiers &
- (InputEvent.SHIFT_MASK |
- InputEvent.CTRL_MASK |
- InputEvent.META_MASK |
- InputEvent.ALT_MASK);
- int peButton = 0;
- if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
- peButton = PConstants.LEFT;
- } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- peButton = PConstants.CENTER;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- peButton = PConstants.RIGHT;
- }
-
- if (PApplet.platform == PConstants.MACOSX) {
- //if (nativeEvent.isPopupTrigger()) {
- if ((modifiers & InputEvent.CTRL_MASK) != 0) {
- peButton = PConstants.RIGHT;
- }
- }
-
- @SuppressWarnings("deprecation")
- int peCount = peAction == MouseEvent.WHEEL ?
- (int) nativeEvent.getWheelRotation() :
- nativeEvent.getClickCount();
-
- MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(),
- peAction, peModifiers,
- nativeEvent.getX(), nativeEvent.getY(),
- peButton,
- peCount);
-
- pg.parent.postEvent(me);
+ protected interface TessellatorCallback {
+ public void begin(int type);
+ public void end();
+ public void vertex(Object data);
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData);
+ public void error(int errnum);
}
- protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent,
- int peAction) {
- int peModifiers = nativeEvent.getModifiers() &
- (InputEvent.SHIFT_MASK |
- InputEvent.CTRL_MASK |
- InputEvent.META_MASK |
- InputEvent.ALT_MASK);
- char keyChar;
- if ((int)nativeEvent.getKeyChar() == 0) {
- keyChar = PConstants.CODED;
- } else {
- keyChar = nativeEvent.getKeyChar();
- }
-
- KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
- peAction, peModifiers,
- keyChar,
- nativeEvent.getKeyCode());
-
- pg.parent.postEvent(ke);
+ protected String tessError(int err) {
+ return "";
}
- class NEWTWindowListener implements com.jogamp.newt.event.WindowListener {
- @Override
- public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) {
- pg.parent.focusGained(null);
- }
- @Override
- public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) {
- pg.parent.focusLost(null);
- }
+ ///////////////////////////////////////////////////////////
- @Override
- public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) {
- }
+ // FontOutline interface
- @Override
- public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) {
- }
- @Override
- public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) {
- }
+ protected static boolean SHAPE_TEXT_SUPPORTED;
+ protected static int SEG_MOVETO;
+ protected static int SEG_LINETO;
+ protected static int SEG_QUADTO;
+ protected static int SEG_CUBICTO;
+ protected static int SEG_CLOSE;
- @Override
- public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) {
- }
- @Override
- public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { }
- }
+ protected abstract FontOutline createFontOutline(char ch, Object font);
- // NEWT mouse listener
- class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter {
- @Override
- public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.PRESS);
- }
- @Override
- public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.RELEASE);
- }
- @Override
- public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.CLICK);
- }
- @Override
- public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.DRAG);
- }
- @Override
- public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.MOVE);
- }
- @Override
- public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.WHEEL);
- }
- @Override
- public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.ENTER);
- }
- @Override
- public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
- nativeMouseEvent(e, MouseEvent.EXIT);
- }
- }
- // NEWT key listener
- class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter {
- @Override
- public void keyPressed(com.jogamp.newt.event.KeyEvent e) {
- nativeKeyEvent(e, KeyEvent.PRESS);
- }
- @Override
- public void keyReleased(com.jogamp.newt.event.KeyEvent e) {
- nativeKeyEvent(e, KeyEvent.RELEASE);
- }
- @Override
- public void keyTyped(com.jogamp.newt.event.KeyEvent e) {
- nativeKeyEvent(e, KeyEvent.TYPE);
- }
+ protected interface FontOutline {
+ public boolean isDone();
+ public int currentSegment(float coords[]);
+ public void next();
}
@@ -2832,595 +2133,449 @@ public class PGL {
// The entire GLES 2.0 specification is available below:
// http://www.khronos.org/opengles/2_X/
//
+ // Implementations of the PGL functions for specific OpenGL bindings (JOGL,
+ // LWJGL) should simply call the corresponding GL function in the bindings.
+ // readPixels(), activeTexture() and bindTexture() are special cases, please
+ // read their comments.
+ // Also, keep in mind the note about the PGL constants below.
+ //
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Constants
+ // Very important note: set the GL constants in your PGL subclass by using an
+ // static initialization block as follows:
+ // static {
+ // FALSE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_FALSE;
+ // TRUE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_TRUE;
+ // ...
+ // }
+ // and not by re-declaring the constants, because doing so will lead to
+ // errors when the constants are accessed through PGL because they are not
+ // overridden but hidden by the new declarations, and hence they keep their
+ // initial values (all zeroes) when accessed through the superclass.
- public static final int FALSE = GL.GL_FALSE;
- public static final int TRUE = GL.GL_TRUE;
+ public static int FALSE;
+ public static int TRUE;
- public static final int INT = GL2.GL_INT;
- public static final int BYTE = GL.GL_BYTE;
- public static final int SHORT = GL.GL_SHORT;
- public static final int FLOAT = GL.GL_FLOAT;
- public static final int BOOL = GL2.GL_BOOL;
- public static final int UNSIGNED_INT = GL.GL_UNSIGNED_INT;
- public static final int UNSIGNED_BYTE = GL.GL_UNSIGNED_BYTE;
- public static final int UNSIGNED_SHORT = GL.GL_UNSIGNED_SHORT;
+ public static int INT;
+ public static int BYTE;
+ public static int SHORT;
+ public static int FLOAT;
+ public static int BOOL;
+ public static int UNSIGNED_INT;
+ public static int UNSIGNED_BYTE;
+ public static int UNSIGNED_SHORT;
- public static final int RGB = GL.GL_RGB;
- public static final int RGBA = GL.GL_RGBA;
- public static final int ALPHA = GL.GL_ALPHA;
- public static final int LUMINANCE = GL.GL_LUMINANCE;
- public static final int LUMINANCE_ALPHA = GL.GL_LUMINANCE_ALPHA;
+ public static int RGB;
+ public static int RGBA;
+ public static int ALPHA;
+ public static int LUMINANCE;
+ public static int LUMINANCE_ALPHA;
- public static final int UNSIGNED_SHORT_5_6_5 = GL.GL_UNSIGNED_SHORT_5_6_5;
- public static final int UNSIGNED_SHORT_4_4_4_4 = GL.GL_UNSIGNED_SHORT_4_4_4_4;
- public static final int UNSIGNED_SHORT_5_5_5_1 = GL.GL_UNSIGNED_SHORT_5_5_5_1;
+ public static int UNSIGNED_SHORT_5_6_5;
+ public static int UNSIGNED_SHORT_4_4_4_4;
+ public static int UNSIGNED_SHORT_5_5_5_1;
- public static final int RGBA4 = GL2.GL_RGBA4;
- public static final int RGB5_A1 = GL2.GL_RGB5_A1;
- public static final int RGB565 = GL2.GL_RGB565;
+ public static int RGBA4;
+ public static int RGB5_A1;
+ public static int RGB565;
+ public static int RGB8;
+ public static int RGBA8;
+ public static int ALPHA8;
- public static final int READ_ONLY = GL2.GL_READ_ONLY;
- public static final int WRITE_ONLY = GL2.GL_WRITE_ONLY;
- public static final int READ_WRITE = GL2.GL_READ_WRITE;
+ public static int READ_ONLY;
+ public static int WRITE_ONLY;
+ public static int READ_WRITE;
- public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO;
- public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD;
+ public static int TESS_WINDING_NONZERO;
+ public static int TESS_WINDING_ODD;
- public static final int GENERATE_MIPMAP_HINT = GL.GL_GENERATE_MIPMAP_HINT;
- public static final int FASTEST = GL.GL_FASTEST;
- public static final int NICEST = GL.GL_NICEST;
- public static final int DONT_CARE = GL.GL_DONT_CARE;
+ public static int GENERATE_MIPMAP_HINT;
+ public static int FASTEST;
+ public static int NICEST;
+ public static int DONT_CARE;
- public static final int VENDOR = GL.GL_VENDOR;
- public static final int RENDERER = GL.GL_RENDERER;
- public static final int VERSION = GL.GL_VERSION;
- public static final int EXTENSIONS = GL.GL_EXTENSIONS;
- public static final int SHADING_LANGUAGE_VERSION = GL2ES2.GL_SHADING_LANGUAGE_VERSION;
+ public static int VENDOR;
+ public static int RENDERER;
+ public static int VERSION;
+ public static int EXTENSIONS;
+ public static int SHADING_LANGUAGE_VERSION;
- public static final int MAX_SAMPLES = GL2.GL_MAX_SAMPLES;
- public static final int SAMPLES = GL.GL_SAMPLES;
+ public static int MAX_SAMPLES;
+ public static int SAMPLES;
- public static final int ALIASED_LINE_WIDTH_RANGE = GL.GL_ALIASED_LINE_WIDTH_RANGE;
- public static final int ALIASED_POINT_SIZE_RANGE = GL.GL_ALIASED_POINT_SIZE_RANGE;
+ public static int ALIASED_LINE_WIDTH_RANGE;
+ public static int ALIASED_POINT_SIZE_RANGE;
- public static final int DEPTH_BITS = GL.GL_DEPTH_BITS;
- public static final int STENCIL_BITS = GL.GL_STENCIL_BITS;
+ public static int DEPTH_BITS;
+ public static int STENCIL_BITS;
- public static final int CCW = GL.GL_CCW;
- public static final int CW = GL.GL_CW;
+ public static int CCW;
+ public static int CW;
- public static final int VIEWPORT = GL.GL_VIEWPORT;
+ public static int VIEWPORT;
- public static final int ARRAY_BUFFER = GL.GL_ARRAY_BUFFER;
- public static final int ELEMENT_ARRAY_BUFFER = GL.GL_ELEMENT_ARRAY_BUFFER;
+ public static int ARRAY_BUFFER;
+ public static int ELEMENT_ARRAY_BUFFER;
- public static final int MAX_VERTEX_ATTRIBS = GL2.GL_MAX_VERTEX_ATTRIBS;
+ public static int MAX_VERTEX_ATTRIBS;
- public static final int STATIC_DRAW = GL.GL_STATIC_DRAW;
- public static final int DYNAMIC_DRAW = GL.GL_DYNAMIC_DRAW;
- public static final int STREAM_DRAW = GL2.GL_STREAM_DRAW;
+ public static int STATIC_DRAW;
+ public static int DYNAMIC_DRAW;
+ public static int STREAM_DRAW;
- public static final int BUFFER_SIZE = GL.GL_BUFFER_SIZE;
- public static final int BUFFER_USAGE = GL.GL_BUFFER_USAGE;
+ public static int BUFFER_SIZE;
+ public static int BUFFER_USAGE;
- public static final int POINTS = GL.GL_POINTS;
- public static final int LINE_STRIP = GL.GL_LINE_STRIP;
- public static final int LINE_LOOP = GL.GL_LINE_LOOP;
- public static final int LINES = GL.GL_LINES;
- public static final int TRIANGLE_FAN = GL.GL_TRIANGLE_FAN;
- public static final int TRIANGLE_STRIP = GL.GL_TRIANGLE_STRIP;
- public static final int TRIANGLES = GL.GL_TRIANGLES;
+ public static int POINTS;
+ public static int LINE_STRIP;
+ public static int LINE_LOOP;
+ public static int LINES;
+ public static int TRIANGLE_FAN;
+ public static int TRIANGLE_STRIP;
+ public static int TRIANGLES;
- public static final int CULL_FACE = GL.GL_CULL_FACE;
- public static final int FRONT = GL.GL_FRONT;
- public static final int BACK = GL.GL_BACK;
- public static final int FRONT_AND_BACK = GL.GL_FRONT_AND_BACK;
+ public static int CULL_FACE;
+ public static int FRONT;
+ public static int BACK;
+ public static int FRONT_AND_BACK;
- public static final int POLYGON_OFFSET_FILL = GL.GL_POLYGON_OFFSET_FILL;
+ public static int POLYGON_OFFSET_FILL;
- public static final int UNPACK_ALIGNMENT = GL.GL_UNPACK_ALIGNMENT;
- public static final int PACK_ALIGNMENT = GL.GL_PACK_ALIGNMENT;
+ public static int UNPACK_ALIGNMENT;
+ public static int PACK_ALIGNMENT;
- public static final int TEXTURE_2D = GL.GL_TEXTURE_2D;
- public static final int TEXTURE_RECTANGLE = GL2.GL_TEXTURE_RECTANGLE;
+ public static int TEXTURE_2D;
+ public static int TEXTURE_RECTANGLE;
- public static final int TEXTURE_BINDING_2D = GL.GL_TEXTURE_BINDING_2D;
- public static final int TEXTURE_BINDING_RECTANGLE = GL2.GL_TEXTURE_BINDING_RECTANGLE;
+ public static int TEXTURE_BINDING_2D;
+ public static int TEXTURE_BINDING_RECTANGLE;
- public static final int MAX_TEXTURE_SIZE = GL.GL_MAX_TEXTURE_SIZE;
- public static final int TEXTURE_MAX_ANISOTROPY = GL.GL_TEXTURE_MAX_ANISOTROPY_EXT;
- public static final int MAX_TEXTURE_MAX_ANISOTROPY = GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
+ public static int MAX_TEXTURE_SIZE;
+ public static int TEXTURE_MAX_ANISOTROPY;
+ public static int MAX_TEXTURE_MAX_ANISOTROPY;
- public static final int MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
- public static final int MAX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_TEXTURE_IMAGE_UNITS;
- public static final int MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+ public static int MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+ public static int MAX_TEXTURE_IMAGE_UNITS;
+ public static int MAX_COMBINED_TEXTURE_IMAGE_UNITS;
- public static final int NUM_COMPRESSED_TEXTURE_FORMATS = GL2ES2.GL_NUM_COMPRESSED_TEXTURE_FORMATS;
- public static final int COMPRESSED_TEXTURE_FORMATS = GL2ES2.GL_COMPRESSED_TEXTURE_FORMATS;
+ public static int NUM_COMPRESSED_TEXTURE_FORMATS;
+ public static int COMPRESSED_TEXTURE_FORMATS;
- public static final int NEAREST = GL.GL_NEAREST;
- public static final int LINEAR = GL.GL_LINEAR;
- public static final int LINEAR_MIPMAP_NEAREST = GL.GL_LINEAR_MIPMAP_NEAREST;
- public static final int LINEAR_MIPMAP_LINEAR = GL.GL_LINEAR_MIPMAP_LINEAR;
+ public static int NEAREST;
+ public static int LINEAR;
+ public static int LINEAR_MIPMAP_NEAREST;
+ public static int LINEAR_MIPMAP_LINEAR;
- public static final int CLAMP_TO_EDGE = GL.GL_CLAMP_TO_EDGE;
- public static final int REPEAT = GL.GL_REPEAT;
+ public static int CLAMP_TO_EDGE;
+ public static int REPEAT;
- public static final int TEXTURE0 = GL.GL_TEXTURE0;
- public static final int TEXTURE1 = GL.GL_TEXTURE1;
- public static final int TEXTURE2 = GL.GL_TEXTURE2;
- public static final int TEXTURE3 = GL.GL_TEXTURE3;
- public static final int TEXTURE_MIN_FILTER = GL.GL_TEXTURE_MIN_FILTER;
- public static final int TEXTURE_MAG_FILTER = GL.GL_TEXTURE_MAG_FILTER;
- public static final int TEXTURE_WRAP_S = GL.GL_TEXTURE_WRAP_S;
- public static final int TEXTURE_WRAP_T = GL.GL_TEXTURE_WRAP_T;
+ public static int TEXTURE0;
+ public static int TEXTURE1;
+ public static int TEXTURE2;
+ public static int TEXTURE3;
+ public static int TEXTURE_MIN_FILTER;
+ public static int TEXTURE_MAG_FILTER;
+ public static int TEXTURE_WRAP_S;
+ public static int TEXTURE_WRAP_T;
+ public static int TEXTURE_WRAP_R;
- public static final int TEXTURE_CUBE_MAP = GL.GL_TEXTURE_CUBE_MAP;
- public static final int TEXTURE_CUBE_MAP_POSITIVE_X = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- public static final int TEXTURE_CUBE_MAP_POSITIVE_Y = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
- public static final int TEXTURE_CUBE_MAP_POSITIVE_Z = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
- public static final int TEXTURE_CUBE_MAP_NEGATIVE_X = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
- public static final int TEXTURE_CUBE_MAP_NEGATIVE_Y = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
- public static final int TEXTURE_CUBE_MAP_NEGATIVE_Z = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ public static int TEXTURE_CUBE_MAP;
+ public static int TEXTURE_CUBE_MAP_POSITIVE_X;
+ public static int TEXTURE_CUBE_MAP_POSITIVE_Y;
+ public static int TEXTURE_CUBE_MAP_POSITIVE_Z;
+ public static int TEXTURE_CUBE_MAP_NEGATIVE_X;
+ public static int TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ public static int TEXTURE_CUBE_MAP_NEGATIVE_Z;
- public static final int VERTEX_SHADER = GL2.GL_VERTEX_SHADER;
- public static final int FRAGMENT_SHADER = GL2.GL_FRAGMENT_SHADER;
- public static final int INFO_LOG_LENGTH = GL2.GL_INFO_LOG_LENGTH;
- public static final int SHADER_SOURCE_LENGTH = GL2.GL_SHADER_SOURCE_LENGTH;
- public static final int COMPILE_STATUS = GL2.GL_COMPILE_STATUS;
- public static final int LINK_STATUS = GL2.GL_LINK_STATUS;
- public static final int VALIDATE_STATUS = GL2.GL_VALIDATE_STATUS;
- public static final int SHADER_TYPE = GL2.GL_SHADER_TYPE;
- public static final int DELETE_STATUS = GL2.GL_DELETE_STATUS;
+ public static int VERTEX_SHADER;
+ public static int FRAGMENT_SHADER;
+ public static int INFO_LOG_LENGTH;
+ public static int SHADER_SOURCE_LENGTH;
+ public static int COMPILE_STATUS;
+ public static int LINK_STATUS;
+ public static int VALIDATE_STATUS;
+ public static int SHADER_TYPE;
+ public static int DELETE_STATUS;
- public static final int FLOAT_VEC2 = GL2.GL_FLOAT_VEC2;
- public static final int FLOAT_VEC3 = GL2.GL_FLOAT_VEC3;
- public static final int FLOAT_VEC4 = GL2.GL_FLOAT_VEC4;
- public static final int FLOAT_MAT2 = GL2.GL_FLOAT_MAT2;
- public static final int FLOAT_MAT3 = GL2.GL_FLOAT_MAT3;
- public static final int FLOAT_MAT4 = GL2.GL_FLOAT_MAT4;
- public static final int INT_VEC2 = GL2.GL_INT_VEC2;
- public static final int INT_VEC3 = GL2.GL_INT_VEC3;
- public static final int INT_VEC4 = GL2.GL_INT_VEC4;
- public static final int BOOL_VEC2 = GL2.GL_BOOL_VEC2;
- public static final int BOOL_VEC3 = GL2.GL_BOOL_VEC3;
- public static final int BOOL_VEC4 = GL2.GL_BOOL_VEC4;
- public static final int SAMPLER_2D = GL2.GL_SAMPLER_2D;
- public static final int SAMPLER_CUBE = GL2.GL_SAMPLER_CUBE;
+ public static int FLOAT_VEC2;
+ public static int FLOAT_VEC3;
+ public static int FLOAT_VEC4;
+ public static int FLOAT_MAT2;
+ public static int FLOAT_MAT3;
+ public static int FLOAT_MAT4;
+ public static int INT_VEC2;
+ public static int INT_VEC3;
+ public static int INT_VEC4;
+ public static int BOOL_VEC2;
+ public static int BOOL_VEC3;
+ public static int BOOL_VEC4;
+ public static int SAMPLER_2D;
+ public static int SAMPLER_CUBE;
- public static final int LOW_FLOAT = GL2.GL_LOW_FLOAT;
- public static final int MEDIUM_FLOAT = GL2.GL_MEDIUM_FLOAT;
- public static final int HIGH_FLOAT = GL2.GL_HIGH_FLOAT;
- public static final int LOW_INT = GL2.GL_LOW_INT;
- public static final int MEDIUM_INT = GL2.GL_MEDIUM_INT;
- public static final int HIGH_INT = GL2.GL_HIGH_INT;
+ public static int LOW_FLOAT;
+ public static int MEDIUM_FLOAT;
+ public static int HIGH_FLOAT;
+ public static int LOW_INT;
+ public static int MEDIUM_INT;
+ public static int HIGH_INT;
- public static final int CURRENT_VERTEX_ATTRIB = GL2.GL_CURRENT_VERTEX_ATTRIB;
+ public static int CURRENT_VERTEX_ATTRIB;
- public static final int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING;
- public static final int VERTEX_ATTRIB_ARRAY_ENABLED = GL2.GL_VERTEX_ATTRIB_ARRAY_ENABLED;
- public static final int VERTEX_ATTRIB_ARRAY_SIZE = GL2.GL_VERTEX_ATTRIB_ARRAY_SIZE;
- public static final int VERTEX_ATTRIB_ARRAY_STRIDE = GL2.GL_VERTEX_ATTRIB_ARRAY_STRIDE;
- public static final int VERTEX_ATTRIB_ARRAY_TYPE = GL2.GL_VERTEX_ATTRIB_ARRAY_TYPE;
- public static final int VERTEX_ATTRIB_ARRAY_NORMALIZED = GL2.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED;
+ public static int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING;
+ public static int VERTEX_ATTRIB_ARRAY_ENABLED;
+ public static int VERTEX_ATTRIB_ARRAY_SIZE;
+ public static int VERTEX_ATTRIB_ARRAY_STRIDE;
+ public static int VERTEX_ATTRIB_ARRAY_TYPE;
+ public static int VERTEX_ATTRIB_ARRAY_NORMALIZED;
+ public static int VERTEX_ATTRIB_ARRAY_POINTER;
- public static final int BLEND = GL.GL_BLEND;
- public static final int ONE = GL.GL_ONE;
- public static final int ZERO = GL.GL_ZERO;
- public static final int SRC_ALPHA = GL.GL_SRC_ALPHA;
- public static final int DST_ALPHA = GL.GL_DST_ALPHA;
- public static final int ONE_MINUS_SRC_ALPHA = GL.GL_ONE_MINUS_SRC_ALPHA;
- public static final int ONE_MINUS_DST_COLOR = GL.GL_ONE_MINUS_DST_COLOR;
- public static final int ONE_MINUS_SRC_COLOR = GL.GL_ONE_MINUS_SRC_COLOR;
- public static final int DST_COLOR = GL.GL_DST_COLOR;
- public static final int SRC_COLOR = GL.GL_SRC_COLOR;
+ public static int BLEND;
+ public static int ONE;
+ public static int ZERO;
+ public static int SRC_ALPHA;
+ public static int DST_ALPHA;
+ public static int ONE_MINUS_SRC_ALPHA;
+ public static int ONE_MINUS_DST_COLOR;
+ public static int ONE_MINUS_SRC_COLOR;
+ public static int DST_COLOR;
+ public static int SRC_COLOR;
- public static final int SAMPLE_ALPHA_TO_COVERAGE = GL.GL_SAMPLE_ALPHA_TO_COVERAGE;
- public static final int SAMPLE_COVERAGE = GL.GL_SAMPLE_COVERAGE;
+ public static int SAMPLE_ALPHA_TO_COVERAGE;
+ public static int SAMPLE_COVERAGE;
- public static final int KEEP = GL.GL_KEEP;
- public static final int REPLACE = GL.GL_REPLACE;
- public static final int INCR = GL.GL_INCR;
- public static final int DECR = GL.GL_DECR;
- public static final int INVERT = GL.GL_INVERT;
- public static final int INCR_WRAP = GL.GL_INCR_WRAP;
- public static final int DECR_WRAP = GL.GL_DECR_WRAP;
- public static final int NEVER = GL.GL_NEVER;
- public static final int ALWAYS = GL.GL_ALWAYS;
+ public static int KEEP;
+ public static int REPLACE;
+ public static int INCR;
+ public static int DECR;
+ public static int INVERT;
+ public static int INCR_WRAP;
+ public static int DECR_WRAP;
+ public static int NEVER;
+ public static int ALWAYS;
- public static final int EQUAL = GL.GL_EQUAL;
- public static final int LESS = GL.GL_LESS;
- public static final int LEQUAL = GL.GL_LEQUAL;
- public static final int GREATER = GL.GL_GREATER;
- public static final int GEQUAL = GL.GL_GEQUAL;
- public static final int NOTEQUAL = GL.GL_NOTEQUAL;
+ public static int EQUAL;
+ public static int LESS;
+ public static int LEQUAL;
+ public static int GREATER;
+ public static int GEQUAL;
+ public static int NOTEQUAL;
- public static final int FUNC_ADD = GL.GL_FUNC_ADD;
- public static final int FUNC_MIN = GL2.GL_MIN;
- public static final int FUNC_MAX = GL2.GL_MAX;
- public static final int FUNC_REVERSE_SUBTRACT = GL.GL_FUNC_REVERSE_SUBTRACT;
- public static final int FUNC_SUBTRACT = GL.GL_FUNC_SUBTRACT;
+ public static int FUNC_ADD;
+ public static int FUNC_MIN;
+ public static int FUNC_MAX;
+ public static int FUNC_REVERSE_SUBTRACT;
+ public static int FUNC_SUBTRACT;
- public static final int DITHER = GL.GL_DITHER;
+ public static int DITHER;
- public static final int CONSTANT_COLOR = GL2.GL_CONSTANT_COLOR;
- public static final int CONSTANT_ALPHA = GL2.GL_CONSTANT_ALPHA;
- public static final int ONE_MINUS_CONSTANT_COLOR = GL2.GL_ONE_MINUS_CONSTANT_COLOR;
- public static final int ONE_MINUS_CONSTANT_ALPHA = GL2.GL_ONE_MINUS_CONSTANT_ALPHA;
- public static final int SRC_ALPHA_SATURATE = GL.GL_SRC_ALPHA_SATURATE;
+ public static int CONSTANT_COLOR;
+ public static int CONSTANT_ALPHA;
+ public static int ONE_MINUS_CONSTANT_COLOR;
+ public static int ONE_MINUS_CONSTANT_ALPHA;
+ public static int SRC_ALPHA_SATURATE;
- public static final int SCISSOR_TEST = GL.GL_SCISSOR_TEST;
- public static final int DEPTH_TEST = GL.GL_DEPTH_TEST;
- public static final int DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK;
- public static final int ALPHA_TEST = GL2.GL_ALPHA_TEST;
+ public static int SCISSOR_TEST;
+ public static int STENCIL_TEST;
+ public static int DEPTH_TEST;
+ public static int DEPTH_WRITEMASK;
+ public static int ALPHA_TEST;
- public static final int COLOR_BUFFER_BIT = GL.GL_COLOR_BUFFER_BIT;
- public static final int DEPTH_BUFFER_BIT = GL.GL_DEPTH_BUFFER_BIT;
- public static final int STENCIL_BUFFER_BIT = GL.GL_STENCIL_BUFFER_BIT;
+ public static int COLOR_BUFFER_BIT;
+ public static int DEPTH_BUFFER_BIT;
+ public static int STENCIL_BUFFER_BIT;
- public static final int FRAMEBUFFER = GL.GL_FRAMEBUFFER;
- public static final int COLOR_ATTACHMENT0 = GL.GL_COLOR_ATTACHMENT0;
- public static final int COLOR_ATTACHMENT1 = GL2.GL_COLOR_ATTACHMENT1;
- public static final int COLOR_ATTACHMENT2 = GL2.GL_COLOR_ATTACHMENT2;
- public static final int COLOR_ATTACHMENT3 = GL2.GL_COLOR_ATTACHMENT3;
- public static final int RENDERBUFFER = GL.GL_RENDERBUFFER;
- public static final int DEPTH_ATTACHMENT = GL.GL_DEPTH_ATTACHMENT;
- public static final int STENCIL_ATTACHMENT = GL.GL_STENCIL_ATTACHMENT;
- public static final int READ_FRAMEBUFFER = GL2.GL_READ_FRAMEBUFFER;
- public static final int DRAW_FRAMEBUFFER = GL2.GL_DRAW_FRAMEBUFFER;
+ public static int FRAMEBUFFER;
+ public static int COLOR_ATTACHMENT0;
+ public static int COLOR_ATTACHMENT1;
+ public static int COLOR_ATTACHMENT2;
+ public static int COLOR_ATTACHMENT3;
+ public static int RENDERBUFFER;
+ public static int DEPTH_ATTACHMENT;
+ public static int STENCIL_ATTACHMENT;
+ public static int READ_FRAMEBUFFER;
+ public static int DRAW_FRAMEBUFFER;
- public static final int RGBA8 = GL.GL_RGBA8;
- public static final int DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8;
+ public static int DEPTH24_STENCIL8;
- public static final int DEPTH_COMPONENT = GL2.GL_DEPTH_COMPONENT;
- public static final int DEPTH_COMPONENT16 = GL.GL_DEPTH_COMPONENT16;
- public static final int DEPTH_COMPONENT24 = GL.GL_DEPTH_COMPONENT24;
- public static final int DEPTH_COMPONENT32 = GL.GL_DEPTH_COMPONENT32;
+ public static int DEPTH_COMPONENT;
+ public static int DEPTH_COMPONENT16;
+ public static int DEPTH_COMPONENT24;
+ public static int DEPTH_COMPONENT32;
- public static final int STENCIL_INDEX = GL2.GL_STENCIL_INDEX;
- public static final int STENCIL_INDEX1 = GL.GL_STENCIL_INDEX1;
- public static final int STENCIL_INDEX4 = GL.GL_STENCIL_INDEX4;
- public static final int STENCIL_INDEX8 = GL.GL_STENCIL_INDEX8;
+ public static int STENCIL_INDEX;
+ public static int STENCIL_INDEX1;
+ public static int STENCIL_INDEX4;
+ public static int STENCIL_INDEX8;
- public static final int FRAMEBUFFER_COMPLETE = GL.GL_FRAMEBUFFER_COMPLETE;
- public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
- public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- public static final int FRAMEBUFFER_INCOMPLETE_FORMATS = GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS;
- public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
- public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
- public static final int FRAMEBUFFER_UNSUPPORTED = GL.GL_FRAMEBUFFER_UNSUPPORTED;
+ public static int DEPTH_STENCIL;
- public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL2.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE;
- public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL2.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
- public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL2.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL;
- public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL2.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE;
+ public static int FRAMEBUFFER_COMPLETE;
+ public static int FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ public static int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ public static int FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ public static int FRAMEBUFFER_INCOMPLETE_FORMATS;
+ public static int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
+ public static int FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
+ public static int FRAMEBUFFER_UNSUPPORTED;
- public static final int RENDERBUFFER_WIDTH = GL2.GL_RENDERBUFFER_WIDTH;
- public static final int RENDERBUFFER_HEIGHT = GL2.GL_RENDERBUFFER_HEIGHT;
- public static final int RENDERBUFFER_RED_SIZE = GL2.GL_RENDERBUFFER_RED_SIZE;
- public static final int RENDERBUFFER_GREEN_SIZE = GL2.GL_RENDERBUFFER_GREEN_SIZE;
- public static final int RENDERBUFFER_BLUE_SIZE = GL2.GL_RENDERBUFFER_BLUE_SIZE;
- public static final int RENDERBUFFER_ALPHA_SIZE = GL2.GL_RENDERBUFFER_ALPHA_SIZE;
- public static final int RENDERBUFFER_DEPTH_SIZE = GL2.GL_RENDERBUFFER_DEPTH_SIZE;
- public static final int RENDERBUFFER_STENCIL_SIZE = GL2.GL_RENDERBUFFER_STENCIL_SIZE;
- public static final int RENDERBUFFER_INTERNAL_FORMAT = GL2.GL_RENDERBUFFER_INTERNAL_FORMAT;
+ public static int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE;
+ public static int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
+ public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL;
+ public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE;
- public static final int MULTISAMPLE = GL.GL_MULTISAMPLE;
- public static final int POINT_SMOOTH = GL2.GL_POINT_SMOOTH;
- public static final int LINE_SMOOTH = GL.GL_LINE_SMOOTH;
- public static final int POLYGON_SMOOTH = GL2.GL_POLYGON_SMOOTH;
+ public static int RENDERBUFFER_WIDTH;
+ public static int RENDERBUFFER_HEIGHT;
+ public static int RENDERBUFFER_RED_SIZE;
+ public static int RENDERBUFFER_GREEN_SIZE;
+ public static int RENDERBUFFER_BLUE_SIZE;
+ public static int RENDERBUFFER_ALPHA_SIZE;
+ public static int RENDERBUFFER_DEPTH_SIZE;
+ public static int RENDERBUFFER_STENCIL_SIZE;
+ public static int RENDERBUFFER_INTERNAL_FORMAT;
+
+ public static int MULTISAMPLE;
+ public static int POINT_SMOOTH;
+ public static int LINE_SMOOTH;
+ public static int POLYGON_SMOOTH;
///////////////////////////////////////////////////////////
// Special Functions
- public void flush() {
- gl.glFlush();
- }
-
- public void finish() {
- gl.glFinish();
- }
-
- public void hint(int target, int hint) {
- gl.glHint(target, hint);
- }
+ public abstract void flush();
+ public abstract void finish();
+ public abstract void hint(int target, int hint);
///////////////////////////////////////////////////////////
// State and State Requests
- public void enable(int value) {
- if (-1 < value) {
- gl.glEnable(value);
- }
- }
-
- public void disable(int value) {
- if (-1 < value) {
- gl.glDisable(value);
- }
- }
-
- public void getBooleanv(int value, IntBuffer data) {
- if (-1 < value) {
- if (byteBuffer.capacity() < data.capacity()) {
- byteBuffer = allocateDirectByteBuffer(data.capacity());
- }
- gl.glGetBooleanv(value, byteBuffer);
- for (int i = 0; i < data.capacity(); i++) {
- data.put(i, byteBuffer.get(i));
- }
- } else {
- fillIntBuffer(data, 0, data.capacity() - 1, 0);
- }
- }
-
- public void getIntegerv(int value, IntBuffer data) {
- if (-1 < value) {
- gl.glGetIntegerv(value, data);
- } else {
- fillIntBuffer(data, 0, data.capacity() - 1, 0);
- }
- }
-
- public void getFloatv(int value, FloatBuffer data) {
- if (-1 < value) {
- gl.glGetFloatv(value, data);
- } else {
- fillFloatBuffer(data, 0, data.capacity() - 1, 0);
- }
- }
-
- public boolean isEnabled(int value) {
- return gl.glIsEnabled(value);
- }
-
- public String getString(int name) {
- return gl.glGetString(name);
- }
+ public abstract void enable(int value);
+ public abstract void disable(int value);
+ public abstract void getBooleanv(int value, IntBuffer data);
+ public abstract void getIntegerv(int value, IntBuffer data);
+ public abstract void getFloatv(int value, FloatBuffer data);
+ public abstract boolean isEnabled(int value);
+ public abstract String getString(int name);
///////////////////////////////////////////////////////////
// Error Handling
- public int getError() {
- return gl.glGetError();
- }
-
- public String errorString(int err) {
- return glu.gluErrorString(err);
- }
+ public abstract int getError();
+ public abstract String errorString(int err);
//////////////////////////////////////////////////////////////////////////////
// Buffer Objects
- public void genBuffers(int n, IntBuffer buffers) {
- gl.glGenBuffers(n, buffers);
- }
-
- public void deleteBuffers(int n, IntBuffer buffers) {
- gl.glDeleteBuffers(n, buffers);
- }
-
- public void bindBuffer(int target, int buffer) {
- gl.glBindBuffer(target, buffer);
- }
-
- public void bufferData(int target, int size, Buffer data, int usage) {
- gl.glBufferData(target, size, data, usage);
- }
-
- public void bufferSubData(int target, int offset, int size, Buffer data) {
- gl.glBufferSubData(target, offset, size, data);
- }
-
- public void isBuffer(int buffer) {
- gl.glIsBuffer(buffer);
- }
-
- public void getBufferParameteriv(int target, int value, IntBuffer data) {
- gl.glGetBufferParameteriv(target, value, data);
- }
-
- public ByteBuffer mapBuffer(int target, int access) {
- return gl2.glMapBuffer(target, access);
- }
-
- public ByteBuffer mapBufferRange(int target, int offset, int length, int access) {
- if (gl2x != null) {
- return gl2x.glMapBufferRange(target, offset, length, access);
- } else {
- return null;
- }
- }
-
- public void unmapBuffer(int target) {
- gl2.glUnmapBuffer(target);
- }
+ public abstract void genBuffers(int n, IntBuffer buffers);
+ public abstract void deleteBuffers(int n, IntBuffer buffers);
+ public abstract void bindBuffer(int target, int buffer);
+ public abstract void bufferData(int target, int size, Buffer data, int usage);
+ public abstract void bufferSubData(int target, int offset, int size, Buffer data);
+ public abstract void isBuffer(int buffer);
+ public abstract void getBufferParameteriv(int target, int value, IntBuffer data);
+ public abstract ByteBuffer mapBuffer(int target, int access);
+ public abstract ByteBuffer mapBufferRange(int target, int offset, int length, int access);
+ public abstract void unmapBuffer(int target);
//////////////////////////////////////////////////////////////////////////////
// Viewport and Clipping
- public void depthRangef(float n, float f) {
- gl.glDepthRangef(n, f);
- }
-
- public void viewport(int x, int y, int w, int h) {
- gl.glViewport(x, y, w, h);
- }
+ public abstract void depthRangef(float n, float f);
+ public abstract void viewport(int x, int y, int w, int h);
//////////////////////////////////////////////////////////////////////////////
// Reading Pixels
+ // This is a special case: because the renderer might be using an FBO even on
+ // the main surface, some extra handling might be needed before and after
+ // reading the pixels. To make this transparent to the user, the actual call
+ // to glReadPixels() should be done in readPixelsImpl().
- public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) {
- // The beginPixelsOp/endPixelsOp calls are needed to properly setup the
- // framebuffers to read from.
- PGraphicsOpenGL.pgCurrent.beginPixelsOp(PGraphicsOpenGL.OP_READ);
+ public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer){
+ boolean needEndBegin = format != STENCIL_INDEX &&
+ format != DEPTH_COMPONENT && format != DEPTH_STENCIL;
+ if (needEndBegin) pg.beginReadPixels();
readPixelsImpl(x, y, width, height, format, type, buffer);
- PGraphicsOpenGL.pgCurrent.endPixelsOp();
+ if (needEndBegin) pg.endReadPixels();
}
- protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) {
- gl.glReadPixels(x, y, width, height, format, type, buffer);
- }
+ protected abstract void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer);
//////////////////////////////////////////////////////////////////////////////
// Vertices
- public void vertexAttrib1f(int index, float value) {
- gl2.glVertexAttrib1f(index, value);
- }
-
- public void vertexAttrib2f(int index, float value0, float value1) {
- gl2.glVertexAttrib2f(index, value0, value1);
- }
-
- public void vertexAttrib3f(int index, float value0, float value1, float value2) {
- gl2.glVertexAttrib3f(index, value0, value1, value2);
- }
-
- public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) {
- gl2.glVertexAttrib4f(index, value0, value1, value2, value3);
- }
-
- public void vertexAttrib1fv(int index, FloatBuffer values) {
- gl2.glVertexAttrib1fv(index, values);
- }
-
- public void vertexAttrib2fv(int index, FloatBuffer values) {
- gl2.glVertexAttrib2fv(index, values);
- }
-
- public void vertexAttrib3fv(int index, FloatBuffer values) {
- gl2.glVertexAttrib3fv(index, values);
- }
-
- public void vertexAttri4fv(int index, FloatBuffer values) {
- gl2.glVertexAttrib4fv(index, values);
- }
-
- public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) {
- gl2.glVertexAttribPointer(index, size, type, normalized, stride, offset);
- }
-
- public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) {
- gl2.glVertexAttribPointer(index, size, type, normalized, stride, data);
- }
-
- public void enableVertexAttribArray(int index) {
- gl2.glEnableVertexAttribArray(index);
- }
-
- public void disableVertexAttribArray(int index) {
- gl2.glDisableVertexAttribArray(index);
- }
-
- public void drawArrays(int mode, int first, int count) {
- gl.glDrawArrays(mode, first, count);
- }
-
- public void drawElements(int mode, int count, int type, int offset) {
- gl.glDrawElements(mode, count, type, offset);
- }
-
- public void drawElements(int mode, int count, int type, Buffer indices) {
- gl.glDrawElements(mode, count, type, indices);
- }
+ public abstract void vertexAttrib1f(int index, float value);
+ public abstract void vertexAttrib2f(int index, float value0, float value1);
+ public abstract void vertexAttrib3f(int index, float value0, float value1, float value2);
+ public abstract void vertexAttrib4f(int index, float value0, float value1, float value2, float value3);
+ public abstract void vertexAttrib1fv(int index, FloatBuffer values);
+ public abstract void vertexAttrib2fv(int index, FloatBuffer values);
+ public abstract void vertexAttrib3fv(int index, FloatBuffer values);
+ public abstract void vertexAttri4fv(int index, FloatBuffer values);
+ public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset);
+ public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data);
+ public abstract void enableVertexAttribArray(int index);
+ public abstract void disableVertexAttribArray(int index);
+ public abstract void drawArrays(int mode, int first, int count);
+ public abstract void drawElements(int mode, int count, int type, int offset);
+ public abstract void drawElements(int mode, int count, int type, Buffer indices);
//////////////////////////////////////////////////////////////////////////////
// Rasterization
- public void lineWidth(float width) {
- gl.glLineWidth(width);
- }
-
- public void frontFace(int dir) {
- gl.glFrontFace(dir);
- }
-
- public void cullFace(int mode) {
- gl.glCullFace(mode);
- }
-
- public void polygonOffset(float factor, float units) {
- gl.glPolygonOffset(factor, units);
- }
+ public abstract void lineWidth(float width);
+ public abstract void frontFace(int dir);
+ public abstract void cullFace(int mode);
+ public abstract void polygonOffset(float factor, float units);
//////////////////////////////////////////////////////////////////////////////
// Pixel Rectangles
- public void pixelStorei(int pname, int param) {
- gl.glPixelStorei(pname, param);
- }
+ public abstract void pixelStorei(int pname, int param);
///////////////////////////////////////////////////////////
// Texturing
+ public abstract void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data);
+ public abstract void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border);
+ public abstract void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data);
+ public abstract void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height);
+ public abstract void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data);
+ public abstract void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data);
+ public abstract void texParameteri(int target, int pname, int param);
+ public abstract void texParameterf(int target, int pname, float param);
+ public abstract void texParameteriv(int target, int pname, IntBuffer params);
+ public abstract void texParameterfv(int target, int pname, FloatBuffer params);
+ public abstract void generateMipmap(int target);
+ public abstract void genTextures(int n, IntBuffer textures);
+ public abstract void deleteTextures(int n, IntBuffer textures);
+ public abstract void getTexParameteriv(int target, int pname, IntBuffer params);
+ public abstract void getTexParameterfv(int target, int pname, FloatBuffer params);
+ public abstract boolean isTexture(int texture);
+
+ // activeTexture() and bindTexture() have some extra logic to keep track of
+ // the bound textures, so the actual GL call should go in activeTextureImpl()
+ // and bindTextureImpl().
public void activeTexture(int texture) {
- gl.glActiveTexture(texture);
activeTexUnit = texture - TEXTURE0;
+ activeTextureImpl(texture);
}
- public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) {
- gl.glTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
- }
-
- public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) {
- gl.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
- }
-
- public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data) {
- gl.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, data);
- }
-
- public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height) {
- gl.glCopyTexSubImage2D(target, level, x, y, xOffset, xOffset, width, height);
- }
-
- public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data) {
- gl.glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data);
- }
-
- public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data) {
- gl.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, imageSize, data);
- }
-
- public void texParameteri(int target, int pname, int param) {
- gl.glTexParameteri(target, pname, param);
- }
-
- public void texParameterf(int target, int pname, float param) {
- gl.glTexParameterf(target, pname, param);
- }
-
- public void texParameteriv(int target, int pname, IntBuffer params) {
- gl.glTexParameteriv(target, pname, params);
- }
-
- public void texParameterfv(int target, int pname, FloatBuffer params) {
- gl.glTexParameterfv(target, pname, params);
- }
-
- public void generateMipmap(int target) {
- gl.glGenerateMipmap(target);
- }
+ protected abstract void activeTextureImpl(int texture);
public void bindTexture(int target, int texture) {
- gl.glBindTexture(target, texture);
+ bindTextureImpl(target, texture);
if (boundTextures == null) {
maxTexUnits = getMaxTexUnits();
@@ -3437,439 +2592,115 @@ public class PGL {
boundTextures[activeTexUnit][1] = texture;
}
}
-
- public void genTextures(int n, IntBuffer textures) {
- gl.glGenTextures(n, textures);
- }
-
- public void deleteTextures(int n, IntBuffer textures) {
- gl.glDeleteTextures(n, textures);
- }
-
- public void getTexParameteriv(int target, int pname, IntBuffer params) {
- gl.glGetTexParameteriv(target, pname, params);
- }
-
- public void getTexParameterfv(int target, int pname, FloatBuffer params) {
- gl.glGetTexParameterfv(target, pname, params);
- }
-
- public boolean isTexture(int texture) {
- return gl.glIsTexture(texture);
- }
+ protected abstract void bindTextureImpl(int target, int texture);
///////////////////////////////////////////////////////////
// Shaders and Programs
- public int createShader(int type) {
- return gl2.glCreateShader(type);
- }
-
- public void shaderSource(int shader, String source) {
- gl2.glShaderSource(shader, 1, new String[] { source }, (int[]) null, 0);
- }
-
- public void compileShader(int shader) {
- gl2.glCompileShader(shader);
- }
-
- public void releaseShaderCompiler() {
- gl2.glReleaseShaderCompiler();
- }
-
- public void deleteShader(int shader) {
- gl2.glDeleteShader(shader);
- }
-
- public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) {
- gl2.glShaderBinary(count, shaders, binaryFormat, binary, length);
- }
-
- public int createProgram() {
- return gl2.glCreateProgram();
- }
-
- public void attachShader(int program, int shader) {
- gl2.glAttachShader(program, shader);
- }
-
- public void detachShader(int program, int shader) {
- gl2.glDetachShader(program, shader);
- }
-
- public void linkProgram(int program) {
- gl2.glLinkProgram(program);
- }
-
- public void useProgram(int program) {
- gl2.glUseProgram(program);
- }
-
- public void deleteProgram(int program) {
- gl2.glDeleteProgram(program);
- }
-
- public void getActiveAttrib(int program, int index, int[] size, int[] type, String[] name) {
- int[] tmp = {0, 0, 0};
- byte[] namebuf = new byte[1024];
- gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0);
- if (size != null && size.length != 0) size[0] = tmp[1];
- if (type != null && type.length != 0) type[0] = tmp[2];
- if (name != null && name.length != 0) name[0] = new String(namebuf, 0, tmp[0]);
- }
-
- public int getAttribLocation(int program, String name) {
- return gl2.glGetAttribLocation(program, name);
- }
-
- public void bindAttribLocation(int program, int index, String name) {
- gl2.glBindAttribLocation(program, index, name);
- }
-
- public int getUniformLocation(int program, String name) {
- return gl2.glGetUniformLocation(program, name);
- }
-
- public void getActiveUniform(int program, int index, int[] size,int[] type, String[] name) {
- int[] tmp= {0, 0, 0};
- byte[] namebuf = new byte[1024];
- gl2.glGetActiveUniform(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0);
- if (size != null && size.length != 0) size[0] = tmp[1];
- if (type != null && type.length != 0) type[0] = tmp[2];
- if (name != null && name.length != 0) name[0] = new String(namebuf, 0, tmp[0]);
- }
-
- public void uniform1i(int location, int value) {
- gl2.glUniform1i(location, value);
- }
-
- public void uniform2i(int location, int value0, int value1) {
- gl2.glUniform2i(location, value0, value1);
- }
-
- public void uniform3i(int location, int value0, int value1, int value2) {
- gl2.glUniform3i(location, value0, value1, value2);
- }
-
- public void uniform4i(int location, int value0, int value1, int value2, int value3) {
- gl2.glUniform4i(location, value0, value1, value2, value3);
- }
-
- public void uniform1f(int location, float value) {
- gl2.glUniform1f(location, value);
- }
-
- public void uniform2f(int location, float value0, float value1) {
- gl2.glUniform2f(location, value0, value1);
- }
-
- public void uniform3f(int location, float value0, float value1, float value2) {
- gl2.glUniform3f(location, value0, value1, value2);
- }
-
- public void uniform4f(int location, float value0, float value1, float value2, float value3) {
- gl2.glUniform4f(location, value0, value1, value2, value3);
- }
-
- public void uniform1iv(int location, int count, IntBuffer v) {
- gl2.glUniform1iv(location, count, v);
- }
-
- public void uniform2iv(int location, int count, IntBuffer v) {
- gl2.glUniform2iv(location, count, v);
- }
-
- public void uniform3iv(int location, int count, IntBuffer v) {
- gl2.glUniform3iv(location, count, v);
- }
-
- public void uniform4iv(int location, int count, IntBuffer v) {
- gl2.glUniform4iv(location, count, v);
- }
-
- public void uniform1fv(int location, int count, FloatBuffer v) {
- gl2.glUniform1fv(location, count, v);
- }
-
- public void uniform2fv(int location, int count, FloatBuffer v) {
- gl2.glUniform2fv(location, count, v);
- }
-
- public void uniform3fv(int location, int count, FloatBuffer v) {
- gl2.glUniform3fv(location, count, v);
- }
-
- public void uniform4fv(int location, int count, FloatBuffer v) {
- gl2.glUniform4fv(location, count, v);
- }
-
- public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) {
- gl2.glUniformMatrix2fv(location, count, transpose, mat);
- }
-
- public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) {
- gl2.glUniformMatrix3fv(location, count, transpose, mat);
- }
-
- public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) {
- gl2.glUniformMatrix4fv(location, count, transpose, mat);
- }
-
- public void validateProgram(int program) {
- gl2.glValidateProgram(program);
- }
-
- public boolean isShader(int shader) {
- return gl2.glIsShader(shader);
- }
-
- public void getShaderiv(int shader, int pname, IntBuffer params) {
- gl2.glGetShaderiv(shader, pname, params);
- }
-
- public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) {
- gl2.glGetAttachedShaders(program, maxCount, count, shaders);
- }
-
- public String getShaderInfoLog(int shader) {
- int[] val = { 0 };
- gl2.glGetShaderiv(shader, GL2.GL_INFO_LOG_LENGTH, val, 0);
- int length = val[0];
-
- byte[] log = new byte[length];
- gl2.glGetShaderInfoLog(shader, length, val, 0, log, 0);
- return new String(log);
- }
-
- public String getShaderSource(int shader) {
- int[] len = {0};
- byte[] buf = new byte[1024];
- gl2.glGetShaderSource(shader, 1024, len, 0, buf, 0);
- return new String(buf, 0, len[0]);
- }
-
- public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) {
- gl2.glGetShaderPrecisionFormat(shaderType, precisionType, range, precision);
- }
-
- public void getVertexAttribfv(int index, int pname, FloatBuffer params) {
- gl2.glGetVertexAttribfv(index, pname, params);
- }
-
- public void getVertexAttribiv(int index, int pname, IntBuffer params) {
- gl2.glGetVertexAttribiv(index, pname, params);
- }
-
- public void getVertexAttribPointerv() {
- throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetVertexAttribPointerv()"));
- }
-
- public void getUniformfv(int program, int location, FloatBuffer params) {
- gl2.glGetUniformfv(program, location, params);
- }
-
- public void getUniformiv(int program, int location, IntBuffer params) {
- gl2.glGetUniformiv(program, location, params);
- }
-
- public boolean isProgram(int program) {
- return gl2.glIsProgram(program);
- }
-
- public void getProgramiv(int program, int pname, IntBuffer params) {
- gl2.glGetProgramiv(program, pname, params);
- }
-
- public String getProgramInfoLog(int program) {
- int[] val = { 0 };
- gl2.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH, val, 0);
- int length = val[0];
-
- if (0 < length) {
- byte[] log = new byte[length];
- gl2.glGetProgramInfoLog(program, length, val, 0, log, 0);
- return new String(log);
- } else {
- return "Unknow error";
- }
- }
+ public abstract int createShader(int type);
+ public abstract void shaderSource(int shader, String source);
+ public abstract void compileShader(int shader);
+ public abstract void releaseShaderCompiler();
+ public abstract void deleteShader(int shader);
+ public abstract void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length);
+ public abstract int createProgram();
+ public abstract void attachShader(int program, int shader);
+ public abstract void detachShader(int program, int shader);
+ public abstract void linkProgram(int program);
+ public abstract void useProgram(int program);
+ public abstract void deleteProgram(int program);
+ public abstract String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type);
+ public abstract int getAttribLocation(int program, String name);
+ public abstract void bindAttribLocation(int program, int index, String name);
+ public abstract int getUniformLocation(int program, String name);
+ public abstract String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type);
+ public abstract void uniform1i(int location, int value);
+ public abstract void uniform2i(int location, int value0, int value1);
+ public abstract void uniform3i(int location, int value0, int value1, int value2);
+ public abstract void uniform4i(int location, int value0, int value1, int value2, int value3);
+ public abstract void uniform1f(int location, float value);
+ public abstract void uniform2f(int location, float value0, float value1);
+ public abstract void uniform3f(int location, float value0, float value1, float value2);
+ public abstract void uniform4f(int location, float value0, float value1, float value2, float value3);
+ public abstract void uniform1iv(int location, int count, IntBuffer v);
+ public abstract void uniform2iv(int location, int count, IntBuffer v);
+ public abstract void uniform3iv(int location, int count, IntBuffer v);
+ public abstract void uniform4iv(int location, int count, IntBuffer v);
+ public abstract void uniform1fv(int location, int count, FloatBuffer v);
+ public abstract void uniform2fv(int location, int count, FloatBuffer v);
+ public abstract void uniform3fv(int location, int count, FloatBuffer v);
+ public abstract void uniform4fv(int location, int count, FloatBuffer v);
+ public abstract void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat);
+ public abstract void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat);
+ public abstract void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat);
+ public abstract void validateProgram(int program);
+ public abstract boolean isShader(int shader);
+ public abstract void getShaderiv(int shader, int pname, IntBuffer params);
+ public abstract void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders);
+ public abstract String getShaderInfoLog(int shader);
+ public abstract String getShaderSource(int shader);
+ public abstract void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision);
+ public abstract void getVertexAttribfv(int index, int pname, FloatBuffer params);
+ public abstract void getVertexAttribiv(int index, int pname, IntBuffer params);
+ public abstract void getVertexAttribPointerv(int index, int pname, ByteBuffer data);
+ public abstract void getUniformfv(int program, int location, FloatBuffer params);
+ public abstract void getUniformiv(int program, int location, IntBuffer params);
+ public abstract boolean isProgram(int program);
+ public abstract void getProgramiv(int program, int pname, IntBuffer params);
+ public abstract String getProgramInfoLog(int program);
///////////////////////////////////////////////////////////
// Per-Fragment Operations
- public void scissor(int x, int y, int w, int h) {
- gl.glScissor(x, y, w, h);
- }
-
- public void sampleCoverage(float value, boolean invert) {
- gl2.glSampleCoverage(value, invert);
- }
-
- public void stencilFunc(int func, int ref, int mask) {
- gl2.glStencilFunc(func, ref, mask);
- }
-
- public void stencilFuncSeparate(int face, int func, int ref, int mask) {
- gl2.glStencilFuncSeparate(face, func, ref, mask);
- }
-
- public void stencilOp(int sfail, int dpfail, int dppass) {
- gl2.glStencilOp(sfail, dpfail, dppass);
- }
-
- public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) {
- gl2.glStencilOpSeparate(face, sfail, dpfail, dppass);
- }
-
- public void depthFunc(int func) {
- gl.glDepthFunc(func);
- }
-
- public void blendEquation(int mode) {
- gl.glBlendEquation(mode);
- }
-
- public void blendEquationSeparate(int modeRGB, int modeAlpha) {
- gl.glBlendEquationSeparate(modeRGB, modeAlpha);
- }
-
- public void blendFunc(int src, int dst) {
- gl.glBlendFunc(src, dst);
- }
-
- public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
- gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
- }
-
- public void blendColor(float red, float green, float blue, float alpha) {
- gl2.glBlendColor(red, green, blue, alpha);
- }
-
- public void alphaFunc(int func, float ref) {
- if (gl2x != null) {
- gl2x.glAlphaFunc(func, ref);
- }
- }
+ public abstract void scissor(int x, int y, int w, int h);
+ public abstract void sampleCoverage(float value, boolean invert);
+ public abstract void stencilFunc(int func, int ref, int mask);
+ public abstract void stencilFuncSeparate(int face, int func, int ref, int mask);
+ public abstract void stencilOp(int sfail, int dpfail, int dppass);
+ public abstract void stencilOpSeparate(int face, int sfail, int dpfail, int dppass);
+ public abstract void depthFunc(int func);
+ public abstract void blendEquation(int mode);
+ public abstract void blendEquationSeparate(int modeRGB, int modeAlpha);
+ public abstract void blendFunc(int src, int dst);
+ public abstract void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
+ public abstract void blendColor(float red, float green, float blue, float alpha);
+ public abstract void alphaFunc(int func, float ref);
///////////////////////////////////////////////////////////
// Whole Framebuffer Operations
- public void colorMask(boolean r, boolean g, boolean b, boolean a) {
- gl.glColorMask(r, g, b, a);
- }
-
- public void depthMask(boolean mask) {
- gl.glDepthMask(mask);
- }
-
- public void stencilMask(int mask) {
- gl.glStencilMask(mask);
- }
-
- public void stencilMaskSeparate(int face, int mask) {
- gl2.glStencilMaskSeparate(face, mask);
- }
-
- public void clear(int buf) {
- gl.glClear(buf);
- }
-
- public void clearColor(float r, float g, float b, float a) {
- gl.glClearColor(r, g, b, a);
- }
-
- public void clearDepth(float d) {
- gl.glClearDepthf(d);
- }
-
- public void clearStencil(int s) {
- gl.glClearStencil(s);
- }
+ public abstract void colorMask(boolean r, boolean g, boolean b, boolean a);
+ public abstract void depthMask(boolean mask);
+ public abstract void stencilMask(int mask);
+ public abstract void stencilMaskSeparate(int face, int mask);
+ public abstract void clear(int buf);
+ public abstract void clearColor(float r, float g, float b, float a);
+ public abstract void clearDepth(float d);
+ public abstract void clearStencil(int s);
///////////////////////////////////////////////////////////
// Framebuffers Objects
- public void bindFramebuffer(int target, int framebuffer) {
- gl.glBindFramebuffer(target, framebuffer);
- }
-
- public void deleteFramebuffers(int n, IntBuffer framebuffers) {
- gl.glDeleteFramebuffers(n, framebuffers);
- }
-
- public void genFramebuffers(int n, IntBuffer framebuffers) {
- gl.glGenFramebuffers(n, framebuffers);
- }
-
- public void bindRenderbuffer(int target, int renderbuffer) {
- gl.glBindRenderbuffer(target, renderbuffer);
- }
-
- public void deleteRenderbuffers(int n, IntBuffer renderbuffers) {
- gl.glDeleteRenderbuffers(n, renderbuffers);
- }
-
- public void genRenderbuffers(int n, IntBuffer renderbuffers) {
- gl.glGenRenderbuffers(n, renderbuffers);
- }
-
- public void renderbufferStorage(int target, int internalFormat, int width, int height) {
- gl.glRenderbufferStorage(target, internalFormat, width, height);
- }
-
- public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) {
- gl.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer);
- }
-
- public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) {
- gl.glFramebufferTexture2D(target, attachment, texTarget, texture, level);
- }
-
- public int checkFramebufferStatus(int target) {
- return gl.glCheckFramebufferStatus(target);
- }
-
- public boolean isFramebuffer(int framebuffer) {
- return gl2.glIsFramebuffer(framebuffer);
- }
-
- public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) {
- gl2.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
- }
-
- public boolean isRenderbuffer(int renderbuffer) {
- return gl2.glIsRenderbuffer(renderbuffer);
- }
-
- public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) {
- gl2.glGetRenderbufferParameteriv(target, pname, params);
- }
-
- public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
- if (gl2x != null) {
- gl2x.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
- }
- }
-
- public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) {
- if (gl2x != null) {
- gl2x.glRenderbufferStorageMultisample(target, samples, format, width, height);
- }
- }
-
- public void readBuffer(int buf) {
- if (gl2x != null) {
- gl2x.glReadBuffer(buf);
- }
- }
-
- public void drawBuffer(int buf) {
- if (gl2x != null) {
- gl2x.glDrawBuffer(buf);
- }
- }
+ public abstract void bindFramebuffer(int target, int framebuffer);
+ public abstract void deleteFramebuffers(int n, IntBuffer framebuffers);
+ public abstract void genFramebuffers(int n, IntBuffer framebuffers);
+ public abstract void bindRenderbuffer(int target, int renderbuffer);
+ public abstract void deleteRenderbuffers(int n, IntBuffer renderbuffers);
+ public abstract void genRenderbuffers(int n, IntBuffer renderbuffers);
+ public abstract void renderbufferStorage(int target, int internalFormat, int width, int height);
+ public abstract void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer);
+ public abstract void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level);
+ public abstract int checkFramebufferStatus(int target);
+ public abstract boolean isFramebuffer(int framebuffer);
+ public abstract void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params);
+ public abstract boolean isRenderbuffer(int renderbuffer);
+ public abstract void getRenderbufferParameteriv(int target, int pname, IntBuffer params);
+ public abstract void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter);
+ public abstract void renderbufferStorageMultisample(int target, int samples, int format, int width, int height);
+ public abstract void readBuffer(int buf);
+ public abstract void drawBuffer(int buf);
}
diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java
index a1ad432d8..9c1761cba 100644
--- a/core/src/processing/opengl/PGraphics2D.java
+++ b/core/src/processing/opengl/PGraphics2D.java
@@ -119,7 +119,7 @@ public class PGraphics2D extends PGraphicsOpenGL {
@Override
protected void defaultPerspective() {
- super.ortho(0, width, 0, height, -1, +1);
+ super.ortho(width/2f, (3f/2f) * width, -height/2f, height/2f, -1, +1);
}
@@ -156,7 +156,7 @@ public class PGraphics2D extends PGraphicsOpenGL {
@Override
protected void defaultCamera() {
- super.camera(width/2, height/2);
+ resetMatrix();
}
@@ -180,6 +180,12 @@ public class PGraphics2D extends PGraphicsOpenGL {
popProjection();
}
+// @Override
+// public void resetMatrix() {
+// super.resetMatrix();
+// defaultCamera();
+// }
+
//////////////////////////////////////////////////////////////
@@ -307,35 +313,6 @@ public class PGraphics2D extends PGraphicsOpenGL {
} else if (type == PShape.GEOMETRY) {
shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
}
-
- /*
- if (type == POINTS) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(POINTS);
- } else if (type == LINES) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(LINES);
- } else if (type == TRIANGLE || type == TRIANGLES) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(TRIANGLES);
- } else if (type == TRIANGLE_FAN) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(TRIANGLE_FAN);
- } else if (type == TRIANGLE_STRIP) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(TRIANGLE_STRIP);
- } else if (type == QUAD || type == QUADS) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(QUADS);
- } else if (type == QUAD_STRIP) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(QUAD_STRIP);
- } else if (type == POLYGON) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(POLYGON);
- }
- */
-
shape.is3D(false);
return shape;
}
@@ -375,14 +352,14 @@ public class PGraphics2D extends PGraphicsOpenGL {
shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
shape.setKind(QUAD);
} else if (kind == RECT) {
- if (len != 4 && len != 5 && len != 8) {
+ if (len != 4 && len != 5 && len != 8 && len != 9) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
- if (len != 4) {
+ if (len != 4 && len != 5) {
showWarning("Wrong number of parameters");
return null;
}
diff --git a/core/src/processing/opengl/PGraphics3D.java b/core/src/processing/opengl/PGraphics3D.java
index 0880651cc..43aa52251 100644
--- a/core/src/processing/opengl/PGraphics3D.java
+++ b/core/src/processing/opengl/PGraphics3D.java
@@ -117,6 +117,9 @@ public class PGraphics3D extends PGraphicsOpenGL {
} else if (extension.equals("objz")) {
try {
+ // TODO: The obj file can be read from the gzip, but if it refers to
+ // a materials file and texture images, those must be contained in the
+ // data folder, cannot be inside the gzip.
InputStream input =
new GZIPInputStream(pg.parent.createInput(filename));
obj = new PShapeOBJ(pg.parent, PApplet.createReader(input));
@@ -175,38 +178,6 @@ public class PGraphics3D extends PGraphicsOpenGL {
} else if (type == PShape.GEOMETRY) {
shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
}
-
- /*
- (type == POINTS) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
-
- shape.setKind(POINTS);
- } else if (type == LINES) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
-
- shape.setKind(LINES);
- } else if (type == TRIANGLE || type == TRIANGLES) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
-
- shape.setKind(TRIANGLES);
- } else if (type == TRIANGLE_FAN) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(TRIANGLE_FAN);
- } else if (type == TRIANGLE_STRIP) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(TRIANGLE_STRIP);
- } else if (type == QUAD || type == QUADS) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(QUADS);
- } else if (type == QUAD_STRIP) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(QUAD_STRIP);
- } else if (type == POLYGON) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
- shape.setKind(POLYGON);
- }
- */
-
shape.is3D(true);
return shape;
}
@@ -246,14 +217,14 @@ public class PGraphics3D extends PGraphicsOpenGL {
shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
shape.setKind(QUAD);
} else if (kind == RECT) {
- if (len != 4 && len != 5 && len != 8) {
+ if (len != 4 && len != 5 && len != 8 && len != 9) {
showWarning("Wrong number of parameters");
return null;
}
shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
- if (len != 4) {
+ if (len != 4 && len != 5) {
showWarning("Wrong number of parameters");
return null;
}
@@ -274,7 +245,7 @@ public class PGraphics3D extends PGraphicsOpenGL {
shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
shape.setKind(BOX);
} else if (kind == SPHERE) {
- if (len != 1) {
+ if (len < 1 || 3 < len) {
showWarning("Wrong number of parameters");
return null;
}
diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java
index 8242d2b80..f613fc583 100644
--- a/core/src/processing/opengl/PGraphicsOpenGL.java
+++ b/core/src/processing/opengl/PGraphicsOpenGL.java
@@ -76,12 +76,21 @@ public class PGraphicsOpenGL extends PGraphics {
"for the rest of the sketch's execution";
static final String UNSUPPORTED_SHAPE_FORMAT_ERROR =
"Unsupported shape format";
+ static final String MISSING_UV_TEXCOORDS_ERROR =
+ "No uv texture coordinates supplied with vertex() call";
static final String INVALID_FILTER_SHADER_ERROR =
"Your shader needs to be of TEXTURE type to be used as a filter";
- static final String INVALID_PROCESSING_SHADER_ERROR =
- "The GLSL code doesn't seem to contain a valid shader to use in Processing";
+ static final String INCONSISTENT_SHADER_TYPES =
+ "The vertex and fragment shaders have different types";
static final String WRONG_SHADER_TYPE_ERROR =
"shader() called with a wrong shader";
+ static final String SHADER_NEED_LIGHT_ATTRIBS =
+ "The provided shader needs light attributes (ambient, diffuse, etc.), but " +
+ "the current scene is unlit, so the default shader will be used instead";
+ static final String MISSING_FRAGMENT_SHADER =
+ "The fragment shader is missing, cannot create shader object";
+ static final String MISSING_VERTEX_SHADER =
+ "The vertex shader is missing, cannot create shader object";
static final String UNKNOWN_SHADER_KIND_ERROR =
"Unknown shader kind";
static final String NO_TEXLIGHT_SHADER_ERROR =
@@ -173,8 +182,6 @@ public class PGraphicsOpenGL extends PGraphics {
/** Some hardware limits */
static public int maxTextureSize;
static public int maxSamples;
- static public float maxPointSize;
- static public float maxLineWidth;
static public float maxAnisoAmount;
static public int depthBits;
static public int stencilBits;
@@ -230,31 +237,20 @@ public class PGraphicsOpenGL extends PGraphics {
static protected URL defPointShaderFragURL =
PGraphicsOpenGL.class.getResource("PointFrag.glsl");
- static protected ColorShader defColorShader;
- static protected TextureShader defTextureShader;
- static protected LightShader defLightShader;
- static protected TexlightShader defTexlightShader;
- static protected LineShader defLineShader;
- static protected PointShader defPointShader;
+ static protected PShader defColorShader;
+ static protected PShader defTextureShader;
+ static protected PShader defLightShader;
+ static protected PShader defTexlightShader;
+ static protected PShader defLineShader;
+ static protected PShader defPointShader;
static protected URL maskShaderFragURL =
PGraphicsOpenGL.class.getResource("MaskFrag.glsl");
- static protected TextureShader maskShader;
+ static protected PShader maskShader;
- protected ColorShader colorShader;
- protected TextureShader textureShader;
- protected LightShader lightShader;
- protected TexlightShader texlightShader;
- protected LineShader lineShader;
- protected PointShader pointShader;
-
- // When shader warnings are enabled, the renderer is strict in regards to the
- // use of the polygon shaders. For instance, if a light shader is set to
- // render lit geometry, but the geometry is mixed with some pieces of unlit or
- // textured geometry, then it will warn that the set shader cannot be used for
- // that other type of geometry, even though Processing will use the correct,
- // built-in shaders to handle it.
- protected boolean shaderWarningsEnabled = true;
+ protected PShader polyShader;
+ protected PShader lineShader;
+ protected PShader pointShader;
// ........................................................
@@ -390,12 +386,6 @@ public class PGraphicsOpenGL extends PGraphics {
// ........................................................
- // Blending:
-
- protected int blendMode;
-
- // ........................................................
-
// Clipping
protected boolean clip = false;
@@ -477,6 +467,10 @@ public class PGraphicsOpenGL extends PGraphics {
protected int smoothCallCount = 0;
protected int lastSmoothCall = -10;
+ /** Used to avoid flushing the geometry when blendMode() is called with the
+ * same blend mode as the last */
+ protected int lastBlendMode = -1;
+
/** Type of pixels operation. */
static protected final int OP_NONE = 0;
static protected final int OP_READ = 1;
@@ -504,19 +498,21 @@ public class PGraphicsOpenGL extends PGraphics {
/** Used in round point and ellipse tessellation. The
* number of subdivisions per round point or ellipse is
* calculated with the following formula:
- * n = max(N, (TWO_PI * size / F))
+ * n = min(M, max(N, (TWO_PI * size / F)))
* where size is a measure of the dimensions of the circle
* when projected on screen coordinates. F just sets the
* minimum number of subdivisions, while a smaller F
* would allow to have more detailed circles.
* N = MIN_POINT_ACCURACY
+ * M = MAX_POINT_ACCURACY
* F = POINT_ACCURACY_FACTOR
*/
final static protected int MIN_POINT_ACCURACY = 20;
+ final static protected int MAX_POINT_ACCURACY = 200;
final static protected float POINT_ACCURACY_FACTOR = 10.0f;
/** Used in quad point tessellation. */
- final protected float[][] QUAD_POINT_SIGNS =
+ final static protected float[][] QUAD_POINT_SIGNS =
{ {-1, +1}, {-1, -1}, {+1, -1}, {+1, +1} };
/** To get data from OpenGL. */
@@ -530,7 +526,7 @@ public class PGraphicsOpenGL extends PGraphics {
public PGraphicsOpenGL() {
if (pgl == null) {
- pgl = new PGL(this);
+ pgl = createPGL(this);
}
if (tessellator == null) {
@@ -544,8 +540,8 @@ public class PGraphicsOpenGL extends PGraphics {
viewport = PGL.allocateIntBuffer(4);
- inGeo = newInGeometry(IMMEDIATE);
- tessGeo = newTessGeometry(IMMEDIATE);
+ inGeo = newInGeometry(this, IMMEDIATE);
+ tessGeo = newTessGeometry(this, IMMEDIATE);
texCache = newTexCache();
initialized = false;
@@ -577,7 +573,6 @@ public class PGraphicsOpenGL extends PGraphics {
height = iheight;
allocate();
- reapplySettings();
// init perspective projection based on new dimensions
cameraFOV = 60 * DEG_TO_RAD; // at least for now
@@ -588,10 +583,6 @@ public class PGraphicsOpenGL extends PGraphics {
cameraFar = cameraZ * 10.0f;
cameraAspect = (float) width / (float) height;
- // Forces a restart of OpenGL so the canvas has the right size.
- restartPGL();
-
- // set this flag so that beginDraw() will do an update to the camera.
sized = true;
}
@@ -635,13 +626,15 @@ public class PGraphicsOpenGL extends PGraphics {
public void dispose() { // PGraphics
super.dispose();
- // Swap buffers the end to make sure that no
- // garbage is shown on the screen, this particularly
- // affects non-interactive sketches on windows that
- // render only 1 frame, so no enough rendering
- // iterations have been conducted so far to properly
- // initialize all the buffers.
- pgl.swapBuffers();
+ if (primarySurface) {
+ // Swap buffers the end to make sure that no
+ // garbage is shown on the screen, this particularly
+ // affects non-interactive sketches on windows that
+ // render only 1 frame, so no enough rendering
+ // iterations have been conducted so far to properly
+ // initialize all the buffers.
+ pgl.swapBuffers();
+ }
deletePolyBuffers();
deleteLineBuffers();
@@ -1288,7 +1281,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected void updatePolyBuffers(boolean lit, boolean tex) {
+ protected void updatePolyBuffers(boolean lit, boolean tex,
+ boolean needNormals, boolean needTexCoords) {
createPolyBuffers();
int size = tessGeo.polyVertexCount;
@@ -1306,11 +1300,6 @@ public class PGraphicsOpenGL extends PGraphics {
tessGeo.polyColorsBuffer, PGL.STATIC_DRAW);
if (lit) {
- tessGeo.updatePolyNormalsBuffer();
- pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal);
- pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef,
- tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW);
-
tessGeo.updatePolyAmbientBuffer();
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyAmbient);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
@@ -1331,8 +1320,14 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.bufferData(PGL.ARRAY_BUFFER, sizef,
tessGeo.polyShininessBuffer, PGL.STATIC_DRAW);
}
+ if (lit || needNormals) {
+ tessGeo.updatePolyNormalsBuffer();
+ pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal);
+ pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef,
+ tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW);
+ }
- if (tex) {
+ if (tex || needTexCoords) {
tessGeo.updatePolyTexCoordsBuffer();
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyTexcoord);
pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef,
@@ -1581,7 +1576,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void requestFocus() { // ignore
- //pgl.requestFocus();
+ pgl.requestFocus();
}
@@ -1599,6 +1594,7 @@ public class PGraphicsOpenGL extends PGraphics {
public void requestDraw() {
if (primarySurface) {
if (initialized) {
+ if (sized) pgl.reinitSurface();
pgl.requestDraw();
} else {
initPrimary();
@@ -1645,7 +1641,7 @@ public class PGraphicsOpenGL extends PGraphics {
} else {
beginOffscreenDraw();
}
- setDrawDefaults();
+ setDrawDefaults(); // TODO: look at using checkSettings() instead...
pgCurrent = this;
drawing = true;
@@ -1696,6 +1692,12 @@ public class PGraphicsOpenGL extends PGraphics {
}
+ // Factory method
+ protected PGL createPGL(PGraphicsOpenGL pg) {
+ return new PJOGL(pg);
+ }
+
+
@Override
public PGL beginPGL() {
flush();
@@ -1723,7 +1725,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void restoreGL() {
- setBlendMode(blendMode);
+ blendMode(blendMode); // this should be set by reapplySettings...
if (hints[DISABLE_DEPTH_TEST]) {
pgl.disable(PGL.DEPTH_TEST);
@@ -1736,8 +1738,6 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.disable(PGL.MULTISAMPLE);
} else {
pgl.enable(PGL.MULTISAMPLE);
- pgl.disable(PGL.POINT_SMOOTH);
- pgl.disable(PGL.LINE_SMOOTH);
pgl.disable(PGL.POLYGON_SMOOTH);
}
@@ -1765,6 +1765,13 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer());
}
+ public void beginReadPixels() {
+ pgCurrent.beginPixelsOp(OP_READ);
+ }
+
+ public void endReadPixels() {
+ pgCurrent.endPixelsOp();
+ }
protected void beginPixelsOp(int op) {
FrameBuffer pixfb = null;
@@ -2036,10 +2043,10 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void beginShape(int kind) {
shape = kind;
- curveVertexCount = 0;
inGeo.clear();
- breakShape = true;
+ curveVertexCount = 0;
+ breakShape = false;
defaultEdges = true;
textureImage0 = textureImage;
@@ -2111,6 +2118,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void vertex(float x, float y) {
vertexImpl(x, y, 0, 0, 0);
+ if (textureImage != null) PGraphics.showWarning(MISSING_UV_TEXCOORDS_ERROR);
}
@@ -2123,6 +2131,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void vertex(float x, float y, float z) {
vertexImpl(x, y, z, 0, 0);
+ if (textureImage != null) PGraphics.showWarning(MISSING_UV_TEXCOORDS_ERROR);
}
@@ -2165,17 +2174,16 @@ public class PGraphicsOpenGL extends PGraphics {
u, v,
scolor, sweight,
ambientColor, specularColor, emissiveColor, shininess,
- vertexCode());
+ VERTEX, vertexBreak());
}
- protected int vertexCode() {
- int code = VERTEX;
+ protected boolean vertexBreak() {
if (breakShape) {
- code = BREAK;
breakShape = false;
+ return true;
}
- return code;
+ return false;
}
@@ -2218,12 +2226,13 @@ public class PGraphicsOpenGL extends PGraphics {
tessellator.setInGeometry(inGeo);
tessellator.setTessGeometry(tessGeo);
tessellator.setFill(fill || textureImage != null);
+ tessellator.setTexCache(texCache, textureImage0, textureImage);
tessellator.setStroke(stroke);
tessellator.setStrokeColor(strokeColor);
tessellator.setStrokeWeight(strokeWeight);
tessellator.setStrokeCap(strokeCap);
tessellator.setStrokeJoin(strokeJoin);
- tessellator.setTexCache(texCache, textureImage0, textureImage);
+ tessellator.setRenderer(pgCurrent);
tessellator.setTransform(modelview);
tessellator.set3D(is3D());
@@ -2248,8 +2257,6 @@ public class PGraphicsOpenGL extends PGraphics {
if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleStripNormals();
tessellator.tessellateTriangleStrip();
} else if (shape == QUAD || shape == QUADS) {
-
-
if (stroke && defaultEdges) inGeo.addQuadsEdges();
if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadsNormals();
tessellator.tessellateQuads();
@@ -2258,7 +2265,6 @@ public class PGraphicsOpenGL extends PGraphics {
if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals();
tessellator.tessellateQuadStrip();
} else if (shape == POLYGON) {
- if (stroke && defaultEdges) inGeo.addPolygonEdges(mode == CLOSE);
tessellator.tessellatePolygon(false, mode == CLOSE,
normalMode == NORMAL_MODE_AUTO);
}
@@ -2361,14 +2367,18 @@ public class PGraphicsOpenGL extends PGraphics {
protected void flushPolys() {
- updatePolyBuffers(lights, texCache.hasTextures);
+ boolean customShader = polyShader != null;
+ boolean needNormals = customShader ? polyShader.accessNormals() : false;
+ boolean needTexCoords = customShader ? polyShader.accessTexCoords() : false;
+
+ updatePolyBuffers(lights, texCache.hasTextures, needNormals, needTexCoords);
for (int i = 0; i < texCache.size; i++) {
Texture tex = texCache.getTexture(i);
// If the renderer is 2D, then lights should always be false,
// so no need to worry about that.
- BaseShader shader = getPolyShader(lights, tex != null);
+ PShader shader = getPolyShader(lights, tex != null);
shader.bind();
int first = texCache.firstCache[i];
@@ -2399,18 +2409,18 @@ public class PGraphicsOpenGL extends PGraphics {
voffset * PGL.SIZEOF_FLOAT);
}
- if (tex != null) {
+ if (lights || needNormals) {
shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0,
3 * voffset * PGL.SIZEOF_FLOAT);
+ }
+
+ if (tex != null || needTexCoords) {
shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0,
2 * voffset * PGL.SIZEOF_FLOAT);
shader.setTexture(tex);
}
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(glPolyIndex, icount, ioffset);
}
shader.unbind();
@@ -2528,7 +2538,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void flushLines() {
updateLineBuffers();
- LineShader shader = getLineShader();
+ PShader shader = getLineShader();
shader.bind();
IndexCache cache = tessGeo.lineIndexCache;
@@ -2544,10 +2554,7 @@ public class PGraphicsOpenGL extends PGraphics {
shader.setLineAttribute(glLineAttrib, 4, PGL.FLOAT, 0,
4 * voffset * PGL.SIZEOF_FLOAT);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glLineIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(glLineIndex, icount, ioffset);
}
shader.unbind();
@@ -2632,7 +2639,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void flushPoints() {
updatePointBuffers();
- PointShader shader = getPointShader();
+ PShader shader = getPointShader();
shader.bind();
IndexCache cache = tessGeo.pointIndexCache;
@@ -2648,10 +2655,7 @@ public class PGraphicsOpenGL extends PGraphics {
shader.setPointAttribute(glPointAttrib, 2, PGL.FLOAT, 0,
2 * voffset * PGL.SIZEOF_FLOAT);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPointIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(glPointIndex, icount, ioffset);
}
shader.unbind();
@@ -2683,8 +2687,8 @@ public class PGraphicsOpenGL extends PGraphics {
int perim;
if (0 < size) { // round point
weight = +size / 0.5f;
- perim = PApplet.max(MIN_POINT_ACCURACY,
- (int) (TWO_PI * weight / POINT_ACCURACY_FACTOR)) + 1;
+ perim = PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY,
+ (int) (TWO_PI * weight / POINT_ACCURACY_FACTOR))) + 1;
} else { // Square point
weight = -size / 0.5f;
perim = 5;
@@ -2755,9 +2759,7 @@ public class PGraphicsOpenGL extends PGraphics {
inGeo.setNormal(normalX, normalY, normalZ);
inGeo.addBezierVertex(x2, y2, z2,
x3, y3, z3,
- x4, y4, z4,
- fill, stroke, bezierDetail, vertexCode(), shape);
-
+ x4, y4, z4, vertexBreak());
}
@@ -2783,8 +2785,7 @@ public class PGraphicsOpenGL extends PGraphics {
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
inGeo.addQuadraticVertex(cx, cy, cz,
- x3, y3, z3,
- fill, stroke, bezierDetail, vertexCode(), shape);
+ x3, y3, z3, vertexBreak());
}
@@ -2809,8 +2810,7 @@ public class PGraphicsOpenGL extends PGraphics {
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addCurveVertex(x, y, z,
- fill, stroke, curveDetail, vertexCode(), shape);
+ inGeo.addCurveVertex(x, y, z, vertexBreak());
}
@@ -2901,70 +2901,43 @@ public class PGraphicsOpenGL extends PGraphics {
x2, y2, 0,
x3, y3, 0,
x4, y4, 0,
- fill, stroke);
- endShape();
- }
-
- //////////////////////////////////////////////////////////////
-
- // RECT
-
- // public void rectMode(int mode)
-
- @Override
- public void rect(float a, float b, float c, float d) {
- beginShape(QUADS);
- defaultEdges = false;
- normalMode = NORMAL_MODE_SHAPE;
- inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
- ambientColor, specularColor, emissiveColor, shininess);
- inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addRect(a, b, c, d,
- fill, stroke, rectMode);
+ stroke);
endShape();
}
@Override
- public void rect(float a, float b, float c, float d,
- float tl, float tr, float br, float bl) {
+ protected void rectImpl(float x1, float y1, float x2, float y2,
+ float tl, float tr, float br, float bl) {
beginShape(POLYGON);
defaultEdges = false;
normalMode = NORMAL_MODE_SHAPE;
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addRect(a, b, c, d,
- tl, tr, br, bl,
- fill, stroke, bezierDetail, rectMode);
- endShape(CLOSE);
+ inGeo.addRect(x1, y1, x2, y2, tl, tr, br, bl, stroke);
+ endShape();
}
- // protected void rectImpl(float x1, float y1, float x2, float y2)
//////////////////////////////////////////////////////////////
// ELLIPSE
- // public void ellipseMode(int mode)
-
@Override
- public void ellipse(float a, float b, float c, float d) {
+ public void ellipseImpl(float a, float b, float c, float d) {
beginShape(TRIANGLE_FAN);
defaultEdges = false;
normalMode = NORMAL_MODE_SHAPE;
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addEllipse(a, b, c, d, fill, stroke, ellipseMode);
+ inGeo.addEllipse(a, b, c, d, fill, stroke);
endShape();
}
- // public void ellipse(float a, float b, float c, float d)
-
-
@Override
protected void arcImpl(float x, float y, float w, float h,
float start, float stop, int mode) {
@@ -3006,6 +2979,10 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void sphere(float r) {
+ if ((sphereDetailU < 3) || (sphereDetailV < 2)) {
+ sphereDetail(30);
+ }
+
beginShape(TRIANGLES);
defaultEdges = false;
normalMode = NORMAL_MODE_VERTEX;
@@ -3083,7 +3060,11 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void smooth() {
- smooth(2);
+ if (quality < 2) {
+ smooth(2);
+ } else {
+ smooth(quality);
+ }
}
@@ -3111,6 +3092,7 @@ public class PGraphicsOpenGL extends PGraphics {
lastSmoothCall = parent.frameCount;
quality = level;
+
if (quality == 1) {
quality = 0;
}
@@ -3272,8 +3254,49 @@ public class PGraphicsOpenGL extends PGraphics {
// TEXT IMPL
- // protected void textLineAlignImpl(char buffer[], int start, int stop,
- // float x, float y)
+ @Override
+ public float textAscent() {
+ if (textFont == null) defaultFontOrDeath("textAscent");
+ Object font = textFont.getNative();
+ float ascent = 0;
+ if (font != null) ascent = pgl.getFontAscent(font);
+ if (ascent == 0) ascent = super.textAscent();
+ return ascent;
+ }
+
+
+ @Override
+ public float textDescent() {
+ if (textFont == null) defaultFontOrDeath("textAscent");
+ Object font = textFont.getNative();
+ float descent = 0;
+ if (font != null) descent = pgl.getFontDescent(font);
+ if (descent == 0) descent = super.textDescent();
+ return descent;
+ }
+
+
+ @Override
+ protected float textWidthImpl(char buffer[], int start, int stop) {
+ Object font = textFont.getNative();
+ float twidth = 0;
+ if (font != null) twidth = pgl.getTextWidth(font, buffer, start, stop);
+ if (twidth == 0) twidth = super.textWidthImpl(buffer, start, stop);
+ return twidth;
+ }
+
+
+ @Override
+ public void textSize(float size) {
+ if (textFont == null) defaultFontOrDeath("textSize", size);
+ Object font = textFont.getNative();
+ if (font != null) {
+ Object dfont = pgl.getDerivedFont(font, size);
+ textFont.setNative(dfont);
+ }
+ super.textSize(size);
+ }
+
/**
* Implementation of actual drawing for a line of text.
@@ -3339,7 +3362,6 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
protected void textCharImpl(char ch, float x, float y) {
PFont.Glyph glyph = textFont.getGlyph(ch);
-
if (glyph != null) {
if (textMode == MODEL) {
FontTexture.TextureInfo tinfo = textTex.getTexInfo(glyph);
@@ -3373,10 +3395,8 @@ public class PGraphicsOpenGL extends PGraphics {
if (textTex.currentTex != info.texIndex) {
textTex.setTexture(info.texIndex);
}
- PImage tex = textTex.getCurrentTexture();
-
beginShape(QUADS);
- texture(tex);
+ texture(textTex.getCurrentTexture());
vertex(x0, y0, info.u0, info.v0);
vertex(x1, y0, info.u1, info.v0);
vertex(x1, y1, info.u1, info.v1);
@@ -3430,17 +3450,13 @@ public class PGraphicsOpenGL extends PGraphics {
beginShape();
while (!outline.isDone()) {
int type = outline.currentSegment(textPoints);
- switch (type) {
- case PGL.SEG_MOVETO: // 1 point (2 vars) in textPoints
- case PGL.SEG_LINETO: // 1 point
- if (type == PGL.SEG_MOVETO) {
- beginContour();
- }
+ if (type == PGL.SEG_MOVETO) { // 1 point (2 vars) in textPoints
+ } else if (type == PGL.SEG_LINETO) { // 1 point
+ if (type == PGL.SEG_MOVETO) beginContour();
vertex(x + textPoints[0], y + textPoints[1]);
lastX = textPoints[0];
lastY = textPoints[1];
- break;
- case PGL.SEG_QUADTO: // 2 points
+ } else if (type == PGL.SEG_QUADTO) { // 2 points
for (int i = 1; i < bezierDetail; i++) {
float t = (float)i / (float)bezierDetail;
vertex(x + bezierPoint(lastX,
@@ -3454,8 +3470,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
lastX = textPoints[2];
lastY = textPoints[3];
- break;
- case PGL.SEG_CUBICTO: // 3 points
+ } else if (type == PGL.SEG_CUBICTO) { // 3 points
for (int i = 1; i < bezierDetail; i++) {
float t = (float)i / (float)bezierDetail;
vertex(x + bezierPoint(lastX, textPoints[0],
@@ -3465,10 +3480,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
lastX = textPoints[4];
lastY = textPoints[5];
- break;
- case PGL.SEG_CLOSE:
+ } else if (type == PGL.SEG_CLOSE) {
endContour();
- break;
}
outline.next();
}
@@ -4241,10 +4254,10 @@ public class PGraphicsOpenGL extends PGraphics {
public void ortho(float left, float right,
float bottom, float top,
float near, float far) {
- left -= width/2;
- right -= width/2;
- bottom -= height/2;
- top -= height/2;
+ left -= width/2f;
+ right -= width/2f;
+ bottom -= height/2f;
+ top -= height/2f;
// Flushing geometry with a different perspective configuration.
flush();
@@ -4523,8 +4536,20 @@ public class PGraphicsOpenGL extends PGraphics {
return nonZero(ow) ? oz / ow : oz;
}
+ //////////////////////////////////////////////////////////////
+
// STYLES
+ @Override
+ public void popStyle() {
+ // popStyle() sets ambient to true (because it calls ambient() in style())
+ // and so setting the setAmbient flag to true, even if the user didn't call
+ // ambient, so need to revert to false.
+ boolean savedSetAmbient = setAmbient;
+ super.popStyle();
+ if (!savedSetAmbient) setAmbient = false;
+ }
+
// public void pushStyle()
// public void popStyle()
// public void style(PStyle)
@@ -4704,6 +4729,9 @@ public class PGraphicsOpenGL extends PGraphics {
public void lights() {
enableLighting();
+ // reset number of lights
+ lightCount = 0;
+
// need to make sure colorMode is RGB 255 here
int colorModeSaved = colorMode;
colorMode = RGB;
@@ -5005,6 +5033,11 @@ public class PGraphicsOpenGL extends PGraphics {
if (0 < parent.frameCount) {
clearColorBuffer = true;
}
+ // Setting the background as opaque. If this an offscreen surface, the
+ // alpha channel will be set to 1 in endOffscreenDraw(), even if
+ // blending operations during draw create translucent areas in the
+ // color buffer.
+ backgroundA = 1;
}
@@ -5199,9 +5232,9 @@ public class PGraphicsOpenGL extends PGraphics {
try {
if (0 < x || 0 < y || w < width || h < height) {
- // The pixels to copy to the texture need to be consecutive, and they
- // are not in the pixels array, so putting each row one after another
- // in nativePixels.
+ // 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 = y * width + x;
int offset1 = 0;
@@ -5237,7 +5270,6 @@ public class PGraphicsOpenGL extends PGraphics {
// First, copy the pixels to the texture. We don't need to invert the
// pixel copy because the texture will be drawn inverted.
-
pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName,
x, y, w, h, nativePixelBuffer);
beginPixelsOp(OP_WRITE);
@@ -5294,6 +5326,17 @@ public class PGraphicsOpenGL extends PGraphics {
setgetPixels = true;
super.setImpl(sourceImage, sourceX, sourceY, sourceWidth, sourceHeight,
targetX, targetY);
+ // do we need this?
+ // see https://github.com/processing/processing/issues/2125
+// if (sourceImage.format == RGB) {
+// int targetOffset = targetY * width + targetX;
+// for (int y = sourceY; y < sourceY + sourceHeight; y++) {
+// for (int x = targetOffset; x < targetOffset + sourceWidth; x++) {
+// pixels[x] |= 0xff000000;
+// }
+// targetOffset += width;
+// }
+// }
}
@@ -5302,8 +5345,8 @@ public class PGraphicsOpenGL extends PGraphics {
// LOAD/UPDATE TEXTURE
- // Copies the contents of the color buffer into the pixels
- // array, and then the pixels array into the screen texture.
+ // Loads the current contents of the renderer's drawing surface into the
+ // its texture.
public void loadTexture() {
boolean needEndDraw = false;
if (!drawing) {
@@ -5340,12 +5383,10 @@ public class PGraphicsOpenGL extends PGraphics {
texture.setNative(nativePixelBuffer, 0, 0, width, height);
}
- } else {
- // We need to copy the contents of the multisampled buffer to the
- // color buffer, so the later is up-to-date with the last drawing.
- if (offscreenMultisample) {
- multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
- }
+ } else if (offscreenMultisample) {
+ // We need to copy the contents of the multisampled buffer to the color
+ // buffer, so the later is up-to-date with the last drawing.
+ multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
}
if (needEndDraw) {
@@ -5463,8 +5504,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
if (maskShader == null) {
- maskShader = new TextureShader(parent, defTextureShaderVertURL,
- maskShaderFragURL);
+ maskShader = new PShader(parent, defTextureShaderVertURL,
+ maskShaderFragURL);
}
maskShader.set("mask", alpha);
filter(maskShader);
@@ -5505,7 +5546,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void filter(PShader shader) {
- if (!(shader instanceof TextureShader)) {
+ if (!shader.isPolyShader() || !shader.supportsTexturing()) {
PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR);
return;
}
@@ -5547,8 +5588,8 @@ public class PGraphicsOpenGL extends PGraphics {
stroke = false;
int prevBlendMode = blendMode;
blendMode(REPLACE);
- TextureShader prevTexShader = textureShader;
- textureShader = (TextureShader) shader;
+ PShader prevShader = polyShader;
+ polyShader = shader;
beginShape(QUADS);
texture(filterImage);
@@ -5560,7 +5601,7 @@ public class PGraphicsOpenGL extends PGraphics {
end2D();
// Restoring previous configuration.
- textureShader = prevTexShader;
+ polyShader = prevShader;
stroke = prevStroke;
lights = prevLights;
textureMode = prevTextureMode;
@@ -5581,101 +5622,100 @@ public class PGraphicsOpenGL extends PGraphics {
//////////////////////////////////////////////////////////////
- /**
- * Extremely slow and not optimized, should use GL methods instead. Currently
- * calls a beginPixels() on the whole canvas, then does the copy, then it
- * calls endPixels().
- */
- // public void copy(int sx1, int sy1, int sx2, int sy2,
- // int dx1, int dy1, int dx2, int dy2)
+ // COPY
- // public void copy(PImage src,
- // int sx1, int sy1, int sx2, int sy2,
- // int dx1, int dy1, int dx2, int dy2)
+
+ @Override
+ public void copy(int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh) {
+ if (primarySurface) pgl.requestFBOLayer();
+ loadTexture();
+ if (filterTexture == null || filterTexture.contextIsOutdated()) {
+ filterTexture = new Texture(texture.width, texture.height,
+ texture.getParameters());
+ filterTexture.invertedY(true);
+ filterImage = wrapTexture(filterTexture);
+ }
+ filterTexture.put(texture, sx, height - (sy + sh), sw, height - sy);
+ copy(filterImage, sx, sy, sw, sh, dx, dy, dw, dh);
+ }
+
+
+ @Override
+ public void copy(PImage src,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh) {
+ boolean needEndDraw = false;
+ if (!drawing) {
+ beginDraw();
+ needEndDraw = true;
+ }
+
+ flush(); // make sure that the screen contents are up to date.
+
+ Texture tex = getTexture(src);
+ pgl.drawTexture(tex.glTarget, tex.glName,
+ tex.glWidth, tex.glHeight, width, height,
+ sx, tex.height - (sy + sh),
+ sx + sw, tex.height - sy,
+ dx, height - (dy + dh),
+ dx + dw, height - dy);
+
+ if (needEndDraw) {
+ endDraw();
+ }
+ }
//////////////////////////////////////////////////////////////
// BLEND
- // static public int blendColor(int c1, int c2, int mode)
-
- // public void blend(PImage src,
- // int sx, int sy, int dx, int dy, int mode) {
- // set(dx, dy, PImage.blendColor(src.get(sx, sy), get(dx, dy), mode));
- // }
-
-
- /**
- * Extremely slow and not optimized, should use GL methods instead. Currently
- * calls a beginPixels() on the whole canvas, then does the copy, then it
- * calls endPixels(). Please help fix: Bug 941, Bug 942.
- */
- // public void blend(int sx1, int sy1, int sx2, int sy2,
- // int dx1, int dy1, int dx2, int dy2, int mode) {
- // loadPixels();
- // super.blend(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode);
- // updatePixels();
- // }
-
- // public void blend(PImage src,
- // int sx1, int sy1, int sx2, int sy2,
- // int dx1, int dy1, int dx2, int dy2, int mode) {
- // loadPixels();
- // super.blend(src, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode);
- // updatePixels();
- // }
-
/**
* Allows to set custom blend modes for the entire scene, using openGL.
* Reference article about blending modes:
* http://www.pegtop.net/delphi/articles/blendmodes/
- * HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be
+ * DIFFERENCE, HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be
* implemented in fixed-function pipeline because they require
* conditional blending and non-linear blending equations.
*/
@Override
- public void blendMode(int mode) {
- if (blendMode != mode) {
+ protected void blendModeImpl() {
+ if (blendMode != lastBlendMode) {
// Flush any geometry that uses a different blending mode.
flush();
- setBlendMode(mode);
}
- }
-
- protected void setBlendMode(int mode) {
- blendMode = mode;
pgl.enable(PGL.BLEND);
- if (mode == REPLACE) {
+ if (blendMode == REPLACE) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.ONE, PGL.ZERO);
- } else if (mode == BLEND) {
+ } else if (blendMode == BLEND) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.SRC_ALPHA, PGL.ONE_MINUS_SRC_ALPHA);
- } else if (mode == ADD) {
+ } else if (blendMode == ADD) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.SRC_ALPHA, PGL.ONE);
- } else if (mode == SUBTRACT) {
+ } else if (blendMode == SUBTRACT) {
if (blendEqSupported) {
- pgl.blendEquation(PGL.FUNC_ADD);
+ pgl.blendEquation(PGL.FUNC_REVERSE_SUBTRACT);
+ pgl.blendFunc(PGL.ONE, PGL.SRC_ALPHA);
+ } else {
+ PGraphics.showWarning(BLEND_DRIVER_ERROR, "SUBTRACT");
}
- pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ZERO);
- } else if (mode == LIGHTEST) {
+ } else if (blendMode == LIGHTEST) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_MAX);
pgl.blendFunc(PGL.SRC_ALPHA, PGL.DST_ALPHA);
@@ -5683,7 +5723,7 @@ public class PGraphicsOpenGL extends PGraphics {
PGraphics.showWarning(BLEND_DRIVER_ERROR, "LIGHTEST");
}
- } else if (mode == DARKEST) {
+ } else if (blendMode == DARKEST) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_MIN);
pgl.blendFunc(PGL.SRC_ALPHA, PGL.DST_ALPHA);
@@ -5691,47 +5731,43 @@ public class PGraphicsOpenGL extends PGraphics {
PGraphics.showWarning(BLEND_DRIVER_ERROR, "DARKEST");
}
- } else if (mode == DIFFERENCE) {
- if (blendEqSupported) {
- pgl.blendEquation(PGL.FUNC_REVERSE_SUBTRACT);
- pgl.blendFunc(PGL.ONE, PGL.ONE);
- } else {
- PGraphics.showWarning(BLEND_DRIVER_ERROR, "DIFFERENCE");
- }
-
- } else if (mode == EXCLUSION) {
+ } else if (blendMode == EXCLUSION) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ONE_MINUS_SRC_COLOR);
- } else if (mode == MULTIPLY) {
+ } else if (blendMode == MULTIPLY) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.DST_COLOR, PGL.SRC_COLOR);
- } else if (mode == SCREEN) {
+ } else if (blendMode == SCREEN) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
}
pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ONE);
- } else if (mode == OVERLAY) {
+ } else if (blendMode == DIFFERENCE) {
+ PGraphics.showWarning(BLEND_RENDERER_ERROR, "DIFFERENCE");
+
+ } else if (blendMode == OVERLAY) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "OVERLAY");
- } else if (mode == HARD_LIGHT) {
+ } else if (blendMode == HARD_LIGHT) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "HARD_LIGHT");
- } else if (mode == SOFT_LIGHT) {
+ } else if (blendMode == SOFT_LIGHT) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "SOFT_LIGHT");
- } else if (mode == DODGE) {
+ } else if (blendMode == DODGE) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "DODGE");
- } else if (mode == BURN) {
+ } else if (blendMode == BURN) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "BURN");
}
+ lastBlendMode = blendMode;
}
@@ -5748,23 +5784,25 @@ public class PGraphicsOpenGL extends PGraphics {
/**
+ * Not an approved function, this will change or be removed in the future.
* This utility method returns the texture associated to the renderer's.
* drawing surface, making sure is updated to reflect the current contents
* off the screen (or offscreen drawing surface).
*/
- protected Texture getTexture() {
+ public Texture getTexture() {
loadTexture();
return texture;
}
/**
+ * Not an approved function, this will change or be removed in the future.
* This utility method returns the texture associated to the image.
* creating and/or updating it if needed.
*
* @param img the image to have a texture metadata associated to it
*/
- protected Texture getTexture(PImage img) {
+ public Texture getTexture(PImage img) {
Texture tex = (Texture)initCache(img);
if (tex == null) return null;
@@ -6061,6 +6099,15 @@ public class PGraphicsOpenGL extends PGraphics {
protected void endOffscreenDraw() {
+ // Set alpha channel to opaque in order to match behavior of JAVA2D:
+ // https://github.com/processing/processing/issues/1844
+ // but still not working as expected. Some strange artifacts with multismapled
+ // surfaces (see second code example in the issue above).
+// pgl.colorMask(false, false, false, true);
+// pgl.clearColor(0, 0, 0, 1);
+// pgl.clear(PGL.COLOR_BUFFER_BIT);
+// pgl.colorMask(true, true, true, true);
+
if (offscreenMultisample) {
multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
}
@@ -6088,11 +6135,8 @@ public class PGraphicsOpenGL extends PGraphics {
// Each frame starts with textures disabled.
super.noTexture();
- // Screen blend is needed for alpha (i.e. fonts) to work.
- // Using setBlendMode() instead of blendMode() because
- // the latter will set the blend mode only if it is different
- // from current.
- setBlendMode(BLEND);
+ // Making sure that OpenGL is using the last blend mode set by the user.
+ blendModeImpl();
// this is necessary for 3D drawing
if (hints[DISABLE_DEPTH_TEST]) {
@@ -6121,11 +6165,11 @@ public class PGraphicsOpenGL extends PGraphics {
} else {
pgl.enable(PGL.MULTISAMPLE);
}
- pgl.disable(PGL.POINT_SMOOTH);
- pgl.disable(PGL.LINE_SMOOTH);
pgl.disable(PGL.POLYGON_SMOOTH);
if (sized) {
+ //reapplySettings();
+
// To avoid having garbage in the screen after a resize,
// in the case background is not called in draw().
background(backgroundColor);
@@ -6176,9 +6220,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (restoreSurface) {
restoreSurfaceFromPixels();
- //if (1 < parent.frameCount) {
restoreSurface = false;
- //}
}
if (hints[DISABLE_DEPTH_MASK]) {
@@ -6204,16 +6246,11 @@ public class PGraphicsOpenGL extends PGraphics {
OPENGL_EXTENSIONS = pgl.getString(PGL.EXTENSIONS);
GLSL_VERSION = pgl.getString(PGL.SHADING_LANGUAGE_VERSION);
- npotTexSupported =
- -1 < OPENGL_EXTENSIONS.indexOf("_texture_non_power_of_two");
- autoMipmapGenSupported =
- -1 < OPENGL_EXTENSIONS.indexOf("_generate_mipmap");
- fboMultisampleSupported =
- -1 < OPENGL_EXTENSIONS.indexOf("_framebuffer_multisample");
- packedDepthStencilSupported =
- -1 < OPENGL_EXTENSIONS.indexOf("_packed_depth_stencil");
- anisoSamplingSupported =
- -1 < OPENGL_EXTENSIONS.indexOf("_texture_filter_anisotropic");
+ npotTexSupported = pgl.hasNpotTexSupport();
+ autoMipmapGenSupported = pgl.hasAutoMipmapGenSupport();
+ fboMultisampleSupported = pgl.hasFboMultisampleSupport();
+ packedDepthStencilSupported = pgl.hasPackedDepthStencilSupport();
+ anisoSamplingSupported = pgl.hasAnisoSamplingSupport();
try {
pgl.blendEquation(PGL.FUNC_ADD);
@@ -6231,12 +6268,6 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.getIntegerv(PGL.MAX_SAMPLES, intBuffer);
maxSamples = intBuffer.get(0);
- pgl.getIntegerv(PGL.ALIASED_LINE_WIDTH_RANGE, intBuffer);
- maxLineWidth = intBuffer.get(0);
-
- pgl.getIntegerv(PGL.ALIASED_POINT_SIZE_RANGE, intBuffer);
- maxPointSize = intBuffer.get(0);
-
if (anisoSamplingSupported) {
pgl.getFloatv(PGL.MAX_TEXTURE_MAX_ANISOTROPY, floatBuffer);
maxAnisoAmount = floatBuffer.get(0);
@@ -6253,133 +6284,77 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public PShader loadShader(String fragFilename) {
- int shaderType = getShaderType(fragFilename);
- if (shaderType == -1) {
- PGraphics.showWarning(INVALID_PROCESSING_SHADER_ERROR);
+ if (fragFilename == null || fragFilename.equals("")) {
+ PGraphics.showWarning(MISSING_FRAGMENT_SHADER);
return null;
}
- PShader shader = null;
- if (shaderType == PShader.POINT) {
- shader = new PointShader(parent);
- shader.setVertexShader(defPointShaderVertURL);
- } else if (shaderType == PShader.LINE) {
- shader = new LineShader(parent);
- shader.setVertexShader(defLineShaderVertURL);
- } else if (shaderType == PShader.TEXLIGHT) {
- shader = new TexlightShader(parent);
- shader.setVertexShader(defTexlightShaderVertURL);
- } else if (shaderType == PShader.LIGHT) {
- shader = new LightShader(parent);
- shader.setVertexShader(defLightShaderVertURL);
- } else if (shaderType == PShader.TEXTURE) {
- shader = new TextureShader(parent);
- shader.setVertexShader(defTextureShaderVertURL);
- } else if (shaderType == PShader.COLOR) {
- shader = new ColorShader(parent);
- shader.setVertexShader(defColorShaderVertURL);
- }
+
+ int type = PShader.getShaderType(parent.loadStrings(fragFilename),
+ PShader.POLY);
+ PShader shader = new PShader(parent);
+ shader.setType(type);
shader.setFragmentShader(fragFilename);
+ if (type == PShader.POINT) {
+ String[] vertSource = pgl.loadVertexShader(defPointShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else if (type == PShader.LINE) {
+ String[] vertSource = pgl.loadVertexShader(defLineShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else if (type == PShader.TEXLIGHT) {
+ String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else if (type == PShader.LIGHT) {
+ String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else if (type == PShader.TEXTURE) {
+ String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else if (type == PShader.COLOR) {
+ String[] vertSource = pgl.loadVertexShader(defColorShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ } else {
+ String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL, 120);
+ shader.setVertexShader(vertSource);
+ }
return shader;
}
@Override
public PShader loadShader(String fragFilename, String vertFilename) {
- int shaderType = getShaderType(vertFilename);
- if (shaderType == -1) {
- shaderType = getShaderType(fragFilename);
- }
- if (shaderType == -1) {
- PGraphics.showWarning(INVALID_PROCESSING_SHADER_ERROR);
- return null;
- }
-
- PShader shader = null;
if (fragFilename == null || fragFilename.equals("")) {
- if (shaderType == PShader.POINT) {
- shader = new PointShader(parent);
- shader.setFragmentShader(defPointShaderFragURL);
- } else if (shaderType == PShader.LINE) {
- shader = new LineShader(parent);
- shader.setFragmentShader(defLineShaderFragURL);
- } else if (shaderType == PShader.TEXLIGHT) {
- shader = new TexlightShader(parent);
- shader.setFragmentShader(defTextureShaderFragURL);
- } else if (shaderType == PShader.LIGHT) {
- shader = new LightShader(parent);
- shader.setFragmentShader(defColorShaderFragURL);
- } else if (shaderType == PShader.TEXTURE) {
- shader = new TextureShader(parent);
- shader.setFragmentShader(defTextureShaderFragURL);
- } else if (shaderType == PShader.COLOR) {
- shader = new ColorShader(parent);
- shader.setFragmentShader(defColorShaderFragURL);
- }
- if (shader != null) {
- shader.setVertexShader(vertFilename);
- }
+ PGraphics.showWarning(MISSING_FRAGMENT_SHADER);
+ return null;
+ } else if (fragFilename == null || fragFilename.equals("")) {
+ PGraphics.showWarning(MISSING_VERTEX_SHADER);
+ return null;
} else {
- if (shaderType == PShader.POINT) {
- shader = new PointShader(parent, vertFilename, fragFilename);
- } else if (shaderType == PShader.LINE) {
- shader = new LineShader(parent, vertFilename, fragFilename);
- } else if (shaderType == PShader.TEXLIGHT) {
- shader = new TexlightShader(parent, vertFilename, fragFilename);
- } else if (shaderType == PShader.LIGHT) {
- shader = new LightShader(parent, vertFilename, fragFilename);
- } else if (shaderType == PShader.TEXTURE) {
- shader = new TextureShader(parent, vertFilename, fragFilename);
- } else if (shaderType == PShader.COLOR) {
- shader = new ColorShader(parent, vertFilename, fragFilename);
- }
+ return new PShader(parent, vertFilename, fragFilename);
}
- return shader;
}
@Override
public void shader(PShader shader) {
- shader(shader, POLYGON);
+ flush(); // Flushing geometry drawn with a different shader.
+
+ if (shader.isPolyShader()) polyShader = shader;
+ else if (shader.isLineShader()) lineShader = shader;
+ else if (shader.isPointShader()) pointShader = shader;
+ else PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR);
}
@Override
+ // TODO: deprecate this method, the kind arguments is not used anymore
public void shader(PShader shader, int kind) {
- flush(); // Flushing geometry drawn with a different shader.
-
- if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) {
- if (shader instanceof TextureShader) {
- textureShader = (TextureShader) shader;
- } else if (shader instanceof ColorShader) {
- colorShader = (ColorShader) shader;
- } else if (shader instanceof TexlightShader) {
- texlightShader = (TexlightShader) shader;
- } else if (shader instanceof LightShader) {
- lightShader = (LightShader) shader;
- } else {
- PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR);
- }
- } else if (kind == LINES) {
- if (shader instanceof LineShader) {
- lineShader = (LineShader)shader;
- } else {
- PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR);
- }
- } else if (kind == POINTS) {
- if (shader instanceof PointShader) {
- pointShader = (PointShader)shader;
- } else {
- PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR);
- }
- } else {
- PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR);
- }
+ shader(shader);
}
@Override
public void resetShader() {
- resetShader(POLYGON);
+ resetShader(TRIANGLES);
}
@@ -6388,10 +6363,7 @@ public class PGraphicsOpenGL extends PGraphics {
flush(); // Flushing geometry drawn with a different shader.
if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) {
- textureShader = null;
- colorShader = null;
- texlightShader = null;
- lightShader = null;
+ polyShader = null;
} else if (kind == LINES) {
lineShader = null;
} else if (kind == POINTS) {
@@ -6402,35 +6374,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
- public void shaderWarnings(boolean enable) {
- shaderWarningsEnabled = enable;
- }
-
-
- protected int getShaderType(String filename) {
- String[] source = parent.loadStrings(filename);
- int type = -1;
- for (int i = 0; i < source.length; i++) {
- String line = source[i].trim();
-
- if (line.indexOf("#define PROCESSING_POINT_SHADER") == 0) {
- type = PShader.POINT;
- } else if (line.indexOf("#define PROCESSING_LINE_SHADER") == 0) {
- type = PShader.LINE;
- } else if (line.indexOf("#define PROCESSING_COLOR_SHADER") == 0) {
- type = PShader.COLOR;
- } else if (line.indexOf("#define PROCESSING_LIGHT_SHADER") == 0) {
- type = PShader.LIGHT;
- } else if (line.indexOf("#define PROCESSING_TEXTURE_SHADER") == 0) {
- type = PShader.TEXTURE;
- } else if (line.indexOf("#define PROCESSING_TEXLIGHT_SHADER") == 0) {
- type = PShader.TEXLIGHT;
- }
- }
- return type;
- }
-
-
protected void deleteDefaultShaders() {
// The default shaders contains references to the PGraphics object that
// creates them, so when restarting the renderer, those references should
@@ -6445,114 +6388,84 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected BaseShader getPolyShader(boolean lit, boolean tex) {
- BaseShader shader;
+ protected PShader getPolyShader(boolean lit, boolean tex) {
+ PShader shader;
+ boolean useDefault = polyShader == null;
+ if (polyShader != null) {
+ polyShader.setRenderer(this);
+ polyShader.loadAttributes();
+ polyShader.loadUniforms();
+ }
if (lit) {
if (tex) {
- if (texlightShader == null) {
+ if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) {
if (defTexlightShader == null) {
- defTexlightShader = new TexlightShader(parent,
- defTexlightShaderVertURL,
- defTextureShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120);
+ defTexlightShader = new PShader(parent, vertSource, fragSource);
}
shader = defTexlightShader;
- texlightShaderCheck();
} else {
- shader = texlightShader;
+ shader = polyShader;
}
} else {
- if (lightShader == null) {
+ if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) {
if (defLightShader == null) {
- defLightShader = new LightShader(parent,
- defLightShaderVertURL,
- defColorShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120);
+ defLightShader = new PShader(parent, vertSource, fragSource);
}
shader = defLightShader;
- lightShaderCheck();
} else {
- shader = lightShader;
+ shader = polyShader;
}
}
} else {
+ if (polyShader != null && polyShader.accessLightAttribs()) {
+ PGraphics.showWarning(SHADER_NEED_LIGHT_ATTRIBS);
+ useDefault = true;
+ }
+
if (tex) {
- if (textureShader == null) {
+ if (useDefault || !polyShader.checkPolyType(PShader.TEXTURE)) {
if (defTextureShader == null) {
- defTextureShader = new TextureShader(parent,
- defTextureShaderVertURL,
- defTextureShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120);
+ defTextureShader = new PShader(parent, vertSource, fragSource);
}
shader = defTextureShader;
- textureShaderCheck();
} else {
- shader = textureShader;
+ shader = polyShader;
}
} else {
- if (colorShader == null) {
+ if (useDefault || !polyShader.checkPolyType(PShader.COLOR)) {
if (defColorShader == null) {
- defColorShader = new ColorShader(parent,
- defColorShaderVertURL,
- defColorShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defColorShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120);
+ defColorShader = new PShader(parent, vertSource, fragSource);
}
shader = defColorShader;
- colorShaderCheck();
} else {
- shader = colorShader;
+ shader = polyShader;
}
}
}
- shader.setRenderer(this);
- shader.loadAttributes();
- shader.loadUniforms();
+ if (shader != polyShader) {
+ shader.setRenderer(this);
+ shader.loadAttributes();
+ shader.loadUniforms();
+ }
return shader;
}
- protected void texlightShaderCheck() {
- if (shaderWarningsEnabled &&
- (lightShader != null ||
- textureShader != null ||
- colorShader != null)) {
- PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR);
- }
- }
-
-
- protected void lightShaderCheck() {
- if (shaderWarningsEnabled &&
- (texlightShader != null ||
- textureShader != null ||
- colorShader != null)) {
- PGraphics.showWarning(NO_LIGHT_SHADER_ERROR);
- }
- }
-
-
- protected void textureShaderCheck() {
- if (shaderWarningsEnabled &&
- (texlightShader != null ||
- lightShader != null ||
- colorShader != null)) {
- PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR);
- }
- }
-
-
- protected void colorShaderCheck() {
- if (shaderWarningsEnabled &&
- (texlightShader != null ||
- lightShader != null ||
- textureShader != null)) {
- PGraphics.showWarning(NO_COLOR_SHADER_ERROR);
- }
- }
-
-
- protected LineShader getLineShader() {
- LineShader shader;
+ protected PShader getLineShader() {
+ PShader shader;
if (lineShader == null) {
if (defLineShader == null) {
- defLineShader = new LineShader(parent, defLineShaderVertURL,
- defLineShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defLineShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defLineShaderFragURL, 120);
+ defLineShader = new PShader(parent, vertSource, fragSource);
}
shader = defLineShader;
} else {
@@ -6565,12 +6478,13 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected PointShader getPointShader() {
- PointShader shader;
+ protected PShader getPointShader() {
+ PShader shader;
if (pointShader == null) {
if (defPointShader == null) {
- defPointShader = new PointShader(parent, defPointShaderVertURL,
- defPointShaderFragURL);
+ String[] vertSource = pgl.loadVertexShader(defPointShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defPointShaderFragURL, 120);
+ defPointShader = new PShader(parent, vertSource, fragSource);
}
shader = defPointShader;
} else {
@@ -6583,765 +6497,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected class BaseShader extends PShader {
- protected int transformLoc;
- protected int modelviewLoc;
- protected int projectionLoc;
- protected int bufferLoc;
- protected int bufferUnit;
- protected int viewportLoc;
-
- public BaseShader(PApplet parent) {
- super(parent);
- }
-
- public BaseShader(PApplet parent, String vertFilename, String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public BaseShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadUniforms() {
- transformLoc = getUniformLoc("transform");
- modelviewLoc = getUniformLoc("modelview");
- projectionLoc = getUniformLoc("projection");
- viewportLoc = getUniformLoc("viewport");
- bufferLoc = getUniformLoc("buffer");
- }
-
- @Override
- public void unbind() {
- if (-1 < bufferLoc) {
- pgl.requestFBOLayer();
- pgl.activeTexture(PGL.TEXTURE0 + bufferUnit);
- pgCurrent.unbindFrontTexture();
- pgl.activeTexture(PGL.TEXTURE0);
- }
-
- pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
-
- super.unbind();
- }
-
- protected void setCommonUniforms() {
- if (-1 < transformLoc) {
- pgCurrent.updateGLProjmodelview();
- setUniformMatrix(transformLoc, pgCurrent.glProjmodelview);
- }
-
- if (-1 < modelviewLoc) {
- pgCurrent.updateGLModelview();
- setUniformMatrix(modelviewLoc, pgCurrent.glModelview);
- }
-
- if (-1 < projectionLoc) {
- pgCurrent.updateGLProjection();
- setUniformMatrix(projectionLoc, pgCurrent.glProjection);
- }
-
- if (-1 < viewportLoc) {
- float x = pgCurrent.viewport.get(0);
- float y = pgCurrent.viewport.get(1);
- float w = pgCurrent.viewport.get(2);
- float h = pgCurrent.viewport.get(3);
- setUniformValue(viewportLoc, x, y, w, h);
- }
-
- if (-1 < bufferLoc) {
- bufferUnit = getLastTexUnit() + 1;
- setUniformValue(bufferLoc, bufferUnit);
- pgl.activeTexture(PGL.TEXTURE0 + bufferUnit);
- pgCurrent.bindFrontTexture();
- } else {
- bufferUnit = -1;
- }
- }
-
- public void setVertexAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setColorAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setNormalAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setAmbientAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setSpecularAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setEmissiveAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setShininessAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setTexcoordAttribute(int vboId, int size, int type,
- int stride, int offset) { }
- public void setTexture(Texture tex) { }
- }
-
-
- protected class ColorShader extends BaseShader {
- protected int vertexLoc;
- protected int colorLoc;
-
- public ColorShader(PApplet parent) {
- super(parent);
- }
-
- public ColorShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public ColorShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadAttributes() {
- vertexLoc = getAttributeLoc("vertex");
- colorLoc = getAttributeLoc("color");
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
- }
-
- @Override
- public void setVertexAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setColorAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset);
- }
-
- @Override
- public void bind() {
- super.bind();
- if (pgCurrent == null) {
- setRenderer(PGraphicsOpenGL.pgCurrent);
- loadAttributes();
- loadUniforms();
- }
-
- if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc);
-
- setCommonUniforms();
- }
-
- @Override
- public void unbind() {
- if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc);
-
- super.unbind();
- }
- }
-
-
- protected class LightShader extends BaseShader {
- protected int normalMatrixLoc;
-
- protected int lightCountLoc;
- protected int lightPositionLoc;
- protected int lightNormalLoc;
- protected int lightAmbientLoc;
- protected int lightDiffuseLoc;
- protected int lightSpecularLoc;
- protected int lightFalloffLoc;
- protected int lightSpotLoc;
-
- protected int vertexLoc;
- protected int colorLoc;
- protected int normalLoc;
-
- protected int ambientLoc;
- protected int specularLoc;
- protected int emissiveLoc;
- protected int shininessLoc;
-
- public LightShader(PApplet parent) {
- super(parent);
- }
-
- public LightShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public LightShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadAttributes() {
- vertexLoc = getAttributeLoc("vertex");
- colorLoc = getAttributeLoc("color");
- normalLoc = getAttributeLoc("normal");
-
- ambientLoc = getAttributeLoc("ambient");
- specularLoc = getAttributeLoc("specular");
- emissiveLoc = getAttributeLoc("emissive");
- shininessLoc = getAttributeLoc("shininess");
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
-
- normalMatrixLoc = getUniformLoc("normalMatrix");
-
- lightCountLoc = getUniformLoc("lightCount");
- lightPositionLoc = getUniformLoc("lightPosition");
- lightNormalLoc = getUniformLoc("lightNormal");
- lightAmbientLoc = getUniformLoc("lightAmbient");
- lightDiffuseLoc = getUniformLoc("lightDiffuse");
- lightSpecularLoc = getUniformLoc("lightSpecular");
- lightFalloffLoc = getUniformLoc("lightFalloff");
- lightSpotLoc = getUniformLoc("lightSpot");
- }
-
- @Override
- public void setVertexAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setColorAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset);
- }
-
- @Override
- public void setNormalAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setAmbientAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset);
- }
-
- @Override
- public void setSpecularAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset);
- }
-
- @Override
- public void setEmissiveAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset);
- }
-
- @Override
- public void setShininessAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void bind() {
- super.bind();
- if (pgCurrent == null) {
- setRenderer(PGraphicsOpenGL.pgCurrent);
- loadAttributes();
- loadUniforms();
- }
-
- if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc);
- if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc);
-
- if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc);
- if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc);
- if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc);
- if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc);
-
- if (-1 < normalMatrixLoc) {
- pgCurrent.updateGLNormal();
- setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal);
- }
-
- int count = pgCurrent.lightCount;
- setUniformValue(lightCountLoc, count);
- setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count);
- setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count);
- setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count);
- setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count);
- setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count);
- setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients,
- 3, count);
- setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count);
-
- setCommonUniforms();
- }
-
- @Override
- public void unbind() {
- if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc);
- if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc);
-
- if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc);
- if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc);
- if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc);
- if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc);
-
- super.unbind();
- }
- }
-
-
- protected class TextureShader extends ColorShader {
- protected Texture texture;
- protected int texUnit;
- protected int texCoordLoc;
-
- protected int textureLoc;
- protected int texMatrixLoc;
- protected int texOffsetLoc;
-
- protected int normalMatrixLoc;
- protected int normalLoc;
-
- protected float[] tcmat;
-
- public TextureShader(PApplet parent) {
- super(parent);
- }
-
- public TextureShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public TextureShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
-
- textureLoc = getUniformLoc("texture");
- texMatrixLoc = getUniformLoc("texMatrix");
- texOffsetLoc = getUniformLoc("texOffset");
-
- normalMatrixLoc = getUniformLoc("normalMatrix");
- }
-
- @Override
- public void loadAttributes() {
- super.loadAttributes();
-
- texCoordLoc = getAttributeLoc("texCoord");
-
- normalLoc = getAttributeLoc("normal");
- }
-
- @Override
- public void setNormalAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setTexcoordAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public int getLastTexUnit() {
- return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit();
- }
-
- @Override
- public void setTexture(Texture tex) {
- float scaleu = 1;
- float scalev = 1;
- float dispu = 0;
- float dispv = 0;
-
- if (tex.invertedX()) {
- scaleu = -1;
- dispu = 1;
- }
-
- if (tex.invertedY()) {
- scalev = -1;
- dispv = 1;
- }
-
- scaleu *= tex.maxTexcoordU();
- dispu *= tex.maxTexcoordU();
- scalev *= tex.maxTexcoordV();
- dispv *= tex.maxTexcoordV();
-
- if (-1 < texMatrixLoc) {
- if (tcmat == null) {
- tcmat = new float[16];
- }
- tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu;
- tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv;
- tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0;
- tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0;
- setUniformMatrix(texMatrixLoc, tcmat);
- }
-
- setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
-
- if (-1 < textureLoc) {
- texUnit = getLastTexUnit() + 1;
- setUniformValue(textureLoc, texUnit);
- pgl.activeTexture(PGL.TEXTURE0 + texUnit);
- tex.bind();
- texture = tex;
- }
- }
-
- @Override
- public void bind() {
- super.bind();
-
- if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc);
-
- if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc);
- if (-1 < normalMatrixLoc) {
- pgCurrent.updateGLNormal();
- setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal);
- }
- }
-
- @Override
- public void unbind() {
- if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc);
- if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc);
-
- if (-1 < textureLoc && texture != null) {
- pgl.activeTexture(PGL.TEXTURE0 + texUnit);
- texture.unbind();
- pgl.activeTexture(PGL.TEXTURE0);
- texture = null;
- }
-
- super.unbind();
- }
- }
-
-
- protected class TexlightShader extends LightShader {
- protected Texture texture;
- protected int texUnit;
- protected int texCoordLoc;
-
- protected int textureLoc;
- protected int texMatrixLoc;
- protected int texOffsetLoc;
-
- protected float[] tcmat;
-
- public TexlightShader(PApplet parent) {
- super(parent);
- }
-
- public TexlightShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public TexlightShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
-
- textureLoc = getUniformLoc("texture");
- texMatrixLoc = getUniformLoc("texMatrix");
- texOffsetLoc = getUniformLoc("texOffset");
- }
-
- @Override
- public void loadAttributes() {
- super.loadAttributes();
-
- texCoordLoc = getAttributeLoc("texCoord");
- }
-
- @Override
- public void setTexcoordAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public int getLastTexUnit() {
- return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit();
- }
-
- @Override
- public void setTexture(Texture tex) {
- float scaleu = 1;
- float scalev = 1;
- float dispu = 0;
- float dispv = 0;
-
- if (tex.invertedX()) {
- scaleu = -1;
- dispu = 1;
- }
-
- if (tex.invertedY()) {
- scalev = -1;
- dispv = 1;
- }
-
- scaleu *= tex.maxTexcoordU;
- dispu *= tex.maxTexcoordU;
- scalev *= tex.maxTexcoordV;
- dispv *= tex.maxTexcoordV;
-
- if (-1 < texMatrixLoc) {
- if (tcmat == null) {
- tcmat = new float[16];
- }
- tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu;
- tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv;
- tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0;
- tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0;
- setUniformMatrix(texMatrixLoc, tcmat);
- }
-
- setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
-
- if (-1 < textureLoc) {
- texUnit = getLastTexUnit() + 1;
- setUniformValue(textureLoc, texUnit);
- pgl.activeTexture(PGL.TEXTURE0 + texUnit);
- tex.bind();
- texture = tex;
- }
- }
-
- @Override
- public void bind() {
- super.bind();
-
- if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc);
- }
-
- @Override
- public void unbind() {
- if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc);
-
- if (-1 < textureLoc && texture != null) {
- pgl.activeTexture(PGL.TEXTURE0 + texUnit);
- texture.unbind();
- pgl.activeTexture(PGL.TEXTURE0);
- texture = null;
- }
-
- super.unbind();
- }
- }
-
-
- protected class LineShader extends BaseShader {
- protected int perspectiveLoc;
- protected int scaleLoc;
-
- protected int vertexLoc;
- protected int colorLoc;
- protected int directionLoc;
-
- public LineShader(PApplet parent) {
- super(parent);
- }
-
- public LineShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public LineShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadAttributes() {
- vertexLoc = getAttributeLoc("vertex");
- colorLoc = getAttributeLoc("color");
- directionLoc = getAttributeLoc("direction");
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
-
- viewportLoc = getUniformLoc("viewport");
- perspectiveLoc = getUniformLoc("perspective");
- scaleLoc = getUniformLoc("scale");
- }
-
- @Override
- public void setVertexAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setColorAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset);
- }
-
- public void setLineAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void bind() {
- super.bind();
- if (pgCurrent == null) {
- setRenderer(PGraphicsOpenGL.pgCurrent);
- loadAttributes();
- loadUniforms();
- }
-
- if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc);
- if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc);
-
- if (pgCurrent.getHint(ENABLE_STROKE_PERSPECTIVE) &&
- pgCurrent.nonOrthoProjection()) {
- setUniformValue(perspectiveLoc, 1);
- } else {
- setUniformValue(perspectiveLoc, 0);
- }
-
- if (pgCurrent.getHint(DISABLE_OPTIMIZED_STROKE)) {
- setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f);
- } else {
- float f = PGL.STROKE_DISPLACEMENT;
- if (orthoProjection()) {
- setUniformValue(scaleLoc, 1, 1, f);
- } else {
- setUniformValue(scaleLoc, f, f, f);
- }
- }
-
- setCommonUniforms();
- }
-
- @Override
- public void unbind() {
- if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc);
- if (-1 < directionLoc) pgl.disableVertexAttribArray(directionLoc);
-
- super.unbind();
- }
- }
-
-
- protected class PointShader extends BaseShader {
- protected int perspectiveLoc;
-
- protected int vertexLoc;
- protected int colorLoc;
- protected int offsetLoc;
-
- public PointShader(PApplet parent) {
- super(parent);
- }
-
- public PointShader(PApplet parent, String vertFilename,
- String fragFilename) {
- super(parent, vertFilename, fragFilename);
- }
-
- public PointShader(PApplet parent, URL vertURL, URL fragURL) {
- super(parent, vertURL, fragURL);
- }
-
- @Override
- public void loadAttributes() {
- vertexLoc = getAttributeLoc("vertex");
- colorLoc = getAttributeLoc("color");
- offsetLoc = getAttributeLoc("offset");
- }
-
- @Override
- public void loadUniforms() {
- super.loadUniforms();
-
- perspectiveLoc = getUniformLoc("perspective");
- }
-
- @Override
- public void setVertexAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void setColorAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset);
- }
-
- public void setPointAttribute(int vboId, int size, int type,
- int stride, int offset) {
- setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset);
- }
-
- @Override
- public void bind() {
- super.bind();
- if (pgCurrent == null) {
- setRenderer(PGraphicsOpenGL.pgCurrent);
- loadAttributes();
- loadUniforms();
- }
-
- if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc);
- if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc);
-
- if (pgCurrent.getHint(ENABLE_STROKE_PERSPECTIVE) &&
- pgCurrent.nonOrthoProjection()) {
- setUniformValue(perspectiveLoc, 1);
- } else {
- setUniformValue(perspectiveLoc, 0);
- }
-
- super.setCommonUniforms();
- }
-
- @Override
- public void unbind() {
- if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc);
- if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc);
- if (-1 < offsetLoc) pgl.disableVertexAttribArray(offsetLoc);
-
- super.unbind();
- }
- }
-
-
//////////////////////////////////////////////////////////////
// Utils
@@ -7359,24 +6514,24 @@ public class PGraphicsOpenGL extends PGraphics {
// Input (raw) and Tessellated geometry, tessellator.
- protected InGeometry newInGeometry(int mode) {
- return new InGeometry(mode);
+ static protected InGeometry newInGeometry(PGraphicsOpenGL pg, int mode) {
+ return new InGeometry(pg, mode);
}
- protected TessGeometry newTessGeometry(int mode) {
- return new TessGeometry(mode);
+ static protected TessGeometry newTessGeometry(PGraphicsOpenGL pg, int mode) {
+ return new TessGeometry(pg, mode);
}
- protected TexCache newTexCache() {
+ static protected TexCache newTexCache() {
return new TexCache();
}
// Holds an array of textures and the range of vertex
// indices each texture applies to.
- protected class TexCache {
+ static protected class TexCache {
int size;
PImage[] textures;
int[] firstIndex;
@@ -7494,7 +6649,7 @@ public class PGraphicsOpenGL extends PGraphics {
// Stores the offsets and counts of indices and vertices
// to render a piece of geometry that doesn't fit in a single
// glDrawElements() call.
- protected class IndexCache {
+ static protected class IndexCache {
int size;
int[] indexCount;
int[] indexOffset;
@@ -7599,23 +6754,14 @@ public class PGraphicsOpenGL extends PGraphics {
// Holds the input vertices: xyz coordinates, fill/tint color,
// normal, texture coordinates and stroke color and weight.
- protected class InGeometry {
+ static protected class InGeometry {
+ PGraphicsOpenGL pg;
int renderMode;
+
int vertexCount;
+ int codeCount;
int edgeCount;
- // Range of vertices that will be processed by the
- // tessellator. They can be used in combination with the
- // edges array to have the tessellator using only a specific
- // range of vertices to generate fill geometry, while the
- // line geometry will be read from the edge vertices, which
- // could be completely different.
- int firstVertex;
- int lastVertex;
-
- int firstEdge;
- int lastEdge;
-
float[] vertices;
int[] colors;
float[] normals;
@@ -7623,8 +6769,10 @@ public class PGraphicsOpenGL extends PGraphics {
int[] strokeColors;
float[] strokeWeights;
- // lines
- boolean[] breaks;
+ // vertex codes
+ int[] codes;
+
+ // Stroke edges
int[][] edges;
// Material properties
@@ -7643,7 +6791,8 @@ public class PGraphicsOpenGL extends PGraphics {
float shininessFactor;
float normalX, normalY, normalZ;
- InGeometry(int mode) {
+ InGeometry(PGraphicsOpenGL pg, int mode) {
+ this.pg = pg;
renderMode = mode;
allocate();
}
@@ -7653,12 +6802,13 @@ public class PGraphicsOpenGL extends PGraphics {
// Allocate/dispose
void clear() {
- vertexCount = firstVertex = lastVertex = 0;
- edgeCount = firstEdge = lastEdge = 0;
+ vertexCount = 0;
+ codeCount = 0;
+ edgeCount = 0;
}
void clearEdges() {
- edgeCount = firstEdge = lastEdge = 0;
+ edgeCount = 0;
}
void allocate() {
@@ -7672,7 +6822,6 @@ public class PGraphicsOpenGL extends PGraphics {
specular = new int[PGL.DEFAULT_IN_VERTICES];
emissive = new int[PGL.DEFAULT_IN_VERTICES];
shininess = new float[PGL.DEFAULT_IN_VERTICES];
- breaks = new boolean[PGL.DEFAULT_IN_VERTICES];
edges = new int[PGL.DEFAULT_IN_EDGES][3];
clear();
@@ -7692,7 +6841,14 @@ public class PGraphicsOpenGL extends PGraphics {
expandSpecular(newSize);
expandEmissive(newSize);
expandShininess(newSize);
- expandBreaks(newSize);
+ }
+ }
+
+ void codeCheck() {
+ if (codeCount == codes.length) {
+ int newLen = codeCount << 1;
+
+ expandCodes(newLen);
}
}
@@ -7734,17 +6890,17 @@ public class PGraphicsOpenGL extends PGraphics {
int getNumEdgeClosures() {
int count = 0;
- for (int i = firstEdge; i <= lastEdge; i++) {
+ for (int i = 0; i < edgeCount; i++) {
if (edges[i][2] == EDGE_CLOSE) count++;
}
return count;
}
int getNumEdgeVertices(boolean bevel) {
- int segVert = lastEdge - firstEdge + 1;
+ int segVert = edgeCount;
int bevVert = 0;
if (bevel) {
- for (int i = firstEdge; i <= lastEdge; i++) {
+ for (int i = 0; i < edgeCount; i++) {
int[] edge = edges[i];
if (edge[2] == EDGE_MIDDLE || edge[2] == EDGE_START) bevVert++;
if (edge[2] == EDGE_CLOSE) segVert--;
@@ -7756,10 +6912,10 @@ public class PGraphicsOpenGL extends PGraphics {
}
int getNumEdgeIndices(boolean bevel) {
- int segInd = lastEdge - firstEdge + 1;
+ int segInd = edgeCount;
int bevInd = 0;
if (bevel) {
- for (int i = firstEdge; i <= lastEdge; i++) {
+ for (int i = 0; i < edgeCount; i++) {
int[] edge = edges[i];
if (edge[2] == EDGE_MIDDLE || edge[2] == EDGE_START) bevInd++;
if (edge[2] == EDGE_CLOSE) segInd--;
@@ -7865,10 +7021,10 @@ public class PGraphicsOpenGL extends PGraphics {
shininess = temp;
}
- void expandBreaks(int n) {
- boolean temp[] = new boolean[n];
- PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount);
- breaks = temp;
+ void expandCodes(int n) {
+ int temp[] = new int[n];
+ PApplet.arrayCopy(codes, 0, temp, 0, codeCount);
+ codes = temp;
}
void expandEdges(int n) {
@@ -7893,7 +7049,10 @@ public class PGraphicsOpenGL extends PGraphics {
trimSpecular();
trimEmissive();
trimShininess();
- trimBreaks();
+ }
+
+ if (0 < codeCount && codeCount < codes.length) {
+ trimCodes();
}
if (0 < edgeCount && edgeCount < edges.length) {
@@ -7961,10 +7120,10 @@ public class PGraphicsOpenGL extends PGraphics {
shininess = temp;
}
- void trimBreaks() {
- boolean temp[] = new boolean[vertexCount];
- PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount);
- breaks = temp;
+ void trimCodes() {
+ int temp[] = new int[codeCount];
+ PApplet.arrayCopy(codes, 0, temp, 0, codeCount);
+ codes = temp;
}
void trimEdges() {
@@ -7977,8 +7136,12 @@ public class PGraphicsOpenGL extends PGraphics {
//
// Vertices
+ int addVertex(float x, float y, boolean brk) {
+ return addVertex(x, y, VERTEX, brk);
+ }
+
int addVertex(float x, float y,
- int code) {
+ int code, boolean brk) {
return addVertex(x, y, 0,
fillColor,
normalX, normalY, normalZ,
@@ -7986,12 +7149,18 @@ public class PGraphicsOpenGL extends PGraphics {
strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor,
shininessFactor,
- code);
+ code, brk);
}
int addVertex(float x, float y,
float u, float v,
- int code) {
+ boolean brk) {
+ return addVertex(x, y, u, v, VERTEX, brk);
+ }
+
+ int addVertex(float x, float y,
+ float u, float v,
+ int code, boolean brk) {
return addVertex(x, y, 0,
fillColor,
normalX, normalY, normalZ,
@@ -7999,11 +7168,15 @@ public class PGraphicsOpenGL extends PGraphics {
strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor,
shininessFactor,
- code);
+ code, brk);
+ }
+
+ int addVertex(float x, float y, float z, boolean brk) {
+ return addVertex(x, y, z, VERTEX, brk);
}
int addVertex(float x, float y, float z,
- int code) {
+ int code, boolean brk) {
return addVertex(x, y, z,
fillColor,
normalX, normalY, normalZ,
@@ -8011,12 +7184,18 @@ public class PGraphicsOpenGL extends PGraphics {
strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor,
shininessFactor,
- code);
+ code, brk);
}
int addVertex(float x, float y, float z,
float u, float v,
- int code) {
+ boolean brk) {
+ return addVertex(x, y, z, u, v, VERTEX, brk);
+ }
+
+ int addVertex(float x, float y, float z,
+ float u, float v,
+ int code, boolean brk) {
return addVertex(x, y, z,
fillColor,
normalX, normalY, normalZ,
@@ -8024,7 +7203,7 @@ public class PGraphicsOpenGL extends PGraphics {
strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor,
shininessFactor,
- code);
+ code, brk);
}
int addVertex(float x, float y, float z,
@@ -8033,12 +7212,10 @@ public class PGraphicsOpenGL extends PGraphics {
float u, float v,
int scolor, float sweight,
int am, int sp, int em, float shine,
- int code) {
+ int code, boolean brk) {
vertexCheck();
int index;
- curveVertexCount = 0;
-
index = 3 * vertexCount;
vertices[index++] = x;
vertices[index++] = y;
@@ -8063,147 +7240,50 @@ public class PGraphicsOpenGL extends PGraphics {
emissive[vertexCount] = PGL.javaToNativeARGB(em);
shininess[vertexCount] = shine;
- breaks[vertexCount] = code == BREAK;
+ if (brk || (code == VERTEX && codes != null) ||
+ code == BEZIER_VERTEX ||
+ code == QUADRATIC_VERTEX ||
+ code == CURVE_VERTEX) {
+ if (codes == null) {
+ codes = new int[PApplet.max(PGL.DEFAULT_IN_VERTICES, vertexCount)];
+ Arrays.fill(codes, 0, vertexCount, VERTEX);
+ codeCount = vertexCount;
+ }
+
+ if (brk) {
+ codeCheck();
+ codes[codeCount] = BREAK;
+ codeCount++;
+ }
+
+ if (code != -1) {
+ codeCheck();
+ codes[codeCount] = code;
+ codeCount++;
+ }
+ }
- lastVertex = vertexCount;
vertexCount++;
- return lastVertex;
+ return vertexCount - 1;
}
- void addBezierVertex(float x2, float y2, float z2,
- float x3, float y3, float z3,
- float x4, float y4, float z4,
- boolean fill, boolean stroke, int detail, int code) {
- addBezierVertex(x2, y2, z2,
- x3, y3, z3,
- x4, y4, z4,
- fill, stroke, detail, code, POLYGON);
- }
-
- void addBezierVertex(float x2, float y2, float z2,
- float x3, float y3, float z3,
- float x4, float y4, float z4,
- boolean fill, boolean stroke, int detail, int code,
- int shape) {
- bezierInitCheck();
- bezierVertexCheck(shape, vertexCount);
-
- PMatrix3D draw = bezierDrawMatrix;
-
- float x1 = getLastVertexX();
- float y1 = getLastVertexY();
- float z1 = getLastVertexZ();
-
- float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
- float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
- float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
-
- float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
- float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
- float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
-
- float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
- float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
- float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
-
- for (int j = 0; j < detail; j++) {
- x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
- y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
- z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
- addVertex(x1, y1, z1, j == 0 && code == BREAK ? BREAK : VERTEX);
- }
+ public void addBezierVertex(float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4, boolean brk) {
+ addVertex(x2, y2, z2, BEZIER_VERTEX, brk);
+ addVertex(x3, y3, z3, -1, false);
+ addVertex(x4, y4, z4, -1, false);
}
public void addQuadraticVertex(float cx, float cy, float cz,
- float x3, float y3, float z3,
- boolean fill, boolean stroke, int detail,
- int code) {
- addQuadraticVertex(cx, cy, cz,
- x3, y3, z3,
- fill, stroke, detail, code, POLYGON);
+ float x3, float y3, float z3, boolean brk) {
+ addVertex(cx, cy, cz, QUADRATIC_VERTEX, brk);
+ addVertex(x3, y3, z3, -1, false);
}
- public void addQuadraticVertex(float cx, float cy, float cz,
- float x3, float y3, float z3,
- boolean fill, boolean stroke, int detail,
- int code, int shape) {
- float x1 = getLastVertexX();
- float y1 = getLastVertexY();
- float z1 = getLastVertexZ();
- addBezierVertex(
- x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f), z1 + ((cz-z1)*2/3.0f),
- x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f), z3 + ((cz-z3)*2/3.0f),
- x3, y3, z3,
- fill, stroke, detail, code, shape);
- }
-
- void addCurveVertex(float x, float y, float z,
- boolean fill, boolean stroke, int detail, int code) {
- addCurveVertex(x, y, z,
- fill, stroke, detail, code, POLYGON);
- }
-
- void addCurveVertex(float x, float y, float z,
- boolean fill, boolean stroke, int detail, int code,
- int shape) {
- curveVertexCheck(shape);
-
- float[] vertex = curveVertices[curveVertexCount];
- vertex[X] = x;
- vertex[Y] = y;
- vertex[Z] = z;
- curveVertexCount++;
-
- // draw a segment if there are enough points
- if (curveVertexCount > 3) {
- float[] v1 = curveVertices[curveVertexCount-4];
- float[] v2 = curveVertices[curveVertexCount-3];
- float[] v3 = curveVertices[curveVertexCount-2];
- float[] v4 = curveVertices[curveVertexCount-1];
- addCurveVertexSegment(v1[X], v1[Y], v1[Z],
- v2[X], v2[Y], v2[Z],
- v3[X], v3[Y], v3[Z],
- v4[X], v4[Y], v4[Z],
- detail, code);
- }
- }
-
- void addCurveVertexSegment(float x1, float y1, float z1,
- float x2, float y2, float z2,
- float x3, float y3, float z3,
- float x4, float y4, float z4,
- int detail, int code) {
- float x0 = x2;
- float y0 = y2;
- float z0 = z2;
-
- PMatrix3D draw = curveDrawMatrix;
-
- float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
- float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
- float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
-
- float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
- float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
- float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
-
- float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
- float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
- float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
-
- // addVertex() will reset curveVertexCount, so save it
- int savedCount = curveVertexCount;
-
- addVertex(x0, y0, z0, code == BREAK ? BREAK : VERTEX);
- for (int j = 0; j < detail; j++) {
- x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
- y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
- z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
- addVertex(x0, y0, z0, VERTEX);
- }
-
- curveVertexCount = savedCount;
+ public void addCurveVertex(float x, float y, float z, boolean brk) {
+ addVertex(x, y, z, CURVE_VERTEX, brk);
}
// Returns the vertex data in the PGraphics double array format.
@@ -8234,29 +7314,32 @@ public class PGraphicsOpenGL extends PGraphics {
vert[SA] = ((strokeColors[i] >> 24) & 0xFF) / 255.0f;
vert[SW] = strokeWeights[i];
-
- /*
- // Android doesn't have these:
- vert[AR] = ((ambient[i] >> 16) & 0xFF) / 255.0f;
- vert[AG] = ((ambient[i] >> 8) & 0xFF) / 255.0f;
- vert[AB] = ((ambient[i] >> 0) & 0xFF) / 255.0f;
-
- vert[SPR] = ((specular[i] >> 16) & 0xFF) / 255.0f;
- vert[SPG] = ((specular[i] >> 8) & 0xFF) / 255.0f;
- vert[SPB] = ((specular[i] >> 0) & 0xFF) / 255.0f;
-
- vert[ER] = ((emissive[i] >> 16) & 0xFF) / 255.0f;
- vert[EG] = ((emissive[i] >> 8) & 0xFF) / 255.0f;
- vert[EB] = ((emissive[i] >> 0) & 0xFF) / 255.0f;
-
- vert[SHINE] = shininess[i];
- */
-
}
return data;
}
+ boolean hasBezierVertex() {
+ for (int i = 0; i < codeCount; i++) {
+ if (codes[i] == BEZIER_VERTEX) return true;
+ }
+ return false;
+ }
+
+ boolean hasQuadraticVertex() {
+ for (int i = 0; i < codeCount; i++) {
+ if (codes[i] == QUADRATIC_VERTEX) return true;
+ }
+ return false;
+ }
+
+ boolean hasCurveVertex() {
+ for (int i = 0; i < codeCount; i++) {
+ if (codes[i] == CURVE_VERTEX) return true;
+ }
+ return false;
+ }
+
// -----------------------------------------------------------------
//
// Edges
@@ -8275,10 +7358,9 @@ public class PGraphicsOpenGL extends PGraphics {
// 3 = isolated edge (start, end)
edge[2] = (start ? 1 : 0) + 2 * (end ? 1 : 0);
- lastEdge = edgeCount;
edgeCount++;
- return lastEdge;
+ return edgeCount - 1;
}
int closeEdge(int i, int j) {
@@ -8287,16 +7369,15 @@ public class PGraphicsOpenGL extends PGraphics {
int[] edge = edges[edgeCount];
edge[0] = i;
edge[1] = j;
- edge[2] = -1;
+ edge[2] = EDGE_CLOSE;
- lastEdge = edgeCount;
edgeCount++;
- return lastEdge;
+ return edgeCount - 1;
}
void addTrianglesEdges() {
- for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) {
+ for (int i = 0; i < vertexCount / 3; i++) {
int i0 = 3 * i + 0;
int i1 = 3 * i + 1;
int i2 = 3 * i + 2;
@@ -8309,8 +7390,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addTriangleFanEdges() {
- for (int i = firstVertex + 1; i < lastVertex; i++) {
- int i0 = firstVertex;
+ for (int i = 1; i < vertexCount - 1; i++) {
+ int i0 = 0;
int i1 = i;
int i2 = i + 1;
@@ -8322,7 +7403,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addTriangleStripEdges() {
- for (int i = firstVertex + 1; i < lastVertex; i++) {
+ for (int i = 1; i < vertexCount - 1; i++) {
int i0 = i;
int i1, i2;
if (i % 2 == 0) {
@@ -8341,7 +7422,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addQuadsEdges() {
- for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) {
+ for (int i = 0; i < vertexCount / 4; i++) {
int i0 = 4 * i + 0;
int i1 = 4 * i + 1;
int i2 = 4 * i + 2;
@@ -8356,11 +7437,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addQuadStripEdges() {
- for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) {
- int i0 = firstVertex + 2 * (qd - 1);
- int i1 = firstVertex + 2 * (qd - 1) + 1;
- int i2 = firstVertex + 2 * qd + 1;
- int i3 = firstVertex + 2 * qd;
+ for (int qd = 1; qd < vertexCount / 2; qd++) {
+ int i0 = 2 * (qd - 1);
+ int i1 = 2 * (qd - 1) + 1;
+ int i2 = 2 * qd + 1;
+ int i3 = 2 * qd;
addEdge(i0, i1, true, false);
addEdge(i1, i2, false, false);
@@ -8370,50 +7451,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- void addPolygonEdges(boolean closed) {
- int start = firstVertex;
- boolean begin = true;
- for (int i = firstVertex + 1; i <= lastVertex; i++) {
- if (breaks[i]) {
- if (closed) {
- // Closing previous contour.
- addEdge(i - 1, start, begin, false);
- closeEdge(i - 1, start);
- }
-
- // Starting new contour.
- start = i;
- begin = true;
- } else {
- if (i == lastVertex) {
- if (closed && start + 1 < i) {
- // Closing the end of the last contour, if it
- // has more than 1 segment.
- addEdge(i - 1, i, begin, false);
- addEdge(i, start, false, false);
- closeEdge(i, start);
- } else {
- // Leaving the last contour open.
- addEdge(i - 1, i, begin, true);
- }
- } else {
-
- if (i < lastVertex && breaks[i + 1] && !closed) {
- // A new contour starts at the next vertex and
- // the polygon is not closed, so this is the last
- // segment of the current contour.
- addEdge(i - 1, i, begin, true);
- } else {
- // The current contour does not end at vertex i.
- addEdge(i - 1, i, begin, false);
- }
- }
-
- begin = false;
- }
- }
- }
-
// -----------------------------------------------------------------
//
// Normal calculation
@@ -8473,7 +7510,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void calcTrianglesNormals() {
- for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) {
+ for (int i = 0; i < vertexCount / 3; i++) {
int i0 = 3 * i + 0;
int i1 = 3 * i + 1;
int i2 = 3 * i + 2;
@@ -8483,8 +7520,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
void calcTriangleFanNormals() {
- for (int i = firstVertex + 1; i < lastVertex; i++) {
- int i0 = firstVertex;
+ for (int i = 1; i < vertexCount - 1; i++) {
+ int i0 = 0;
int i1 = i;
int i2 = i + 1;
@@ -8493,7 +7530,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void calcTriangleStripNormals() {
- for (int i = firstVertex + 1; i < lastVertex; i++) {
+ for (int i = 1; i < vertexCount - 1; i++) {
int i1 = i;
int i0, i2;
if (i % 2 == 0) {
@@ -8510,7 +7547,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void calcQuadsNormals() {
- for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) {
+ for (int i = 0; i < vertexCount / 4; i++) {
int i0 = 4 * i + 0;
int i1 = 4 * i + 1;
int i2 = 4 * i + 2;
@@ -8522,11 +7559,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
void calcQuadStripNormals() {
- for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) {
- int i0 = firstVertex + 2 * (qd - 1);
- int i1 = firstVertex + 2 * (qd - 1) + 1;
- int i2 = firstVertex + 2 * qd;
- int i3 = firstVertex + 2 * qd + 1;
+ for (int qd = 1; qd < vertexCount / 2; qd++) {
+ int i0 = 2 * (qd - 1);
+ int i1 = 2 * (qd - 1) + 1;
+ int i2 = 2 * qd;
+ int i3 = 2 * qd + 1;
calcTriangleNormal(i0, i3, i1);
calcTriangleNormal(i0, i2, i3);
@@ -8556,14 +7593,14 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addPoint(float x, float y, float z, boolean fill, boolean stroke) {
- addVertex(x, y, z, VERTEX);
+ addVertex(x, y, z, VERTEX, true);
}
void addLine(float x1, float y1, float z1,
float x2, float y2, float z2,
boolean fill, boolean stroke) {
- int idx1 = addVertex(x1, y1, z1, VERTEX);
- int idx2 = addVertex(x2, y2, z2, VERTEX);
+ int idx1 = addVertex(x1, y1, z1, VERTEX, true);
+ int idx2 = addVertex(x2, y2, z2, VERTEX, false);
if (stroke) addEdge(idx1, idx2, true, true);
}
@@ -8571,9 +7608,9 @@ public class PGraphicsOpenGL extends PGraphics {
float x2, float y2, float z2,
float x3, float y3, float z3,
boolean fill, boolean stroke) {
- int idx1 = addVertex(x1, y1, z1, VERTEX);
- int idx2 = addVertex(x2, y2, z2, VERTEX);
- int idx3 = addVertex(x3, y3, z3, VERTEX);
+ int idx1 = addVertex(x1, y1, z1, VERTEX, true);
+ int idx2 = addVertex(x2, y2, z2, VERTEX, false);
+ int idx3 = addVertex(x3, y3, z3, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8586,11 +7623,11 @@ public class PGraphicsOpenGL extends PGraphics {
float x2, float y2, float z2,
float x3, float y3, float z3,
float x4, float y4, float z4,
- boolean fill, boolean stroke) {
- int idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX);
- int idx2 = addVertex(x2, y2, z2, 1, 0, VERTEX);
- int idx3 = addVertex(x3, y3, z3, 1, 1, VERTEX);
- int idx4 = addVertex(x4, y4, z4, 0, 1, VERTEX);
+ boolean stroke) {
+ int idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true);
+ int idx2 = addVertex(x2, y2, z2, 1, 0, VERTEX, false);
+ int idx3 = addVertex(x3, y3, z3, 1, 1, VERTEX, false);
+ int idx4 = addVertex(x4, y4, z4, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8601,151 +7638,45 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addRect(float a, float b, float c, float d,
- boolean fill, boolean stroke, int rectMode) {
- float hradius, vradius;
- switch (rectMode) {
- case CORNERS:
- break;
- case CORNER:
- c += a; d += b;
- break;
- case RADIUS:
- hradius = c;
- vradius = d;
- c = a + hradius;
- d = b + vradius;
- a -= hradius;
- b -= vradius;
- break;
- case CENTER:
- hradius = c / 2.0f;
- vradius = d / 2.0f;
- c = a + hradius;
- d = b + vradius;
- a -= hradius;
- b -= vradius;
- }
-
- if (a > c) {
- float temp = a; a = c; c = temp;
- }
-
- if (b > d) {
- float temp = b; b = d; d = temp;
- }
-
+ boolean stroke) {
addQuad(a, b, 0,
c, b, 0,
c, d, 0,
a, d, 0,
- fill, stroke);
+ stroke);
}
void addRect(float a, float b, float c, float d,
float tl, float tr, float br, float bl,
- boolean fill, boolean stroke, int detail, int rectMode) {
- float hradius, vradius;
- switch (rectMode) {
- case CORNERS:
- break;
- case CORNER:
- c += a; d += b;
- break;
- case RADIUS:
- hradius = c;
- vradius = d;
- c = a + hradius;
- d = b + vradius;
- a -= hradius;
- b -= vradius;
- break;
- case CENTER:
- hradius = c / 2.0f;
- vradius = d / 2.0f;
- c = a + hradius;
- d = b + vradius;
- a -= hradius;
- b -= vradius;
- }
-
- if (a > c) {
- float temp = a; a = c; c = temp;
- }
-
- if (b > d) {
- float temp = b; b = d; d = temp;
- }
-
- float maxRounding = PApplet.min((c - a) / 2, (d - b) / 2);
- if (tl > maxRounding) tl = maxRounding;
- if (tr > maxRounding) tr = maxRounding;
- if (br > maxRounding) br = maxRounding;
- if (bl > maxRounding) bl = maxRounding;
-
+ boolean stroke) {
if (nonZero(tr)) {
- addVertex(c-tr, b, VERTEX);
- addQuadraticVertex(c, b, 0, c, b+tr, 0,
- fill, stroke, detail, VERTEX);
+ addVertex(c-tr, b, VERTEX, true);
+ addQuadraticVertex(c, b, 0, c, b+tr, 0, false);
} else {
- addVertex(c, b, VERTEX);
+ addVertex(c, b, VERTEX, true);
}
if (nonZero(br)) {
- addVertex(c, d-br, VERTEX);
- addQuadraticVertex(c, d, 0, c-br, d, 0,
- fill, stroke, detail, VERTEX);
+ addVertex(c, d-br, VERTEX, false);
+ addQuadraticVertex(c, d, 0, c-br, d, 0, false);
} else {
- addVertex(c, d, VERTEX);
+ addVertex(c, d, VERTEX, false);
}
if (nonZero(bl)) {
- addVertex(a+bl, d, VERTEX);
- addQuadraticVertex(a, d, 0, a, d-bl, 0,
- fill, stroke, detail, VERTEX);
+ addVertex(a+bl, d, VERTEX, false);
+ addQuadraticVertex(a, d, 0, a, d-bl, 0, false);
} else {
- addVertex(a, d, VERTEX);
+ addVertex(a, d, VERTEX, false);
}
if (nonZero(tl)) {
- addVertex(a, b+tl, VERTEX);
- addQuadraticVertex(a, b, 0, a+tl, b, 0,
- fill, stroke, detail, VERTEX);
+ addVertex(a, b+tl, VERTEX, false);
+ addQuadraticVertex(a, b, 0, a+tl, b, 0, false);
} else {
- addVertex(a, b, VERTEX);
+ addVertex(a, b, VERTEX, false);
}
-
- if (stroke) addPolygonEdges(true);
}
- void addEllipse(float a, float b, float c, float d,
- boolean fill, boolean stroke, int ellipseMode) {
- float x = a;
- float y = b;
- float w = c;
- float h = d;
-
- if (ellipseMode == CORNERS) {
- w = c - a;
- h = d - b;
-
- } else if (ellipseMode == RADIUS) {
- x = a - c;
- y = b - d;
- w = c * 2;
- h = d * 2;
-
- } else if (ellipseMode == DIAMETER) {
- x = a - c/2f;
- y = b - d/2f;
- }
-
- if (w < 0) { // undo negative width
- x += w;
- w = -w;
- }
-
- if (h < 0) { // undo negative height
- y += h;
- h = -h;
- }
-
+ void addEllipse(float x, float y, float w, float h,
+ boolean fill, boolean stroke) {
float radiusH = w / 2;
float radiusV = h / 2;
@@ -8753,19 +7684,19 @@ public class PGraphicsOpenGL extends PGraphics {
float centerY = y + radiusV;
// should call screenX/Y using current renderer.
- float sx1 = pgCurrent.screenX(x, y);
- float sy1 = pgCurrent.screenY(x, y);
- float sx2 = pgCurrent.screenX(x + w, y + h);
- float sy2 = pgCurrent.screenY(x + w, y + h);
+ float sx1 = pg.screenX(x, y);
+ float sy1 = pg.screenY(x, y);
+ float sx2 = pg.screenX(x + w, y + h);
+ float sy2 = pg.screenY(x + w, y + h);
int accuracy =
- PApplet.max(MIN_POINT_ACCURACY,
+ PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY,
(int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) /
- POINT_ACCURACY_FACTOR));
+ POINT_ACCURACY_FACTOR)));
float inc = (float) SINCOS_LENGTH / accuracy;
if (fill) {
- addVertex(centerX, centerY, VERTEX);
+ addVertex(centerX, centerY, VERTEX, true);
}
int idx0, pidx, idx;
idx0 = pidx = idx = 0;
@@ -8773,7 +7704,7 @@ public class PGraphicsOpenGL extends PGraphics {
for (int i = 0; i < accuracy; i++) {
idx = addVertex(centerX + cosLUT[(int) val] * radiusH,
centerY + sinLUT[(int) val] * radiusV,
- VERTEX);
+ VERTEX, i == 0 && !fill);
val = (val + inc) % SINCOS_LENGTH;
if (0 < i) {
@@ -8787,7 +7718,7 @@ public class PGraphicsOpenGL extends PGraphics {
// Back to the beginning
addVertex(centerX + cosLUT[0] * radiusH,
centerY + sinLUT[0] * radiusV,
- VERTEX);
+ VERTEX, false);
if (stroke) {
addEdge(idx, idx0, false, false);
closeEdge(idx, idx0);
@@ -8808,7 +7739,7 @@ public class PGraphicsOpenGL extends PGraphics {
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
if (fill) {
- addVertex(centerX, centerY, VERTEX);
+ addVertex(centerX, centerY, VERTEX, true);
}
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
@@ -8820,7 +7751,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (ii < 0) ii += SINCOS_LENGTH;
idx = addVertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr,
- VERTEX);
+ VERTEX, i == startLUT && !fill);
if (stroke) {
if (arcMode == PIE) {
@@ -8837,7 +7768,7 @@ public class PGraphicsOpenGL extends PGraphics {
// draw last point explicitly for accuracy
idx = addVertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr,
centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr,
- VERTEX);
+ VERTEX, false);
if (stroke) {
if (arcMode == PIE) {
addEdge(idx, idx0, false, false);
@@ -8852,7 +7783,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (ii < 0) ii += SINCOS_LENGTH;
idx = addVertex(centerX + cosLUT[ii] * hr,
centerY + sinLUT[ii] * vr,
- VERTEX);
+ VERTEX, false);
if (stroke && arcMode == CHORD) {
addEdge(pidx, idx, false, true);
}
@@ -8867,12 +7798,12 @@ public class PGraphicsOpenGL extends PGraphics {
int idx1 = 0, idx2 = 0, idx3 = 0, idx4 = 0;
if (fill || stroke) {
- // front face
- setNormal(0, 0, 1);
- idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX);
- idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX);
- idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX);
- idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX);
+ // back face
+ setNormal(0, 0, -1);
+ idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true);
+ idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX, false);
+ idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX, false);
+ idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8881,12 +7812,12 @@ public class PGraphicsOpenGL extends PGraphics {
closeEdge(idx4, idx1);
}
- // back face
- setNormal(0, 0, -1);
- idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX);
- idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX);
- idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX);
- idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX);
+ // front face
+ setNormal(0, 0, 1);
+ idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX, false);
+ idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX, false);
+ idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX, false);
+ idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8897,10 +7828,10 @@ public class PGraphicsOpenGL extends PGraphics {
// right face
setNormal(1, 0, 0);
- idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX);
- idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX);
- idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX);
- idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX);
+ idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX, false);
+ idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false);
+ idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false);
+ idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8911,24 +7842,10 @@ public class PGraphicsOpenGL extends PGraphics {
// left face
setNormal(-1, 0, 0);
- idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX);
- idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX);
- idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX);
- idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX);
- if (stroke) {
- addEdge(idx1, idx2, true, false);
- addEdge(idx2, idx3, false, false);
- addEdge(idx3, idx4, false, false);
- addEdge(idx4, idx1, false, false);
- closeEdge(idx4, idx1);
- }
-
- // top face
- setNormal(0, 1, 0);
- idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX);
- idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX);
- idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX);
- idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX);
+ idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false);
+ idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX, false);
+ idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX, false);
+ idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8939,10 +7856,24 @@ public class PGraphicsOpenGL extends PGraphics {
// bottom face
setNormal(0, -1, 0);
- idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX);
- idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX);
- idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX);
- idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX);
+ idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false);
+ idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false);
+ idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX, false);
+ idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false);
+ if (stroke) {
+ addEdge(idx1, idx2, true, false);
+ addEdge(idx2, idx3, false, false);
+ addEdge(idx3, idx4, false, false);
+ addEdge(idx4, idx1, false, false);
+ closeEdge(idx4, idx1);
+ }
+
+ // top face
+ setNormal(0, 1, 0);
+ idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX, false);
+ idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX, false);
+ idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false);
+ idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false);
if (stroke) {
addEdge(idx1, idx2, true, false);
addEdge(idx2, idx3, false, false);
@@ -8957,13 +7888,6 @@ public class PGraphicsOpenGL extends PGraphics {
// any vertex or edge.
int[] addSphere(float r, int detailU, int detailV,
boolean fill, boolean stroke) {
- if ((detailU < 3) || (detailV < 2)) {
- sphereDetail(30);
- detailU = detailV = 30;
- } else {
- sphereDetail(detailU, detailV);
- }
-
int nind = 3 * detailU + (6 * detailU + 3) * (detailV - 2) + 3 * detailU;
int[] indices = new int[nind];
@@ -8983,21 +7907,23 @@ public class PGraphicsOpenGL extends PGraphics {
u = 1; v = 1;
for (int i = 0; i < detailU; i++) {
setNormal(0, 1, 0);
- addVertex(0, r, 0, u , v, VERTEX);
+ addVertex(0, r, 0, u , v, VERTEX, true);
u -= du;
}
vertCount = detailU;
vert0 = vertCount;
u = 1; v -= dv;
for (int i = 0; i < detailU; i++) {
- setNormal(sphereX[i], sphereY[i], sphereZ[i]);
- addVertex(r * sphereX[i], r *sphereY[i], r * sphereZ[i], u , v, VERTEX);
+ setNormal(pg.sphereX[i], pg.sphereY[i], pg.sphereZ[i]);
+ addVertex(r*pg.sphereX[i], r*pg.sphereY[i], r*pg.sphereZ[i], u , v,
+ VERTEX, false);
u -= du;
}
vertCount += detailU;
vert1 = vertCount;
- setNormal(sphereX[0], sphereY[0], sphereZ[0]);
- addVertex(r * sphereX[0], r * sphereY[0], r * sphereZ[0], u, v, VERTEX);
+ setNormal(pg.sphereX[0], pg.sphereY[0], pg.sphereZ[0]);
+ addVertex(r*pg.sphereX[0], r*pg.sphereY[0], r*pg.sphereZ[0], u, v,
+ VERTEX, false);
vertCount++;
for (int i = 0; i < detailU; i++) {
@@ -9022,16 +7948,16 @@ public class PGraphicsOpenGL extends PGraphics {
u = 1; v -= dv;
for (int i = 0; i < detailU; i++) {
int ioff = offset + i;
- setNormal(sphereX[ioff], sphereY[ioff], sphereZ[ioff]);
- addVertex(r * sphereX[ioff], r *sphereY[ioff], r * sphereZ[ioff],
- u , v, VERTEX);
+ setNormal(pg.sphereX[ioff], pg.sphereY[ioff], pg.sphereZ[ioff]);
+ addVertex(r*pg.sphereX[ioff], r*pg.sphereY[ioff], r*pg.sphereZ[ioff],
+ u , v, VERTEX, false);
u -= du;
}
vertCount += detailU;
vert1 = vertCount;
- setNormal(sphereX[offset], sphereY[offset], sphereZ[offset]);
- addVertex(r * sphereX[offset], r * sphereY[offset], r * sphereZ[offset],
- u, v, VERTEX);
+ setNormal(pg.sphereX[offset], pg.sphereY[offset], pg.sphereZ[offset]);
+ addVertex(r*pg.sphereX[offset], r*pg.sphereY[offset], r*pg.sphereZ[offset],
+ u, v, VERTEX, false);
vertCount++;
for (int i = 0; i < detailU; i++) {
@@ -9068,7 +7994,7 @@ public class PGraphicsOpenGL extends PGraphics {
u = 1; v = 0;
for (int i = 0; i < detailU; i++) {
setNormal(0, -1, 0);
- addVertex(0, -r, 0, u , v, VERTEX);
+ addVertex(0, -r, 0, u , v, VERTEX, false);
u -= du;
}
vertCount += detailU;
@@ -9092,8 +8018,9 @@ public class PGraphicsOpenGL extends PGraphics {
// Holds tessellated data for polygon, line and point geometry.
- protected class TessGeometry {
+ static protected class TessGeometry {
int renderMode;
+ PGraphicsOpenGL pg;
// Tessellated polygon data
int polyVertexCount;
@@ -9164,7 +8091,8 @@ public class PGraphicsOpenGL extends PGraphics {
float[] pointOffsets;
short[] pointIndices;
- TessGeometry(int mode) {
+ TessGeometry(PGraphicsOpenGL pg, int mode) {
+ this.pg = pg;
renderMode = mode;
allocate();
}
@@ -9966,8 +8894,8 @@ public class PGraphicsOpenGL extends PGraphics {
float y = in.vertices[index++];
float z = in.vertices[index ];
- if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) {
- PMatrix3D mm = modelview;
+ if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) {
+ PMatrix3D mm = pg.modelview;
index = 4 * tessIdx;
pointVertices[index++] = x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03;
@@ -9989,16 +8917,16 @@ public class PGraphicsOpenGL extends PGraphics {
//
// Add line geometry
- void setLineVertex(int tessIdx, InGeometry in, int inIdx0, int rgba) {
+ void setLineVertex(int tessIdx, float[] vertices, int inIdx0, int rgba) {
int index;
index = 3 * inIdx0;
- float x0 = in.vertices[index++];
- float y0 = in.vertices[index++];
- float z0 = in.vertices[index ];
+ float x0 = vertices[index++];
+ float y0 = vertices[index++];
+ float z0 = vertices[index ];
- if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) {
- PMatrix3D mm = modelview;
+ if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) {
+ PMatrix3D mm = pg.modelview;
index = 4 * tessIdx;
lineVertices[index++] = x0*mm.m00 + y0*mm.m01 + z0*mm.m02 + mm.m03;
@@ -10022,27 +8950,27 @@ public class PGraphicsOpenGL extends PGraphics {
}
// Sets line vertex with index tessIdx using the data from input vertices
- //inIdx0 and inIdx1.
- void setLineVertex(int tessIdx, InGeometry in, int inIdx0, int inIdx1,
+ // inIdx0 and inIdx1.
+ void setLineVertex(int tessIdx, float[] vertices, int inIdx0, int inIdx1,
int rgba, float weight) {
int index;
index = 3 * inIdx0;
- float x0 = in.vertices[index++];
- float y0 = in.vertices[index++];
- float z0 = in.vertices[index ];
+ float x0 = vertices[index++];
+ float y0 = vertices[index++];
+ float z0 = vertices[index ];
index = 3 * inIdx1;
- float x1 = in.vertices[index++];
- float y1 = in.vertices[index++];
- float z1 = in.vertices[index ];
+ float x1 = vertices[index++];
+ float y1 = vertices[index++];
+ float z1 = vertices[index ];
float dx = x1 - x0;
float dy = y1 - y0;
float dz = z1 - z0;
- if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) {
- PMatrix3D mm = modelview;
+ if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) {
+ PMatrix3D mm = pg.modelview;
index = 4 * tessIdx;
lineVertices[index++] = x0*mm.m00 + y0*mm.m01 + z0*mm.m02 + mm.m03;
@@ -10107,9 +9035,9 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampXY) {
int index;
- if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) {
- PMatrix3D mm = modelview;
- PMatrix3D nm = modelviewInv;
+ if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) {
+ PMatrix3D mm = pg.modelview;
+ PMatrix3D nm = pg.modelviewInv;
index = 4 * tessIdx;
if (clampXY) {
@@ -10155,7 +9083,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void addPolyVertices(InGeometry in, boolean clampXY) {
- addPolyVertices(in, in.firstVertex, in.lastVertex, clampXY);
+ addPolyVertices(in, 0, in.vertexCount - 1, clampXY);
}
void addPolyVertex(InGeometry in, int i, boolean clampXY) {
@@ -10168,9 +9096,9 @@ public class PGraphicsOpenGL extends PGraphics {
polyVertexCheck(nvert);
- if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) {
- PMatrix3D mm = modelview;
- PMatrix3D nm = modelviewInv;
+ if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) {
+ PMatrix3D mm = pg.modelview;
+ PMatrix3D nm = pg.modelviewInv;
for (int i = 0; i < nvert; i++) {
int inIdx = i0 + i;
@@ -10464,8 +9392,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
// Generates tessellated geometry given a batch of input vertices.
- // Generates tessellated geometry given a batch of input vertices.
- protected class Tessellator {
+ static protected class Tessellator {
InGeometry in;
TessGeometry tess;
TexCache texCache;
@@ -10488,6 +9415,7 @@ public class PGraphicsOpenGL extends PGraphics {
PMatrix transform;
float transformScale;
boolean is2D, is3D;
+ protected PGraphicsOpenGL pg;
int[] rawIndices;
int rawSize;
@@ -10501,6 +9429,21 @@ public class PGraphicsOpenGL extends PGraphics {
int firstPointIndexCache;
int lastPointIndexCache;
+ // Accessor arrays to get the geometry data needed to tessellate the
+ // strokes, it can point to either the input geometry, or the internal
+ // path vertices generated in the polygon discretization.
+ float[] strokeVertices;
+ int[] strokeColors;
+ float[] strokeWeights;
+
+ // Path vertex data that results from discretizing a polygon (i.e.: turning
+ // bezier, quadratic, and curve vertices into "regular" vertices).
+ int pathVertexCount;
+ float[] pathVertices;
+ int[] pathColors;
+ float[] pathWeights;
+ int beginPath;
+
public Tessellator() {
callback = new TessellatorCallback();
gluTess = pgl.createTessellator(callback);
@@ -10530,6 +9473,13 @@ public class PGraphicsOpenGL extends PGraphics {
this.fill = fill;
}
+ void setTexCache(TexCache texCache, PImage prevTexImage,
+ PImage newTexImage) {
+ this.texCache = texCache;
+ this.prevTexImage = prevTexImage;
+ this.newTexImage = newTexImage;
+ }
+
void setStroke(boolean stroke) {
this.stroke = stroke;
}
@@ -10542,23 +9492,20 @@ public class PGraphicsOpenGL extends PGraphics {
this.strokeWeight = weight;
}
- void setStrokeJoin(int strokeJoin) {
- this.strokeJoin = strokeJoin;
- }
-
void setStrokeCap(int strokeCap) {
this.strokeCap = strokeCap;
}
+ void setStrokeJoin(int strokeJoin) {
+ this.strokeJoin = strokeJoin;
+ }
+
void setAccurate2DStrokes(boolean accurate) {
this.accurate2DStrokes = accurate;
}
- void setTexCache(TexCache texCache, PImage prevTexImage,
- PImage newTexImage) {
- this.texCache = texCache;
- this.prevTexImage = prevTexImage;
- this.newTexImage = newTexImage;
+ protected void setRenderer(PGraphicsOpenGL pg) {
+ this.pg = pg;
}
void set3D(boolean value) {
@@ -10576,6 +9523,10 @@ public class PGraphicsOpenGL extends PGraphics {
transformScale = -1;
}
+ void resetCurveVertexCount() {
+ pg.curveVertexCount = 0;
+ }
+
// -----------------------------------------------------------------
//
// Point tessellation
@@ -10589,15 +9540,15 @@ public class PGraphicsOpenGL extends PGraphics {
}
void tessellateRoundPoints() {
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (stroke && 1 <= nInVert) {
// Each point generates a separate triangle fan.
// The number of triangles of each fan depends on the
// stroke weight of the point.
int nPtVert =
- PApplet.max(MIN_POINT_ACCURACY,
+ PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY,
(int) (TWO_PI * strokeWeight /
- POINT_ACCURACY_FACTOR)) + 1;
+ POINT_ACCURACY_FACTOR))) + 1;
if (PGL.MAX_VERTEX_INDEX1 <= nPtVert) {
throw new RuntimeException("Error in point tessellation.");
}
@@ -10624,7 +9575,7 @@ public class PGraphicsOpenGL extends PGraphics {
IndexCache cache = tess.pointIndexCache;
int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast();
firstPointIndexCache = index;
- for (int i = in.firstVertex; i <= in.lastVertex; i++) {
+ for (int i = 0; i < in.vertexCount; i++) {
// Creating the triangle fan for each input vertex.
int count = cache.vertexCount[index];
@@ -10684,7 +9635,7 @@ public class PGraphicsOpenGL extends PGraphics {
IndexCache cache = tess.polyIndexCache;
int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast();
firstPointIndexCache = index;
- for (int i = in.firstVertex; i <= in.lastVertex; i++) {
+ for (int i = 0; i < in.vertexCount; i++) {
int count = cache.vertexCount[index];
if (PGL.MAX_VERTEX_INDEX1 <= count + nPtVert) {
// We need to start a new index block for this point.
@@ -10727,7 +9678,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void tessellateSquarePoints() {
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (stroke && 1 <= nInVert) {
updateTex();
int quadCount = nInVert; // Each point generates a separate quad.
@@ -10757,7 +9708,7 @@ public class PGraphicsOpenGL extends PGraphics {
IndexCache cache = tess.pointIndexCache;
int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast();
firstPointIndexCache = index;
- for (int i = in.firstVertex; i <= in.lastVertex; i++) {
+ for (int i = 0; i < in.vertexCount; i++) {
int nvert = 5;
int count = cache.vertexCount[index];
if (PGL.MAX_VERTEX_INDEX1 <= count + nvert) {
@@ -10812,7 +9763,7 @@ public class PGraphicsOpenGL extends PGraphics {
IndexCache cache = tess.polyIndexCache;
int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast();
firstPointIndexCache = index;
- for (int i = in.firstVertex; i <= in.lastVertex; i++) {
+ for (int i = 0; i < in.vertexCount; i++) {
int nvert = 5;
int count = cache.vertexCount[index];
if (PGL.MAX_VERTEX_INDEX1 <= count + nvert) {
@@ -10852,7 +9803,7 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clamp2D() {
return is2D && tess.renderMode == IMMEDIATE &&
- zero(modelview.m01) && zero(modelview.m10);
+ zero(pg.modelview.m01) && zero(pg.modelview.m10);
}
boolean clampSquarePoints2D() {
@@ -10864,8 +9815,11 @@ public class PGraphicsOpenGL extends PGraphics {
// Line tessellation
void tessellateLines() {
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (stroke && 2 <= nInVert) {
+ strokeVertices = in.vertices;
+ strokeColors = in.strokeColors;
+ strokeWeights = in.strokeWeights;
updateTex();
int lineCount = nInVert / 2; // Each individual line is formed by two consecutive input vertices.
if (is3D) {
@@ -10885,15 +9839,14 @@ public class PGraphicsOpenGL extends PGraphics {
// require 3 indices to specify their connectivities.
int nind = lineCount * 2 * 3;
- int first = in.firstVertex;
tess.lineVertexCheck(nvert);
tess.lineIndexCheck(nind);
int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() :
tess.lineIndexCache.getLast();
firstLineIndexCache = index;
for (int ln = 0; ln < lineCount; ln++) {
- int i0 = first + 2 * ln + 0;
- int i1 = first + 2 * ln + 1;
+ int i0 = 2 * ln + 0;
+ int i1 = 2 * ln + 1;
index = addLineSegment3D(i0, i1, index, null, false);
}
lastLineIndexCache = index;
@@ -10903,7 +9856,6 @@ public class PGraphicsOpenGL extends PGraphics {
int nvert = lineCount * 4;
int nind = lineCount * 2 * 3;
- int first = in.firstVertex;
if (noCapsJoins(nvert)) {
tess.polyVertexCheck(nvert);
tess.polyIndexCheck(nind);
@@ -10913,16 +9865,16 @@ public class PGraphicsOpenGL extends PGraphics {
if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index.
boolean clamp = clampLines2D(lineCount);
for (int ln = 0; ln < lineCount; ln++) {
- int i0 = first + 2 * ln + 0;
- int i1 = first + 2 * ln + 1;
+ int i0 = 2 * ln + 0;
+ int i1 = 2 * ln + 1;
index = addLineSegment2D(i0, i1, index, false, clamp);
}
lastLineIndexCache = lastPolyIndexCache = index;
} else { // full stroking algorithm
LinePath path = new LinePath(LinePath.WIND_NON_ZERO);
for (int ln = 0; ln < lineCount; ln++) {
- int i0 = first + 2 * ln + 0;
- int i1 = first + 2 * ln + 1;
+ int i0 = 2 * ln + 0;
+ int i1 = 2 * ln + 1;
path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1],
in.strokeColors[i0]);
path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
@@ -10935,10 +9887,9 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampLines2D(int lineCount) {
boolean res = clamp2D();
if (res) {
- int first = in.firstVertex;
for (int ln = 0; ln < lineCount; ln++) {
- int i0 = first + 2 * ln + 0;
- int i1 = first + 2 * ln + 1;
+ int i0 = 2 * ln + 0;
+ int i1 = 2 * ln + 1;
res = segmentIsAxisAligned(i0, i1);
if (!res) break;
}
@@ -10947,8 +9898,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
void tessellateLineStrip() {
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (stroke && 2 <= nInVert) {
+ strokeVertices = in.vertices;
+ strokeColors = in.strokeColors;
+ strokeWeights = in.strokeWeights;
updateTex();
int lineCount = nInVert - 1;
if (is3D) {
@@ -10971,10 +9925,10 @@ public class PGraphicsOpenGL extends PGraphics {
int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() :
tess.lineIndexCache.getLast();
firstLineIndexCache = index;
- int i0 = in.firstVertex;
+ int i0 = 0;
short[] lastInd = {-1, -1};
for (int ln = 0; ln < lineCount; ln++) {
- int i1 = in.firstVertex + ln + 1;
+ int i1 = ln + 1;
if (0 < nBevelTr) {
index = addLineSegment3D(i0, i1, index, lastInd, false);
} else {
@@ -10996,21 +9950,19 @@ public class PGraphicsOpenGL extends PGraphics {
tess.polyIndexCache.getLast();
firstLineIndexCache = index;
if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index.
- int i0 = in.firstVertex;
+ int i0 = 0;
boolean clamp = clampLineStrip2D(lineCount);
for (int ln = 0; ln < lineCount; ln++) {
- int i1 = in.firstVertex + ln + 1;
+ int i1 = ln + 1;
index = addLineSegment2D(i0, i1, index, false, clamp);
i0 = i1;
}
lastLineIndexCache = lastPolyIndexCache = index;
} else { // full stroking algorithm
- int first = in.firstVertex;
LinePath path = new LinePath(LinePath.WIND_NON_ZERO);
- path.moveTo(in.vertices[3 * first + 0], in.vertices[3 * first + 1],
- in.strokeColors[first]);
+ path.moveTo(in.vertices[0], in.vertices[1], in.strokeColors[0]);
for (int ln = 0; ln < lineCount; ln++) {
- int i1 = first + ln + 1;
+ int i1 = ln + 1;
path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
in.strokeColors[i1]);
}
@@ -11021,10 +9973,8 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampLineStrip2D(int lineCount) {
boolean res = clamp2D();
if (res) {
- int i0 = in.firstVertex;
for (int ln = 0; ln < lineCount; ln++) {
- int i1 = in.firstVertex + ln + 1;
- res = segmentIsAxisAligned(i0, i1);
+ res = segmentIsAxisAligned(0, ln + 1);
if (!res) break;
}
}
@@ -11032,8 +9982,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
void tessellateLineLoop() {
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (stroke && 2 <= nInVert) {
+ strokeVertices = in.vertices;
+ strokeColors = in.strokeColors;
+ strokeWeights = in.strokeWeights;
updateTex();
int lineCount = nInVert;
if (is3D) {
@@ -11056,11 +10009,11 @@ public class PGraphicsOpenGL extends PGraphics {
int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() :
tess.lineIndexCache.getLast();
firstLineIndexCache = index;
- int i0 = in.firstVertex;
+ int i0 = 0;
short[] lastInd = {-1, -1};
short firstInd = -1;
for (int ln = 0; ln < lineCount - 1; ln++) {
- int i1 = in.firstVertex + ln + 1;
+ int i1 = ln + 1;
if (0 < nBevelTr) {
index = addLineSegment3D(i0, i1, index, lastInd, false);
if (ln == 0) firstInd = (short)(lastInd[0] - 2);
@@ -11069,10 +10022,9 @@ public class PGraphicsOpenGL extends PGraphics {
}
i0 = i1;
}
- index = addLineSegment3D(in.lastVertex, in.firstVertex, index, lastInd,
- false);
+ index = addLineSegment3D(0, in.vertexCount - 1, index, lastInd, false);
if (0 < nBevelTr) {
- index = addBevel3D(in.firstVertex, index, lastInd, firstInd, false);
+ index = addBevel3D(0, index, lastInd, firstInd, false);
}
lastLineIndexCache = index;
}
@@ -11088,23 +10040,20 @@ public class PGraphicsOpenGL extends PGraphics {
tess.polyIndexCache.getLast();
firstLineIndexCache = index;
if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index.
- int i0 = in.firstVertex;
+ int i0 = 0;
boolean clamp = clampLineLoop2D(lineCount);
for (int ln = 0; ln < lineCount - 1; ln++) {
- int i1 = in.firstVertex + ln + 1;
+ int i1 = ln + 1;
index = addLineSegment2D(i0, i1, index, false, clamp);
i0 = i1;
}
- index = addLineSegment2D(in.lastVertex, in.firstVertex, index, false,
- clamp);
+ index = addLineSegment2D(0, in.vertexCount - 1, index, false, clamp);
lastLineIndexCache = lastPolyIndexCache = index;
} else { // full stroking algorithm
- int first = in.firstVertex;
LinePath path = new LinePath(LinePath.WIND_NON_ZERO);
- path.moveTo(in.vertices[3 * first + 0], in.vertices[3 * first + 1],
- in.strokeColors[first]);
+ path.moveTo(in.vertices[0], in.vertices[1], in.strokeColors[0]);
for (int ln = 0; ln < lineCount - 1; ln++) {
- int i1 = first + ln + 1;
+ int i1 = ln + 1;
path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
in.strokeColors[i1]);
}
@@ -11116,10 +10065,8 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampLineLoop2D(int lineCount) {
boolean res = clamp2D();
if (res) {
- int i0 = in.firstVertex;
for (int ln = 0; ln < lineCount; ln++) {
- int i1 = in.firstVertex + ln + 1;
- res = segmentIsAxisAligned(i0, i1);
+ res = segmentIsAxisAligned(0, ln + 1);
if (!res) break;
}
}
@@ -11129,6 +10076,9 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateEdges() {
if (stroke) {
if (in.edgeCount == 0) return;
+ strokeVertices = in.vertices;
+ strokeColors = in.strokeColors;
+ strokeWeights = in.strokeWeights;
if (is3D) {
tessellateEdges3D();
} else if (is2D) {
@@ -11151,7 +10101,7 @@ public class PGraphicsOpenGL extends PGraphics {
firstLineIndexCache = index;
short[] lastInd = {-1, -1};
short firstInd = -1;
- for (int i = in.firstEdge; i <= in.lastEdge; i++) {
+ for (int i = 0; i <= in.edgeCount - 1; i++) {
int[] edge = in.edges[i];
int i0 = edge[0];
int i1 = edge[1];
@@ -11185,7 +10135,7 @@ public class PGraphicsOpenGL extends PGraphics {
firstLineIndexCache = index;
if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index.
boolean clamp = clampEdges2D();
- for (int i = in.firstEdge; i <= in.lastEdge; i++) {
+ for (int i = 0; i <= in.edgeCount - 1; i++) {
int[] edge = in.edges[i];
if (edge[2] == EDGE_CLOSE) continue; // ignoring edge closures when not doing caps or joins.
int i0 = edge[0];
@@ -11195,34 +10145,34 @@ public class PGraphicsOpenGL extends PGraphics {
lastLineIndexCache = lastPolyIndexCache = index;
} else { // full stroking algorithm
LinePath path = new LinePath(LinePath.WIND_NON_ZERO);
- for (int i = in.firstEdge; i <= in.lastEdge; i++) {
+ for (int i = 0; i <= in.edgeCount - 1; i++) {
int[] edge = in.edges[i];
int i0 = edge[0];
int i1 = edge[1];
switch (edge[2]) {
case EDGE_MIDDLE:
- path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
+ path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
break;
case EDGE_START:
- path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1],
- in.strokeColors[i0]);
- path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
+ path.moveTo(strokeVertices[3 * i0 + 0], strokeVertices[3 * i0 + 1],
+ strokeColors[i0]);
+ path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
break;
case EDGE_STOP:
- path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
- path.moveTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
+ path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
+ path.moveTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
break;
case EDGE_SINGLE:
- path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1],
- in.strokeColors[i0]);
- path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
- path.moveTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1],
- in.strokeColors[i1]);
+ path.moveTo(strokeVertices[3 * i0 + 0], strokeVertices[3 * i0 + 1],
+ strokeColors[i0]);
+ path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
+ path.moveTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1],
+ strokeColors[i1]);
break;
case EDGE_CLOSE:
path.closePath();
@@ -11236,12 +10186,12 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampEdges2D() {
boolean res = clamp2D();
if (res) {
- for (int i = in.firstEdge; i <= in.lastEdge; i++) {
+ for (int i = 0; i <= in.edgeCount - 1; i++) {
int[] edge = in.edges[i];
if (edge[2] == EDGE_CLOSE) continue;
int i0 = edge[0];
int i1 = edge[1];
- res = segmentIsAxisAligned(i0, i1);
+ res = segmentIsAxisAligned(strokeVertices, i0, i1);
if (!res) break;
}
}
@@ -11251,7 +10201,7 @@ public class PGraphicsOpenGL extends PGraphics {
// Adding the data that defines a quad starting at vertex i0 and
// ending at i1.
int addLineSegment3D(int i0, int i1, int index, short[] lastInd,
- boolean constStroke) {
+ boolean constStroke) {
IndexCache cache = tess.lineIndexCache;
int count = cache.vertexCount[index];
boolean addBevel = lastInd != null && -1 < lastInd[0] && -1 < lastInd[1];
@@ -11267,26 +10217,28 @@ public class PGraphicsOpenGL extends PGraphics {
int color, color0;
float weight;
- color0 = color = constStroke ? strokeColor : in.strokeColors[i0];
- weight = constStroke ? strokeWeight : in.strokeWeights[i0];
+ color0 = color = constStroke ? strokeColor : strokeColors[i0];
+ weight = constStroke ? strokeWeight : strokeWeights[i0];
+ weight *= transformScale();
- tess.setLineVertex(vidx++, in, i0, i1, color, +weight/2);
+ tess.setLineVertex(vidx++, strokeVertices, i0, i1, color, +weight/2);
tess.lineIndices[iidx++] = (short) (count + 0);
- tess.setLineVertex(vidx++, in, i0, i1, color, -weight/2);
+ tess.setLineVertex(vidx++, strokeVertices, i0, i1, color, -weight/2);
tess.lineIndices[iidx++] = (short) (count + 1);
- color = constStroke ? strokeColor : in.strokeColors[i1];
- weight = constStroke ? strokeWeight : in.strokeWeights[i1];
+ color = constStroke ? strokeColor : strokeColors[i1];
+ weight = constStroke ? strokeWeight : strokeWeights[i1];
+ weight *= transformScale();
- tess.setLineVertex(vidx++, in, i1, i0, color, -weight/2);
+ tess.setLineVertex(vidx++, strokeVertices, i1, i0, color, -weight/2);
tess.lineIndices[iidx++] = (short) (count + 2);
// Starting a new triangle re-using prev vertices.
tess.lineIndices[iidx++] = (short) (count + 2);
tess.lineIndices[iidx++] = (short) (count + 1);
- tess.setLineVertex(vidx++, in, i1, i0, color, +weight/2);
+ tess.setLineVertex(vidx++, strokeVertices, i1, i0, color, +weight/2);
tess.lineIndices[iidx++] = (short) (count + 3);
cache.incCounts(index, 6, 4);
@@ -11294,7 +10246,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (lastInd != null) {
if (-1 < lastInd[0] && -1 < lastInd[1]) {
// Adding bevel triangles
- tess.setLineVertex(vidx, in, i0, color0);
+ tess.setLineVertex(vidx, strokeVertices, i0, color0);
if (newCache) {
PGraphics.showWarning(TOO_LONG_STROKE_PATH_ERROR);
@@ -11342,11 +10294,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
int iidx = cache.indexOffset[index] + cache.indexCount[index];
int vidx = cache.vertexOffset[index] + cache.vertexCount[index];
- int color0 = constStroke ? strokeColor : in.strokeColors[i0];
+ int color0 = constStroke ? strokeColor : strokeColors[i0];
if (lastInd != null) {
if (-1 < lastInd[0] && -1 < lastInd[1]) {
- tess.setLineVertex(vidx, in, i0, color0);
+ tess.setLineVertex(vidx, strokeVertices, i0, color0);
if (newCache) {
PGraphics.showWarning(TOO_LONG_STROKE_PATH_ERROR);
@@ -11381,7 +10333,7 @@ public class PGraphicsOpenGL extends PGraphics {
// ending at i1, in the case of pure 2D renderers (line geometry
// is added to the poly arrays).
int addLineSegment2D(int i0, int i1, int index,
- boolean constStroke, boolean clamp) {
+ boolean constStroke, boolean clamp) {
IndexCache cache = tess.polyIndexCache;
int count = cache.vertexCount[index];
if (PGL.MAX_VERTEX_INDEX1 <= count + 4) {
@@ -11392,15 +10344,15 @@ public class PGraphicsOpenGL extends PGraphics {
int iidx = cache.indexOffset[index] + cache.indexCount[index];
int vidx = cache.vertexOffset[index] + cache.vertexCount[index];
- int color = constStroke ? strokeColor : in.strokeColors[i0];
- float weight = constStroke ? strokeWeight : in.strokeWeights[i0];
+ int color = constStroke ? strokeColor : strokeColors[i0];
+ float weight = constStroke ? strokeWeight : strokeWeights[i0];
if (subPixelStroke(weight)) clamp = false;
- float x0 = in.vertices[3 * i0 + 0];
- float y0 = in.vertices[3 * i0 + 1];
+ float x0 = strokeVertices[3 * i0 + 0];
+ float y0 = strokeVertices[3 * i0 + 1];
- float x1 = in.vertices[3 * i1 + 0];
- float y1 = in.vertices[3 * i1 + 1];
+ float x1 = strokeVertices[3 * i1 + 0];
+ float y1 = strokeVertices[3 * i1 + 1];
// Calculating direction and normal of the line.
float dirx = x1 - x0;
@@ -11445,8 +10397,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
if (!constStroke) {
- color = in.strokeColors[i1];
- weight = in.strokeWeights[i1];
+ color = strokeColors[i1];
+ weight = strokeWeights[i1];
normdx = normx * weight/2;
normdy = normy * weight/2;
if (subPixelStroke(weight)) clamp = false;
@@ -11481,7 +10433,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
void unclampLine2D(int tessIdx, float x, float y) {
- PMatrix3D mm = modelview;
+ PMatrix3D mm = pg.modelview;
int index = 4 * tessIdx;
tess.polyVertices[index++] = x*mm.m00 + y*mm.m01 + mm.m03;
tess.polyVertices[index++] = x*mm.m10 + y*mm.m11 + mm.m13;
@@ -11505,7 +10457,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
boolean noCapsJoins() {
- // The stroke weight is scaled so it correspons to the current
+ // The stroke weight is scaled so it corresponds to the current
// "zoom level" being applied on the geometry due to scaling:
return tess.renderMode == IMMEDIATE &&
transformScale() * strokeWeight < PGL.MIN_CAPS_JOINS_WEIGHT;
@@ -11542,19 +10494,24 @@ public class PGraphicsOpenGL extends PGraphics {
zero(in.vertices[3 * i0 + 1] - in.vertices[3 * i1 + 1]);
}
+ boolean segmentIsAxisAligned(float[] vertices, int i0, int i1) {
+ return zero(vertices[3 * i0 + 0] - vertices[3 * i1 + 0]) ||
+ zero(vertices[3 * i0 + 1] - vertices[3 * i1 + 1]);
+ }
+
// -----------------------------------------------------------------
//
// Polygon primitives tessellation
void tessellateTriangles() {
beginTex();
- int nTri = (in.lastVertex - in.firstVertex + 1) / 3;
+ int nTri = in.vertexCount / 3;
if (fill && 1 <= nTri) {
int nInInd = 3 * nTri;
setRawSize(nInInd);
int idx = 0;
boolean clamp = clampTriangles();
- for (int i = in.firstVertex; i < in.firstVertex + 3 * nTri; i++) {
+ for (int i = 0; i < 3 * nTri; i++) {
rawIndices[idx++] = i;
}
splitRawIndices(clamp);
@@ -11566,7 +10523,7 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampTriangles() {
boolean res = clamp2D();
if (res) {
- int nTri = (in.lastVertex - in.firstVertex + 1) / 3;
+ int nTri = in.vertexCount / 3;
for (int i = 0; i < nTri; i++) {
int i0 = 3 * i + 0;
int i1 = 3 * i + 1;
@@ -11584,7 +10541,7 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateTriangles(int[] indices) {
beginTex();
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (fill && 3 <= nInVert) {
int nInInd = indices.length;
setRawSize(nInInd);
@@ -11617,14 +10574,14 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateTriangleFan() {
beginTex();
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (fill && 3 <= nInVert) {
int nInInd = 3 * (nInVert - 2);
setRawSize(nInInd);
int idx = 0;
boolean clamp = clampTriangleFan();
- for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
- rawIndices[idx++] = in.firstVertex;
+ for (int i = 1; i < in.vertexCount - 1; i++) {
+ rawIndices[idx++] = 0;
rawIndices[idx++] = i;
rawIndices[idx++] = i + 1;
}
@@ -11637,8 +10594,8 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampTriangleFan() {
boolean res = clamp2D();
if (res) {
- for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
- int i0 = in.firstVertex;
+ for (int i = 1; i < in.vertexCount - 1; i++) {
+ int i0 = 0;
int i1 = i;
int i2 = i + 1;
int count = 0;
@@ -11654,13 +10611,13 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateTriangleStrip() {
beginTex();
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
if (fill && 3 <= nInVert) {
int nInInd = 3 * (nInVert - 2);
setRawSize(nInInd);
int idx = 0;
boolean clamp = clampTriangleStrip();
- for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
+ for (int i = 1; i < in.vertexCount - 1; i++) {
rawIndices[idx++] = i;
if (i % 2 == 0) {
rawIndices[idx++] = i - 1;
@@ -11679,7 +10636,7 @@ public class PGraphicsOpenGL extends PGraphics {
boolean clampTriangleStrip() {
boolean res = clamp2D();
if (res) {
- for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
+ for (int i = 1; i < in.vertexCount - 1; i++) {
int i0 = i;
int i1, i2;
if (i % 2 == 0) {
@@ -11702,17 +10659,17 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateQuads() {
beginTex();
- int quadCount = (in.lastVertex - in.firstVertex + 1) / 4;
+ int quadCount = in.vertexCount / 4;
if (fill && 1 <= quadCount) {
int nInInd = 6 * quadCount;
setRawSize(nInInd);
int idx = 0;
boolean clamp = clampQuads(quadCount);
for (int qd = 0; qd < quadCount; qd++) {
- int i0 = in.firstVertex + 4 * qd + 0;
- int i1 = in.firstVertex + 4 * qd + 1;
- int i2 = in.firstVertex + 4 * qd + 2;
- int i3 = in.firstVertex + 4 * qd + 3;
+ int i0 = 4 * qd + 0;
+ int i1 = 4 * qd + 1;
+ int i2 = 4 * qd + 2;
+ int i3 = 4 * qd + 3;
rawIndices[idx++] = i0;
rawIndices[idx++] = i1;
@@ -11732,10 +10689,10 @@ public class PGraphicsOpenGL extends PGraphics {
boolean res = clamp2D();
if (res) {
for (int qd = 0; qd < quadCount; qd++) {
- int i0 = in.firstVertex + 4 * qd + 0;
- int i1 = in.firstVertex + 4 * qd + 1;
- int i2 = in.firstVertex + 4 * qd + 2;
- int i3 = in.firstVertex + 4 * qd + 3;
+ int i0 = 4 * qd + 0;
+ int i1 = 4 * qd + 1;
+ int i2 = 4 * qd + 2;
+ int i3 = 4 * qd + 3;
res = segmentIsAxisAligned(i0, i1) &&
segmentIsAxisAligned(i1, i2) &&
segmentIsAxisAligned(i2, i3);
@@ -11747,17 +10704,17 @@ public class PGraphicsOpenGL extends PGraphics {
void tessellateQuadStrip() {
beginTex();
- int quadCount = (in.lastVertex - in.firstVertex + 1) / 2 - 1;
+ int quadCount = in.vertexCount / 2 - 1;
if (fill && 1 <= quadCount) {
int nInInd = 6 * quadCount;
setRawSize(nInInd);
int idx = 0;
boolean clamp = clampQuadStrip(quadCount);
for (int qd = 1; qd < quadCount + 1; qd++) {
- int i0 = in.firstVertex + 2 * (qd - 1);
- int i1 = in.firstVertex + 2 * (qd - 1) + 1;
- int i2 = in.firstVertex + 2 * qd + 1;
- int i3 = in.firstVertex + 2 * qd;
+ int i0 = 2 * (qd - 1);
+ int i1 = 2 * (qd - 1) + 1;
+ int i2 = 2 * qd + 1;
+ int i3 = 2 * qd;
rawIndices[idx++] = i0;
rawIndices[idx++] = i1;
@@ -11777,10 +10734,10 @@ public class PGraphicsOpenGL extends PGraphics {
boolean res = clamp2D();
if (res) {
for (int qd = 1; qd < quadCount + 1; qd++) {
- int i0 = in.firstVertex + 2 * (qd - 1);
- int i1 = in.firstVertex + 2 * (qd - 1) + 1;
- int i2 = in.firstVertex + 2 * qd + 1;
- int i3 = in.firstVertex + 2 * qd;
+ int i0 = 2 * (qd - 1);
+ int i1 = 2 * (qd - 1) + 1;
+ int i2 = 2 * qd + 1;
+ int i3 = 2 * qd;
res = segmentIsAxisAligned(i0, i1) &&
segmentIsAxisAligned(i1, i2) &&
segmentIsAxisAligned(i2, i3);
@@ -11812,7 +10769,7 @@ public class PGraphicsOpenGL extends PGraphics {
// Current index and vertex ranges
int inInd0 = 0, inInd1 = 0;
- int inMaxVert0 = in.firstVertex, inMaxVert1 = in.firstVertex;
+ int inMaxVert0 = 0, inMaxVert1 = 0;
int inMaxVertRef = inMaxVert0; // Reference vertex where last break split occurred
int inMaxVertRel = -1; // Position of vertices from last range relative to
@@ -12018,78 +10975,535 @@ public class PGraphicsOpenGL extends PGraphics {
// -----------------------------------------------------------------
//
- // Polygon tessellation
+ // Polygon tessellation, includes edge calculation and tessellation.
void tessellatePolygon(boolean solid, boolean closed, boolean calcNormals) {
beginTex();
- int nInVert = in.lastVertex - in.firstVertex + 1;
+ int nInVert = in.vertexCount;
- if (fill && 3 <= nInVert) {
+ if (3 <= nInVert) {
firstPolyIndexCache = -1;
boolean clamp = clampPolygon();
callback.init(in.renderMode == RETAINED, false, calcNormals, clamp);
- gluTess.beginPolygon();
-
- if (solid) {
- // Using NONZERO winding rule for solid polygons.
- gluTess.setWindingRule(PGL.TESS_WINDING_NONZERO);
- } else {
- // Using ODD winding rule to generate polygon with holes.
- gluTess.setWindingRule(PGL.TESS_WINDING_ODD);
+ if (fill) {
+ gluTess.beginPolygon();
+ if (solid) {
+ // Using NONZERO winding rule for solid polygons.
+ gluTess.setWindingRule(PGL.TESS_WINDING_NONZERO);
+ } else {
+ // Using ODD winding rule to generate polygon with holes.
+ gluTess.setWindingRule(PGL.TESS_WINDING_ODD);
+ }
+ gluTess.beginContour();
}
- gluTess.beginContour();
+ if (stroke) {
+ beginPolygonStroke();
+ beginStrokePath();
+ }
- // Now, iterate over all input data and send to GLU tessellator..
- for (int i = in.firstVertex; i <= in.lastVertex; i++) {
- boolean breakPt = in.breaks[i];
- if (breakPt) {
- gluTess.endContour();
- gluTess.beginContour();
+ int i = 0;
+ int c = 0;
+ while (i < in.vertexCount) {
+ int code = VERTEX;
+ boolean brk = false;
+ if (in.codes != null && c < in.codeCount) {
+ code = in.codes[c++];
+ if (code == BREAK && c < in.codeCount) {
+ brk = true;
+ code = in.codes[c++];
+ }
}
- // Separting colors into individual rgba components for interpolation.
- int fa = (in.colors[i] >> 24) & 0xFF;
- int fr = (in.colors[i] >> 16) & 0xFF;
- int fg = (in.colors[i] >> 8) & 0xFF;
- int fb = (in.colors[i] >> 0) & 0xFF;
+ if (brk) {
+ if (stroke) {
+ endStrokePath(closed);
+ beginStrokePath();
+ }
+ if (fill) {
+ gluTess.endContour();
+ gluTess.beginContour();
+ }
+ }
- int aa = (in.ambient[i] >> 24) & 0xFF;
- int ar = (in.ambient[i] >> 16) & 0xFF;
- int ag = (in.ambient[i] >> 8) & 0xFF;
- int ab = (in.ambient[i] >> 0) & 0xFF;
-
- int sa = (in.specular[i] >> 24) & 0xFF;
- int sr = (in.specular[i] >> 16) & 0xFF;
- int sg = (in.specular[i] >> 8) & 0xFF;
- int sb = (in.specular[i] >> 0) & 0xFF;
-
- int ea = (in.emissive[i] >> 24) & 0xFF;
- int er = (in.emissive[i] >> 16) & 0xFF;
- int eg = (in.emissive[i] >> 8) & 0xFF;
- int eb = (in.emissive[i] >> 0) & 0xFF;
-
- // Vertex data includes coordinates, colors, normals, texture
- // coordinates, and material properties.
- double[] vertex = new double[] {
- in.vertices [3*i + 0], in.vertices [3*i + 1], in.vertices[3*i + 2],
- fa, fr, fg, fb,
- in.normals [3*i + 0], in.normals [3*i + 1], in.normals [3*i + 2],
- in.texcoords[2*i + 0], in.texcoords[2*i + 1],
- aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i]};
-
- gluTess.addVertex(vertex);
+ if (code == BEZIER_VERTEX) {
+ addBezierVertex(i);
+ i += 3;
+ } else if (code == QUADRATIC_VERTEX) {
+ addQuadraticVertex(i);
+ i += 2;
+ } else if (code == CURVE_VERTEX) {
+ addCurveVertex(i);
+ i++;
+ } else {
+ addVertex(i);
+ i++;
+ }
+ }
+ if (stroke) {
+ endStrokePath(closed);
+ endPolygonStroke();
+ }
+ if (fill) {
+ gluTess.endContour();
+ gluTess.endPolygon();
}
- gluTess.endContour();
-
- gluTess.endPolygon();
}
endTex();
- tessellateEdges();
+ if (stroke) tessellateStrokePath();
+ }
+
+ void addBezierVertex(int i) {
+ pg.curveVertexCount = 0;
+ pg.bezierInitCheck();
+ pg.bezierVertexCheck(POLYGON, i);
+
+ PMatrix3D draw = pg.bezierDrawMatrix;
+
+ int i1 = i - 1;
+ float x1 = in.vertices[3*i1 + 0];
+ float y1 = in.vertices[3*i1 + 1];
+ float z1 = in.vertices[3*i1 + 2];
+
+ int strokeColor = 0;
+ float strokeWeight = 0;
+ if (stroke) {
+ strokeColor = in.strokeColors[i];
+ strokeWeight = in.strokeWeights[i];
+ }
+
+ int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0;
+ int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0;
+ int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0;
+ int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0;
+ float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0;
+ if (fill) {
+ fcol = in.colors[i];
+ fa = (fcol >> 24) & 0xFF;
+ fr = (fcol >> 16) & 0xFF;
+ fg = (fcol >> 8) & 0xFF;
+ fb = (fcol >> 0) & 0xFF;
+
+ acol = in.ambient[i];
+ aa = (acol >> 24) & 0xFF;
+ ar = (acol >> 16) & 0xFF;
+ ag = (acol >> 8) & 0xFF;
+ ab = (acol >> 0) & 0xFF;
+
+ scol = in.specular[i];
+ sa = (scol >> 24) & 0xFF;
+ sr = (scol >> 16) & 0xFF;
+ sg = (scol >> 8) & 0xFF;
+ sb = (scol >> 0) & 0xFF;
+
+ ecol = in.emissive[i];
+ ea = (ecol >> 24) & 0xFF;
+ er = (ecol >> 16) & 0xFF;
+ eg = (ecol >> 8) & 0xFF;
+ eb = (ecol >> 0) & 0xFF;
+
+ nx = in.normals[3*i + 0];
+ ny = in.normals[3*i + 1];
+ nz = in.normals[3*i + 2];
+ u = in.texcoords[2*i + 0];
+ v = in.texcoords[2*i + 1];
+ sh = in.shininess[i];
+ }
+
+ float x2 = in.vertices[3*i + 0];
+ float y2 = in.vertices[3*i + 1];
+ float z2 = in.vertices[3*i + 2];
+ float x3 = in.vertices[3*(i+1) + 0];
+ float y3 = in.vertices[3*(i+1) + 1];
+ float z3 = in.vertices[3*(i+1) + 2];
+ float x4 = in.vertices[3*(i+2) + 0];
+ float y4 = in.vertices[3*(i+2) + 1];
+ float z4 = in.vertices[3*(i+2) + 2];
+
+ float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
+ float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
+ float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
+
+ float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
+ float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
+ float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
+
+ float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
+ float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
+ float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
+
+ for (int j = 0; j < pg.bezierDetail; j++) {
+ x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
+ y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
+ z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
+ if (fill) {
+ double[] vertex = new double[] {
+ x1, y1, z1,
+ fa, fr, fg, fb,
+ nx, ny, nz,
+ u, v,
+ aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh};
+ gluTess.addVertex(vertex);
+ }
+ if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight);
+ }
+ }
+
+ void addQuadraticVertex(int i) {
+ pg.curveVertexCount = 0;
+ pg.bezierInitCheck();
+ pg.bezierVertexCheck(pg.shape, i);
+
+ PMatrix3D draw = pg.bezierDrawMatrix;
+
+ int i1 = i - 1;
+ float x1 = in.vertices[3*i1 + 0];
+ float y1 = in.vertices[3*i1 + 1];
+ float z1 = in.vertices[3*i1 + 2];
+
+ int strokeColor = 0;
+ float strokeWeight = 0;
+ if (stroke) {
+ strokeColor = in.strokeColors[i];
+ strokeWeight = in.strokeWeights[i];
+ }
+
+ int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0;
+ int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0;
+ int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0;
+ int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0;
+ float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0;
+ if (fill) {
+ fcol = in.colors[i];
+ fa = (fcol >> 24) & 0xFF;
+ fr = (fcol >> 16) & 0xFF;
+ fg = (fcol >> 8) & 0xFF;
+ fb = (fcol >> 0) & 0xFF;
+
+ acol = in.ambient[i];
+ aa = (acol >> 24) & 0xFF;
+ ar = (acol >> 16) & 0xFF;
+ ag = (acol >> 8) & 0xFF;
+ ab = (acol >> 0) & 0xFF;
+
+ scol = in.specular[i];
+ sa = (scol >> 24) & 0xFF;
+ sr = (scol >> 16) & 0xFF;
+ sg = (scol >> 8) & 0xFF;
+ sb = (scol >> 0) & 0xFF;
+
+ ecol = in.emissive[i];
+ ea = (ecol >> 24) & 0xFF;
+ er = (ecol >> 16) & 0xFF;
+ eg = (ecol >> 8) & 0xFF;
+ eb = (ecol >> 0) & 0xFF;
+
+ nx = in.normals[3*i + 0];
+ ny = in.normals[3*i + 1];
+ nz = in.normals[3*i + 2];
+ u = in.texcoords[2*i + 0];
+ v = in.texcoords[2*i + 1];
+ sh = in.shininess[i];
+ }
+
+ float cx = in.vertices[3*i + 0];
+ float cy = in.vertices[3*i + 1];
+ float cz = in.vertices[3*i + 2];
+ float x = in.vertices[3*(i+1) + 0];
+ float y = in.vertices[3*(i+1) + 1];
+ float z = in.vertices[3*(i+1) + 2];
+
+ float x2 = x1 + ((cx-x1)*2/3.0f);
+ float y2 = y1 + ((cy-y1)*2/3.0f);
+ float z2 = z1 + ((cz-z1)*2/3.0f);
+ float x3 = x + ((cx-x)*2/3.0f);
+ float y3 = y + ((cy-y)*2/3.0f);
+ float z3 = z + ((cz-z)*2/3.0f);
+ float x4 = x;
+ float y4 = y;
+ float z4 = z;
+
+ float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
+ float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
+ float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
+
+ float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
+ float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
+ float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
+
+ float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
+ float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
+ float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
+
+ for (int j = 0; j < pg.bezierDetail; j++) {
+ x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3;
+ y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3;
+ z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3;
+ if (fill) {
+ double[] vertex = new double[] {
+ x1, y1, z1,
+ fa, fr, fg, fb,
+ nx, ny, nz,
+ u, v,
+ aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh};
+ gluTess.addVertex(vertex);
+ }
+ if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight);
+ }
+ }
+
+ void addCurveVertex(int i) {
+ pg.curveVertexCheck(POLYGON);
+
+ float[] vertex = pg.curveVertices[pg.curveVertexCount];
+ vertex[X] = in.vertices[3*i + 0];
+ vertex[Y] = in.vertices[3*i + 1];
+ vertex[Z] = in.vertices[3*i + 2];
+ pg.curveVertexCount++;
+
+ // draw a segment if there are enough points
+ if (pg.curveVertexCount > 3) {
+ float[] v1 = pg.curveVertices[pg.curveVertexCount - 4];
+ float[] v2 = pg.curveVertices[pg.curveVertexCount - 3];
+ float[] v3 = pg.curveVertices[pg.curveVertexCount - 2];
+ float[] v4 = pg.curveVertices[pg.curveVertexCount - 1];
+ addCurveVertexSegment(i, v1[X], v1[Y], v1[Z],
+ v2[X], v2[Y], v2[Z],
+ v3[X], v3[Y], v3[Z],
+ v4[X], v4[Y], v4[Z]);
+ }
+ }
+
+ void addCurveVertexSegment(int i, float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4) {
+ int strokeColor = 0;
+ float strokeWeight = 0;
+ if (stroke) {
+ strokeColor = in.strokeColors[i];
+ strokeWeight = in.strokeWeights[i];
+ }
+
+ int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0;
+ int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0;
+ int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0;
+ int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0;
+ float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0;
+ if (fill) {
+ fcol = in.colors[i];
+ fa = (fcol >> 24) & 0xFF;
+ fr = (fcol >> 16) & 0xFF;
+ fg = (fcol >> 8) & 0xFF;
+ fb = (fcol >> 0) & 0xFF;
+
+ acol = in.ambient[i];
+ aa = (acol >> 24) & 0xFF;
+ ar = (acol >> 16) & 0xFF;
+ ag = (acol >> 8) & 0xFF;
+ ab = (acol >> 0) & 0xFF;
+
+ scol = in.specular[i];
+ sa = (scol >> 24) & 0xFF;
+ sr = (scol >> 16) & 0xFF;
+ sg = (scol >> 8) & 0xFF;
+ sb = (scol >> 0) & 0xFF;
+
+ ecol = in.emissive[i];
+ ea = (ecol >> 24) & 0xFF;
+ er = (ecol >> 16) & 0xFF;
+ eg = (ecol >> 8) & 0xFF;
+ eb = (ecol >> 0) & 0xFF;
+
+ nx = in.normals[3*i + 0];
+ ny = in.normals[3*i + 1];
+ nz = in.normals[3*i + 2];
+ u = in.texcoords[2*i + 0];
+ v = in.texcoords[2*i + 1];
+ sh = in.shininess[i];
+ }
+
+ float x = x2;
+ float y = y2;
+ float z = z2;
+
+ PMatrix3D draw = pg.curveDrawMatrix;
+
+ float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4;
+ float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4;
+ float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4;
+
+ float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4;
+ float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4;
+ float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4;
+
+ float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4;
+ float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4;
+ float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4;
+
+ if (fill) {
+ double[] vertex0 = new double[] {
+ x, y, z,
+ fa, fr, fg, fb,
+ nx, ny, nz,
+ u, v,
+ aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh};
+ gluTess.addVertex(vertex0);
+ }
+ if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight);
+
+ for (int j = 0; j < pg.curveDetail; j++) {
+ x += xplot1; xplot1 += xplot2; xplot2 += xplot3;
+ y += yplot1; yplot1 += yplot2; yplot2 += yplot3;
+ z += zplot1; zplot1 += zplot2; zplot2 += zplot3;
+ if (fill) {
+ double[] vertex1 = new double[] {
+ x, y, z,
+ fa, fr, fg, fb,
+ nx, ny, nz,
+ u, v,
+ aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh};
+ gluTess.addVertex(vertex1);
+ }
+ if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight);
+ }
+ }
+
+ void addVertex(int i) {
+ pg.curveVertexCount = 0;
+
+ float x = in.vertices[3*i + 0];
+ float y = in.vertices[3*i + 1];
+ float z = in.vertices[3*i + 2];
+
+ int strokeColor = 0;
+ float strokeWeight = 0;
+ if (stroke) {
+ strokeColor = in.strokeColors[i];
+ strokeWeight = in.strokeWeights[i];
+ }
+
+ if (fill) {
+ // Separating colors into individual rgba components for interpolation.
+ int fcol = in.colors[i];
+ int fa = (fcol >> 24) & 0xFF;
+ int fr = (fcol >> 16) & 0xFF;
+ int fg = (fcol >> 8) & 0xFF;
+ int fb = (fcol >> 0) & 0xFF;
+
+ int acol = in.ambient[i];
+ int aa = (acol >> 24) & 0xFF;
+ int ar = (acol >> 16) & 0xFF;
+ int ag = (acol >> 8) & 0xFF;
+ int ab = (acol >> 0) & 0xFF;
+
+ int scol = in.specular[i];
+ int sa = (scol >> 24) & 0xFF;
+ int sr = (scol >> 16) & 0xFF;
+ int sg = (scol >> 8) & 0xFF;
+ int sb = (scol >> 0) & 0xFF;
+
+ int ecol = in.emissive[i];
+ int ea = (ecol >> 24) & 0xFF;
+ int er = (ecol >> 16) & 0xFF;
+ int eg = (ecol >> 8) & 0xFF;
+ int eb = (ecol >> 0) & 0xFF;
+
+ float nx = in.normals[3*i + 0];
+ float ny = in.normals[3*i + 1];
+ float nz = in.normals[3*i + 2];
+ float u = in.texcoords[2*i + 0];
+ float v = in.texcoords[2*i + 1];
+ float sh = in.shininess[i];
+
+ double[] vertex = new double[] {
+ x, y, z,
+ fa, fr, fg, fb,
+ nx, ny, nz,
+ u, v,
+ aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh};
+ gluTess.addVertex(vertex);
+ }
+ if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight);
+ }
+
+ void beginPolygonStroke() {
+ pathVertexCount = 0;
+ if (pathVertices == null) {
+ pathVertices = new float[3 * PGL.DEFAULT_IN_VERTICES];
+ pathColors = new int[PGL.DEFAULT_IN_VERTICES];
+ pathWeights = new float[PGL.DEFAULT_IN_VERTICES];
+ }
+ }
+
+ void endPolygonStroke() {
+ // Nothing to do here.
+ }
+
+ void beginStrokePath() {
+ beginPath = pathVertexCount;
+ }
+
+ void endStrokePath(boolean closed) {
+ int idx = pathVertexCount;
+ if (beginPath + 1 < idx) {
+ boolean begin = beginPath == idx - 2;
+ boolean end = begin || !closed;
+ in.addEdge(idx - 2, idx - 1, begin, end);
+ if (!end) {
+ in.addEdge(idx - 1, beginPath, false, false);
+ in.closeEdge(idx - 1, beginPath);
+ }
+ }
+ }
+
+ void addStrokeVertex(float x, float y, float z, int c, float w) {
+ int idx = pathVertexCount;
+ if (beginPath + 1 < idx) {
+ in.addEdge(idx - 2, idx - 1, beginPath == idx - 2, false);
+ }
+
+ if (pathVertexCount == pathVertices.length / 3) {
+ int newSize = pathVertexCount << 1;
+
+ float vtemp[] = new float[3 * newSize];
+ PApplet.arrayCopy(pathVertices, 0, vtemp, 0, 3 * pathVertexCount);
+ pathVertices = vtemp;
+
+ int ctemp[] = new int[newSize];
+ PApplet.arrayCopy(pathColors, 0, ctemp, 0, pathVertexCount);
+ pathColors = ctemp;
+
+ float wtemp[] = new float[newSize];
+ PApplet.arrayCopy(pathWeights, 0, wtemp, 0, pathVertexCount);
+ pathWeights = wtemp;
+ }
+
+ pathVertices[3 * idx + 0] = x;
+ pathVertices[3 * idx + 1] = y;
+ pathVertices[3 * idx + 2] = z;
+ pathColors[idx] = c;
+ pathWeights[idx] = w;
+
+ pathVertexCount++;
+ }
+
+ void tessellateStrokePath() {
+ if (in.edgeCount == 0) return;
+ strokeVertices = pathVertices;
+ strokeColors = pathColors;
+ strokeWeights = pathWeights;
+ if (is3D) {
+ tessellateEdges3D();
+ } else if (is2D) {
+ beginNoTex();
+ tessellateEdges2D();
+ endNoTex();
+ }
}
boolean clampPolygon() {
@@ -12167,7 +11581,7 @@ public class PGraphicsOpenGL extends PGraphics {
/////////////////////////////////////////
- // Interenting notes about using the GLU tessellator to render thick
+ // Interesting notes about using the GLU tessellator to render thick
// polylines:
// http://stackoverflow.com/questions/687173/how-do-i-render-thick-2d-lines-as-polygons
//
@@ -12214,17 +11628,9 @@ public class PGraphicsOpenGL extends PGraphics {
vertFirst = cache.vertexCount[cacheIndex];
vertCount = 0;
- switch (type) {
- case PGL.TRIANGLE_FAN:
- primitive = TRIANGLE_FAN;
- break;
- case PGL.TRIANGLE_STRIP:
- primitive = TRIANGLE_STRIP;
- break;
- case PGL.TRIANGLES:
- primitive = TRIANGLES;
- break;
- }
+ if (type == PGL.TRIANGLE_FAN) primitive = TRIANGLE_FAN;
+ else if (type == PGL.TRIANGLE_STRIP) primitive = TRIANGLE_STRIP;
+ else if (type == PGL.TRIANGLES) primitive = TRIANGLES;
}
public void end() {
diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java
new file mode 100644
index 000000000..597d63ae3
--- /dev/null
+++ b/core/src/processing/opengl/PJOGL.java
@@ -0,0 +1,2492 @@
+package processing.opengl;
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2ES3;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLFBODrawable;
+import javax.media.opengl.GLProfile;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+import javax.media.opengl.glu.GLU;
+
+import processing.core.PApplet;
+import processing.core.PConstants;
+import processing.core.PGraphics;
+import processing.event.KeyEvent;
+import processing.event.MouseEvent;
+
+import com.jogamp.newt.awt.NewtCanvasAWT;
+import com.jogamp.newt.event.InputEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.FBObject;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.PathIterator;
+
+import javax.media.opengl.glu.GLUtessellator;
+import javax.media.opengl.glu.GLUtessellatorCallbackAdapter;
+
+public class PJOGL extends PGL {
+ // OpenGL profile to use (2, 3 or 4)
+ public static int PROFILE = 2;
+
+ // The two windowing toolkits available to use in JOGL:
+ public static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing
+ public static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html
+
+ // ........................................................
+
+ // Public members to access the underlying GL objects and context
+
+ /** Basic GL functionality, common to all profiles */
+ public static GL gl;
+
+ /** GLU interface **/
+ public static GLU glu;
+
+ /** The rendering context (holds rendering state info) */
+ public static GLContext context;
+
+ /** The canvas where OpenGL rendering takes place */
+ public static Canvas canvas;
+
+ /** Selected GL profile */
+ public static GLProfile profile;
+
+ // ........................................................
+
+ // Additional parameters
+
+ /** Time that the Processing's animation thread will wait for JOGL's rendering
+ * thread to be done with a single frame.
+ */
+ protected static int DRAW_TIMEOUT_MILLIS = 500;
+
+ // ........................................................
+
+ // OS-specific configuration
+
+ protected static int WINDOW_TOOLKIT;
+ protected static int EVENTS_TOOLKIT;
+ protected static boolean USE_JOGL_FBOLAYER;
+ static {
+ if (PApplet.platform == PConstants.WINDOWS) {
+ // Using AWT on Windows because NEWT displays a black background while
+ // initializing, and the cursor functions don't work. GLWindow has some
+ // functions for basic cursor handling (hide/show):
+ // GLWindow.setPointerVisible(false);
+ // but apparently nothing to set the cursor icon:
+ // https://jogamp.org/bugzilla/show_bug.cgi?id=409
+ WINDOW_TOOLKIT = AWT;
+ EVENTS_TOOLKIT = AWT;
+ USE_FBOLAYER_BY_DEFAULT = false;
+ USE_JOGL_FBOLAYER = false;
+ } else if (PApplet.platform == PConstants.MACOSX) {
+ // Note: The JOGL FBO layer (in 2.0.2) seems incompatible with NEWT.
+ WINDOW_TOOLKIT = AWT;
+ EVENTS_TOOLKIT = AWT;
+ USE_FBOLAYER_BY_DEFAULT = true;
+ USE_JOGL_FBOLAYER = true;
+ } else if (PApplet.platform == PConstants.LINUX) {
+ WINDOW_TOOLKIT = AWT;
+ EVENTS_TOOLKIT = AWT;
+ USE_FBOLAYER_BY_DEFAULT = false;
+ USE_JOGL_FBOLAYER = false;
+ } else if (PApplet.platform == PConstants.OTHER) {
+ WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi?
+ EVENTS_TOOLKIT = NEWT;
+ USE_FBOLAYER_BY_DEFAULT = false;
+ USE_JOGL_FBOLAYER = false;
+ }
+ }
+
+ // ........................................................
+
+ // Protected JOGL-specific objects needed to access the GL profiles
+
+ /** The capabilities of the OpenGL rendering surface */
+ protected static GLCapabilitiesImmutable capabilities;
+
+ /** The rendering surface */
+ protected static GLDrawable drawable;
+
+ /** GLES2 functionality (shaders, etc) */
+ protected static GL2ES2 gl2;
+
+ /** GL3 interface */
+ protected static GL2GL3 gl3;
+
+ /** GL2 desktop functionality (blit framebuffer, map buffer range,
+ * multisampled renerbuffers) */
+ protected static GL2 gl2x;
+
+ /** The AWT-OpenGL canvas */
+ protected static GLCanvas canvasAWT;
+
+ /** The NEWT-OpenGL canvas */
+ protected static NewtCanvasAWT canvasNEWT;
+
+ /** The NEWT window */
+ protected static GLWindow window;
+
+ /** The listener that fires the frame rendering in Processing */
+ protected static PGLListener listener;
+
+ /** This countdown latch is used to maintain the synchronization between
+ * Processing's drawing thread and JOGL's rendering thread */
+ protected CountDownLatch drawLatch;
+
+ /** Flag used to do request final display() call to make sure that the
+ * buffers are properly swapped.
+ */
+ protected boolean prevCanDraw = false;
+
+ // ........................................................
+
+ // JOGL's FBO-layer
+
+ /** Back (== draw, current frame) buffer */
+ protected static FBObject backFBO;
+ /** Sink buffer, used in the multisampled case */
+ protected static FBObject sinkFBO;
+ /** Front (== read, previous frame) buffer */
+ protected static FBObject frontFBO;
+ protected static FBObject.TextureAttachment backTexAttach;
+ protected static FBObject.TextureAttachment frontTexAttach;
+
+ protected boolean changedFrontTex = false;
+ protected boolean changedBackTex = false;
+
+ // ........................................................
+
+ // Utility arrays to copy projection/modelview matrices to GL
+
+ protected float[] projMatrix;
+ protected float[] mvMatrix;
+
+ // ........................................................
+
+ // Static initialization for some parameters that need to be different for
+ // JOGL
+
+ static {
+ MIN_DIRECT_BUFFER_SIZE = 2;
+ INDEX_TYPE = GL.GL_UNSIGNED_SHORT;
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+
+ // Initialization, finalization
+
+
+ public PJOGL(PGraphicsOpenGL pg) {
+ super(pg);
+ if (glu == null) glu = new GLU();
+ }
+
+
+ @Override
+ protected void setFps(float fps) {
+ if (!setFps || targetFps != fps) {
+ if (60 < fps) {
+ // Disables v-sync
+ gl.setSwapInterval(0);
+ } else if (30 < fps) {
+ gl.setSwapInterval(1);
+ } else {
+ gl.setSwapInterval(2);
+ }
+ targetFps = currentFps = fps;
+ setFps = true;
+ }
+ }
+
+
+ @Override
+ protected void initSurface(int antialias) {
+ if (profile == null) {
+ if (PROFILE == 2) {
+ try {
+ profile = GLProfile.getGL2ES1();
+ } catch (GLException ex) {
+ profile = GLProfile.getMaxFixedFunc(true);
+ }
+ } else if (PROFILE == 3) {
+ try {
+ profile = GLProfile.getGL2GL3();
+ } catch (GLException ex) {
+ profile = GLProfile.getMaxProgrammable(true);
+ }
+ if (!profile.isGL3()) {
+ PGraphics.showWarning("Requested profile GL3 but is not available, got: " + profile);
+ }
+ } else if (PROFILE == 4) {
+ try {
+ profile = GLProfile.getGL4ES3();
+ } catch (GLException ex) {
+ profile = GLProfile.getMaxProgrammable(true);
+ }
+ if (!profile.isGL4()) {
+ PGraphics.showWarning("Requested profile GL4 but is not available, got: " + profile);
+ }
+ } else throw new RuntimeException(UNSUPPORTED_GLPROF_ERROR);
+
+ if (2 < PROFILE) {
+ texVertShaderSource = convertVertexSource(texVertShaderSource, 120, 150);
+ tex2DFragShaderSource = convertFragmentSource(tex2DFragShaderSource, 120, 150);
+ texRectFragShaderSource = convertFragmentSource(texRectFragShaderSource, 120, 150);
+ }
+ } else {
+ // Restarting...
+ if (canvasAWT != null) {
+ canvasAWT.removeGLEventListener(listener);
+ pg.parent.removeListeners(canvasAWT);
+ pg.parent.remove(canvasAWT);
+ } else if (canvasNEWT != null) {
+ window.removeGLEventListener(listener);
+ pg.parent.remove(canvasNEWT);
+ }
+ sinkFBO = backFBO = frontFBO = null;
+ }
+
+ // Setting up the desired capabilities;
+ GLCapabilities caps = new GLCapabilities(profile);
+ caps.setAlphaBits(REQUESTED_ALPHA_BITS);
+ caps.setDepthBits(REQUESTED_DEPTH_BITS);
+ caps.setStencilBits(REQUESTED_STENCIL_BITS);
+
+ caps.setBackgroundOpaque(true);
+ caps.setOnscreen(true);
+ if (USE_FBOLAYER_BY_DEFAULT) {
+ if (USE_JOGL_FBOLAYER) {
+ caps.setPBuffer(false);
+ caps.setFBO(true);
+ if (1 < antialias) {
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(antialias);
+ } else {
+ caps.setSampleBuffers(false);
+ }
+ fboLayerRequested = false;
+ } else {
+ caps.setPBuffer(false);
+ caps.setFBO(false);
+ caps.setSampleBuffers(false);
+ fboLayerRequested = 1 < antialias;
+ }
+ } else {
+ if (1 < antialias) {
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(antialias);
+ } else {
+ caps.setSampleBuffers(false);
+ }
+ fboLayerRequested = false;
+ }
+ caps.setDepthBits(REQUESTED_DEPTH_BITS);
+ caps.setStencilBits(REQUESTED_STENCIL_BITS);
+ caps.setAlphaBits(REQUESTED_ALPHA_BITS);
+ reqNumSamples = qualityToSamples(antialias);
+
+ if (WINDOW_TOOLKIT == AWT) {
+ canvasAWT = new GLCanvas(caps);
+ canvasAWT.setBounds(0, 0, pg.width, pg.height);
+ canvasAWT.setBackground(new Color(pg.backgroundColor, true));
+ canvasAWT.setFocusable(true);
+
+ pg.parent.setLayout(new BorderLayout());
+ pg.parent.add(canvasAWT, BorderLayout.CENTER);
+ canvasAWT.requestFocusInWindow();
+
+ canvas = canvasAWT;
+ canvasNEWT = null;
+ } else if (WINDOW_TOOLKIT == NEWT) {
+ window = GLWindow.create(caps);
+ canvasNEWT = new NewtCanvasAWT(window);
+ canvasNEWT.setBounds(0, 0, pg.width, pg.height);
+ canvasNEWT.setBackground(new Color(pg.backgroundColor, true));
+ canvasNEWT.setFocusable(true);
+
+ pg.parent.setLayout(new BorderLayout());
+ pg.parent.add(canvasNEWT, BorderLayout.CENTER);
+ canvasNEWT.requestFocusInWindow();
+
+ canvas = canvasNEWT;
+ canvasAWT = null;
+ }
+
+ registerListeners();
+
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = true;
+ setFps = false;
+ }
+
+
+ @Override
+ protected void reinitSurface() {
+ sinkFBO = backFBO = frontFBO = null;
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = true;
+ }
+
+
+ @Override
+ protected void registerListeners() {
+ if (WINDOW_TOOLKIT == AWT) {
+ pg.parent.removeListeners(pg.parent);
+ pg.parent.addListeners(canvasAWT);
+
+ listener = new PGLListener();
+ canvasAWT.addGLEventListener(listener);
+ } else if (WINDOW_TOOLKIT == NEWT) {
+ if (EVENTS_TOOLKIT == NEWT) {
+ NEWTMouseListener mouseListener = new NEWTMouseListener();
+ window.addMouseListener(mouseListener);
+ NEWTKeyListener keyListener = new NEWTKeyListener();
+ window.addKeyListener(keyListener);
+ NEWTWindowListener winListener = new NEWTWindowListener();
+ window.addWindowListener(winListener);
+ } else if (EVENTS_TOOLKIT == AWT) {
+ pg.parent.removeListeners(canvasNEWT);
+ pg.parent.addListeners(canvasNEWT);
+ }
+
+ listener = new PGLListener();
+ window.addGLEventListener(listener);
+ }
+
+ if (canvas != null) {
+ canvas.setFocusTraversalKeysEnabled(false);
+ }
+ }
+
+
+ @Override
+ protected void deleteSurface() {
+ super.deleteSurface();
+
+ if (canvasAWT != null) {
+ canvasAWT.removeGLEventListener(listener);
+ pg.parent.removeListeners(canvasAWT);
+ } else if (canvasNEWT != null) {
+ window.removeGLEventListener(listener);
+ }
+ GLProfile.shutdown();
+ }
+
+
+ @Override
+ protected int getReadFramebuffer() {
+ if (fboLayerInUse) {
+ return glColorFbo.get(0);
+ } else if (capabilities.isFBO()) {
+ return context.getDefaultReadFramebuffer();
+ } else {
+ return 0;
+ }
+ }
+
+
+ @Override
+ protected int getDrawFramebuffer() {
+ if (fboLayerInUse) {
+ if (1 < numSamples) {
+ return glMultiFbo.get(0);
+ } else {
+ return glColorFbo.get(0);
+ }
+ } else if (capabilities.isFBO()) {
+ return context.getDefaultDrawFramebuffer();
+ } else {
+ return 0;
+ }
+ }
+
+
+ @Override
+ protected int getDefaultDrawBuffer() {
+ if (fboLayerInUse) {
+ return COLOR_ATTACHMENT0;
+ } else if (capabilities.isFBO()) {
+ return GL.GL_COLOR_ATTACHMENT0;
+ } else if (capabilities.getDoubleBuffered()) {
+ return GL.GL_BACK;
+ } else {
+ return GL.GL_FRONT;
+ }
+ }
+
+
+ @Override
+ protected int getDefaultReadBuffer() {
+ if (fboLayerInUse) {
+ return COLOR_ATTACHMENT0;
+ } else if (capabilities.isFBO()) {
+ return GL.GL_COLOR_ATTACHMENT0;
+ } else if (capabilities.getDoubleBuffered()) {
+ return GL.GL_BACK;
+ } else {
+ return GL.GL_FRONT;
+ }
+ }
+
+
+ @Override
+ protected boolean isFBOBacked() {
+ return super.isFBOBacked() || capabilities.isFBO();
+ }
+
+
+ @Override
+ protected int getDepthBits() {
+ return capabilities.getDepthBits();
+ }
+
+
+ @Override
+ protected int getStencilBits() {
+ return capabilities.getStencilBits();
+ }
+
+
+ @Override
+ protected Texture wrapBackTexture(Texture texture) {
+ if (texture == null || changedBackTex) {
+ if (USE_JOGL_FBOLAYER) {
+ texture = new Texture();
+ texture.init(pg.width, pg.height,
+ backTexAttach.getName(), TEXTURE_2D, RGBA,
+ backTexAttach.getWidth(), backTexAttach.getHeight(),
+ backTexAttach.minFilter, backTexAttach.magFilter,
+ backTexAttach.wrapS, backTexAttach.wrapT);
+ texture.invertedY(true);
+ texture.colorBuffer(true);
+ pg.setCache(pg, texture);
+ } else {
+ texture = super.wrapBackTexture(null);
+ }
+ } else {
+ if (USE_JOGL_FBOLAYER) {
+ texture.glName = backTexAttach.getName();
+ } else {
+ texture = super.wrapBackTexture(texture);
+ }
+ }
+ return texture;
+ }
+
+
+ @Override
+ protected Texture wrapFrontTexture(Texture texture) {
+ if (texture == null || changedFrontTex) {
+ if (USE_JOGL_FBOLAYER) {
+ texture = new Texture();
+ texture.init(pg.width, pg.height,
+ backTexAttach.getName(), TEXTURE_2D, RGBA,
+ frontTexAttach.getWidth(), frontTexAttach.getHeight(),
+ frontTexAttach.minFilter, frontTexAttach.magFilter,
+ frontTexAttach.wrapS, frontTexAttach.wrapT);
+ texture.invertedY(true);
+ texture.colorBuffer(true);
+ } else {
+ texture = super.wrapFrontTexture(null);
+ }
+ } else {
+ if (USE_JOGL_FBOLAYER) {
+ texture.glName = frontTexAttach.getName();
+ } else {
+ texture = super.wrapFrontTexture(texture);
+ }
+ }
+ return texture;
+ }
+
+
+ @Override
+ protected void bindFrontTexture() {
+ if (USE_JOGL_FBOLAYER) {
+ usingFrontTex = true;
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ }
+ bindTexture(TEXTURE_2D, frontTexAttach.getName());
+ } else super.bindFrontTexture();
+ }
+
+
+ @Override
+ protected void unbindFrontTexture() {
+ if (USE_JOGL_FBOLAYER) {
+ if (textureIsBound(TEXTURE_2D, frontTexAttach.getName())) {
+ // We don't want to unbind another texture
+ // that might be bound instead of this one.
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ bindTexture(TEXTURE_2D, 0);
+ disableTexturing(TEXTURE_2D);
+ } else {
+ bindTexture(TEXTURE_2D, 0);
+ }
+ }
+ } else super.unbindFrontTexture();
+ }
+
+
+ @Override
+ protected void syncBackTexture() {
+ if (USE_JOGL_FBOLAYER) {
+ if (usingFrontTex) needSepFrontTex = true;
+ if (1 < numSamples) {
+ backFBO.syncSamplingSink(gl);
+ backFBO.bind(gl);
+ }
+ } else super.syncBackTexture();
+ }
+
+
+ @Override
+ protected void beginDraw(boolean clear0) {
+ if (!setFps) setFps(targetFps);
+ if (USE_JOGL_FBOLAYER) return;
+ super.beginDraw(clear0);
+ }
+
+
+ @Override
+ protected void endDraw(boolean clear0) {
+ if (isFBOBacked()) {
+ if (USE_JOGL_FBOLAYER) {
+ if (!clear0 && isFBOBacked() && !isMultisampled()) {
+ // Draw the back texture into the front texture, which will be used as
+ // back texture in the next frame. Otherwise flickering will occur if
+ // the sketch uses "incremental drawing" (background() not called).
+ frontFBO.bind(gl);
+ gl.glDisable(GL.GL_BLEND);
+ drawTexture(TEXTURE_2D, backTexAttach.getName(),
+ backTexAttach.getWidth(), backTexAttach.getHeight(),
+ pg.width, pg.height,
+ 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height);
+ backFBO.bind(gl);
+ }
+ } else {
+ super.endDraw(clear0);
+ }
+ }
+ }
+
+
+ @Override
+ protected boolean canDraw() {
+ return pg.initialized && pg.parent.isDisplayable();
+ }
+
+
+ @Override
+ protected void requestFocus() { }
+
+
+ @Override
+ protected void requestDraw() {
+ boolean canDraw = pg.parent.canDraw();
+ if (pg.initialized && (canDraw || prevCanDraw)) {
+ try {
+ drawLatch = new CountDownLatch(1);
+ if (WINDOW_TOOLKIT == AWT) {
+ canvasAWT.display();
+ } else if (WINDOW_TOOLKIT == NEWT) {
+ window.display();
+ }
+ try {
+ drawLatch.await(DRAW_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ if (canDraw) prevCanDraw = true;
+ else prevCanDraw = false;
+ } catch (GLException e) {
+ // Unwrap GLException so that only the causing exception is shown.
+ Throwable tr = e.getCause();
+ if (tr instanceof RuntimeException) {
+ throw (RuntimeException)tr;
+ } else {
+ throw new RuntimeException(tr);
+ }
+ }
+ }
+ }
+
+
+ @Override
+ protected void swapBuffers() {
+ if (WINDOW_TOOLKIT == AWT) {
+ canvasAWT.swapBuffers();
+ } else if (WINDOW_TOOLKIT == NEWT) {
+ window.swapBuffers();
+ }
+ }
+
+
+ @Override
+ protected void beginGL() {
+ if (gl2x != null) {
+ if (projMatrix == null) {
+ projMatrix = new float[16];
+ }
+ gl2x.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ projMatrix[ 0] = pg.projection.m00;
+ projMatrix[ 1] = pg.projection.m10;
+ projMatrix[ 2] = pg.projection.m20;
+ projMatrix[ 3] = pg.projection.m30;
+ projMatrix[ 4] = pg.projection.m01;
+ projMatrix[ 5] = pg.projection.m11;
+ projMatrix[ 6] = pg.projection.m21;
+ projMatrix[ 7] = pg.projection.m31;
+ projMatrix[ 8] = pg.projection.m02;
+ projMatrix[ 9] = pg.projection.m12;
+ projMatrix[10] = pg.projection.m22;
+ projMatrix[11] = pg.projection.m32;
+ projMatrix[12] = pg.projection.m03;
+ projMatrix[13] = pg.projection.m13;
+ projMatrix[14] = pg.projection.m23;
+ projMatrix[15] = pg.projection.m33;
+ gl2x.glLoadMatrixf(projMatrix, 0);
+
+ if (mvMatrix == null) {
+ mvMatrix = new float[16];
+ }
+ gl2x.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ mvMatrix[ 0] = pg.modelview.m00;
+ mvMatrix[ 1] = pg.modelview.m10;
+ mvMatrix[ 2] = pg.modelview.m20;
+ mvMatrix[ 3] = pg.modelview.m30;
+ mvMatrix[ 4] = pg.modelview.m01;
+ mvMatrix[ 5] = pg.modelview.m11;
+ mvMatrix[ 6] = pg.modelview.m21;
+ mvMatrix[ 7] = pg.modelview.m31;
+ mvMatrix[ 8] = pg.modelview.m02;
+ mvMatrix[ 9] = pg.modelview.m12;
+ mvMatrix[10] = pg.modelview.m22;
+ mvMatrix[11] = pg.modelview.m32;
+ mvMatrix[12] = pg.modelview.m03;
+ mvMatrix[13] = pg.modelview.m13;
+ mvMatrix[14] = pg.modelview.m23;
+ mvMatrix[15] = pg.modelview.m33;
+ gl2x.glLoadMatrixf(mvMatrix, 0);
+ }
+ }
+
+
+ @Override
+ protected boolean hasFBOs() {
+ if (context.hasBasicFBOSupport()) return true;
+ else return super.hasFBOs();
+ }
+
+
+ @Override
+ protected boolean hasShaders() {
+ if (context.hasGLSL()) return true;
+ else return super.hasShaders();
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // JOGL event listeners
+
+
+ protected class PGLListener implements GLEventListener {
+ public PGLListener() {}
+
+ @Override
+ public void display(GLAutoDrawable glDrawable) {
+ getGL(glDrawable);
+
+ if (USE_JOGL_FBOLAYER && capabilities.isFBO()) {
+ // The onscreen drawing surface is backed by an FBO layer.
+ GLFBODrawable fboDrawable = null;
+
+ if (WINDOW_TOOLKIT == AWT) {
+ GLCanvas glCanvas = (GLCanvas)glDrawable;
+ fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable();
+ } else {
+ GLWindow glWindow = (GLWindow)glDrawable;
+ fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable();
+ }
+
+ if (fboDrawable != null) {
+ backFBO = fboDrawable.getFBObject(GL.GL_BACK);
+ if (1 < numSamples) {
+ if (needSepFrontTex) {
+ // When using multisampled FBO, the back buffer is the MSAA
+ // surface so it cannot be read from. The sink buffer contains
+ // the readable 2D texture.
+ // In this case, we create an auxiliary "front" buffer that it is
+ // swapped with the sink buffer at the beginning of each frame.
+ // In this way, we always have a readable copy of the previous
+ // frame in the front texture, while the back is synchronized
+ // with the contents of the MSAA back buffer when requested.
+ if (frontFBO == null) {
+ // init
+ frontFBO = new FBObject();
+ frontFBO.reset(gl, pg.width, pg.height);
+ frontFBO.attachTexture2D(gl, 0, true);
+ sinkFBO = backFBO.getSamplingSinkFBO();
+ changedFrontTex = changedBackTex = true;
+ } else {
+ // swap
+ FBObject temp = sinkFBO;
+ sinkFBO = frontFBO;
+ frontFBO = temp;
+ backFBO.setSamplingSink(sinkFBO);
+ changedFrontTex = changedBackTex = false;
+ }
+ backTexAttach = (FBObject.TextureAttachment) sinkFBO.
+ getColorbuffer(0);
+ frontTexAttach = (FBObject.TextureAttachment)frontFBO.
+ getColorbuffer(0);
+ } else {
+ // Default setting (to save resources): the front and back
+ // textures are the same.
+ sinkFBO = backFBO.getSamplingSinkFBO();
+ backTexAttach = (FBObject.TextureAttachment) sinkFBO.
+ getColorbuffer(0);
+ frontTexAttach = backTexAttach;
+ }
+
+ } else {
+ // w/out multisampling, rendering is done on the back buffer.
+ frontFBO = fboDrawable.getFBObject(GL.GL_FRONT);
+
+ backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK);
+ frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT);
+ }
+ }
+ }
+
+ pg.parent.handleDraw();
+ drawLatch.countDown();
+ }
+
+ @Override
+ public void dispose(GLAutoDrawable adrawable) {
+ }
+
+ @Override
+ public void init(GLAutoDrawable glDrawable) {
+ getGL(glDrawable);
+
+ capabilities = glDrawable.getChosenGLCapabilities();
+ if (!hasFBOs()) {
+ throw new RuntimeException(MISSING_FBO_ERROR);
+ }
+ if (!hasShaders()) {
+ throw new RuntimeException(MISSING_GLSL_ERROR);
+ }
+ if (USE_JOGL_FBOLAYER && capabilities.isFBO()) {
+ int maxs = maxSamples();
+ numSamples = PApplet.min(capabilities.getNumSamples(), maxs);
+ }
+ }
+
+ @Override
+ public void reshape(GLAutoDrawable glDrawable, int x, int y, int w, int h) {
+ //getGL(glDrawable);
+ }
+
+ private void getGL(GLAutoDrawable glDrawable) {
+ drawable = glDrawable;
+ context = glDrawable.getContext();
+ glContext = context.hashCode();
+ glThread = Thread.currentThread();
+
+ gl = context.getGL();
+ gl2 = gl.getGL2ES2();
+ try {
+ gl2x = gl.getGL2();
+ } catch (javax.media.opengl.GLException e) {
+ gl2x = null;
+ }
+ try {
+ gl3 = gl.getGL2GL3();
+ } catch (javax.media.opengl.GLException e) {
+ gl3 = null;
+ }
+ }
+ }
+
+ protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent,
+ int peAction) {
+ int modifiers = nativeEvent.getModifiers();
+ int peModifiers = modifiers &
+ (InputEvent.SHIFT_MASK |
+ InputEvent.CTRL_MASK |
+ InputEvent.META_MASK |
+ InputEvent.ALT_MASK);
+
+ int peButton = 0;
+ if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
+ peButton = PConstants.LEFT;
+ } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
+ peButton = PConstants.CENTER;
+ } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
+ peButton = PConstants.RIGHT;
+ }
+
+ if (PApplet.platform == PConstants.MACOSX) {
+ //if (nativeEvent.isPopupTrigger()) {
+ if ((modifiers & InputEvent.CTRL_MASK) != 0) {
+ peButton = PConstants.RIGHT;
+ }
+ }
+
+ int peCount = 0;
+ if (peAction == MouseEvent.WHEEL) {
+ peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] :
+ (int)nativeEvent.getRotation()[1];
+ } else {
+ peCount = nativeEvent.getClickCount();
+ }
+
+ MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(),
+ peAction, peModifiers,
+ nativeEvent.getX(), nativeEvent.getY(),
+ peButton,
+ peCount);
+
+ pg.parent.postEvent(me);
+ }
+
+ protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent,
+ int peAction) {
+ int peModifiers = nativeEvent.getModifiers() &
+ (InputEvent.SHIFT_MASK |
+ InputEvent.CTRL_MASK |
+ InputEvent.META_MASK |
+ InputEvent.ALT_MASK);
+
+ char keyChar;
+ if ((int)nativeEvent.getKeyChar() == 0) {
+ keyChar = PConstants.CODED;
+ } else {
+ keyChar = nativeEvent.getKeyChar();
+ }
+
+ KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
+ peAction, peModifiers,
+ keyChar,
+ nativeEvent.getKeyCode());
+
+ pg.parent.postEvent(ke);
+ }
+
+ protected class NEWTWindowListener implements com.jogamp.newt.event.WindowListener {
+ @Override
+ public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) {
+ pg.parent.focusGained(null);
+ }
+
+ @Override
+ public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) {
+ pg.parent.focusLost(null);
+ }
+
+ @Override
+ public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) {
+ }
+
+ @Override
+ public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) {
+ }
+
+ @Override
+ public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) {
+ }
+
+ @Override
+ public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) {
+ }
+
+ @Override
+ public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { }
+ }
+
+ // NEWT mouse listener
+ protected class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter {
+ @Override
+ public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.PRESS);
+ }
+ @Override
+ public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.RELEASE);
+ }
+ @Override
+ public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.CLICK);
+ }
+ @Override
+ public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.DRAG);
+ }
+ @Override
+ public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.MOVE);
+ }
+ @Override
+ public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.WHEEL);
+ }
+ @Override
+ public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.ENTER);
+ }
+ @Override
+ public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
+ nativeMouseEvent(e, MouseEvent.EXIT);
+ }
+ }
+
+ // NEWT key listener
+ protected class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter {
+ @Override
+ public void keyPressed(com.jogamp.newt.event.KeyEvent e) {
+ nativeKeyEvent(e, KeyEvent.PRESS);
+ }
+ @Override
+ public void keyReleased(com.jogamp.newt.event.KeyEvent e) {
+ nativeKeyEvent(e, KeyEvent.RELEASE);
+ }
+ public void keyTyped(com.jogamp.newt.event.KeyEvent e) {
+ nativeKeyEvent(e, KeyEvent.TYPE);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Utility functions
+
+
+ @Override
+ protected void enableTexturing(int target) {
+ if (PROFILE == 2) enable(target);
+ if (target == TEXTURE_2D) {
+ texturingTargets[0] = true;
+ } else if (target == TEXTURE_RECTANGLE) {
+ texturingTargets[1] = true;
+ }
+ }
+
+
+ @Override
+ protected void disableTexturing(int target) {
+ if (PROFILE == 2) disable(target);
+ if (target == TEXTURE_2D) {
+ texturingTargets[0] = false;
+ } else if (target == TEXTURE_RECTANGLE) {
+ texturingTargets[1] = false;
+ }
+ }
+
+
+
+ @Override
+ protected int getFontAscent(Object font) {
+ FontMetrics metrics = pg.parent.getFontMetrics((Font)font);
+ return metrics.getAscent();
+ }
+
+
+ @Override
+ protected int getFontDescent(Object font) {
+ FontMetrics metrics = pg.parent.getFontMetrics((Font)font);
+ return metrics.getDescent();
+ }
+
+
+ @Override
+ protected int getTextWidth(Object font, char buffer[], int start, int stop) {
+ // maybe should use one of the newer/fancier functions for this?
+ int length = stop - start;
+ FontMetrics metrics = pg.parent.getFontMetrics((Font)font);
+ return metrics.charsWidth(buffer, start, length);
+ }
+
+
+ @Override
+ protected Object getDerivedFont(Object font, float size) {
+ return ((Font)font).deriveFont(size);
+ }
+
+
+ @Override
+ protected String[] loadVertexShader(String filename, int version) {
+ if (2 < PROFILE && version < 150) {
+ String[] fragSrc0 = pg.parent.loadStrings(filename);
+ return convertFragmentSource(fragSrc0, version, 150);
+ } else {
+ return pg.parent.loadStrings(filename);
+ }
+ }
+
+
+ @Override
+ protected String[] loadFragmentShader(String filename, int version) {
+ if (2 < PROFILE && version < 150) {
+ String[] vertSrc0 = pg.parent.loadStrings(filename);
+ return convertVertexSource(vertSrc0, version, 150);
+ } else {
+ return pg.parent.loadStrings(filename);
+ }
+ }
+
+
+ @Override
+ protected String[] loadFragmentShader(URL url, int version) {
+ try {
+ if (2 < PROFILE && version < 150) {
+ String[] fragSrc0 = PApplet.loadStrings(url.openStream());
+ return convertFragmentSource(fragSrc0, version, 150);
+ } else {
+ return PApplet.loadStrings(url.openStream());
+ }
+ } catch (IOException e) {
+ PGraphics.showException("Cannot load fragment shader " + url.getFile());
+ }
+ return null;
+ }
+
+
+ @Override
+ protected String[] loadVertexShader(URL url, int version) {
+ try {
+ if (2 < PROFILE && version < 150) {
+ String[] vertSrc0 = PApplet.loadStrings(url.openStream());
+ return convertVertexSource(vertSrc0, version, 150);
+ } else {
+ return PApplet.loadStrings(url.openStream());
+ }
+ } catch (IOException e) {
+ PGraphics.showException("Cannot load vertex shader " + url.getFile());
+ }
+ return null;
+ }
+
+
+ @Override
+ protected String[] convertFragmentSource(String[] fragSrc0,
+ int version0, int version1) {
+ String[] fragSrc = new String[fragSrc0.length + 2];
+ fragSrc[0] = "#version 150";
+ fragSrc[1] = "out vec4 fragColor;";
+ for (int i = 0; i < fragSrc0.length; i++) {
+ String line = fragSrc0[i];
+ line = line.replace("varying", "in");
+ line = line.replace("attribute", "in");
+ line = line.replace("gl_FragColor", "fragColor");
+ line = line.replace("texture", "texMap");
+ line = line.replace("texMap2D(", "texture(");
+ line = line.replace("texMap2DRect(", "texture(");
+ fragSrc[i + 2] = line;
+ }
+ return fragSrc;
+ }
+
+
+ @Override
+ protected String[] convertVertexSource(String[] vertSrc0,
+ int version0, int version1) {
+ String[] vertSrc = new String[vertSrc0.length + 1];
+ vertSrc[0] = "#version 150";
+ for (int i = 0; i < vertSrc0.length; i++) {
+ String line = vertSrc0[i];
+ line = line.replace("attribute", "in");
+ line = line.replace("varying", "out");
+ vertSrc[i + 1] = line;
+ }
+ return vertSrc;
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Tessellator
+
+
+ @Override
+ protected Tessellator createTessellator(TessellatorCallback callback) {
+ return new Tessellator(callback);
+ }
+
+
+ protected class Tessellator implements PGL.Tessellator {
+ protected GLUtessellator tess;
+ protected TessellatorCallback callback;
+ protected GLUCallback gluCallback;
+
+ public Tessellator(TessellatorCallback callback) {
+ this.callback = callback;
+ tess = GLU.gluNewTess();
+ gluCallback = new GLUCallback();
+
+ GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback);
+ GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback);
+ GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback);
+ GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback);
+ GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback);
+ }
+
+ @Override
+ public void beginPolygon() {
+ GLU.gluTessBeginPolygon(tess, null);
+ }
+
+ @Override
+ public void endPolygon() {
+ GLU.gluTessEndPolygon(tess);
+ }
+
+ @Override
+ public void setWindingRule(int rule) {
+ GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule);
+ }
+
+ @Override
+ public void beginContour() {
+ GLU.gluTessBeginContour(tess);
+ }
+
+ @Override
+ public void endContour() {
+ GLU.gluTessEndContour(tess);
+ }
+
+ @Override
+ public void addVertex(double[] v) {
+ GLU.gluTessVertex(tess, v, 0, v);
+ }
+
+ protected class GLUCallback extends GLUtessellatorCallbackAdapter {
+ @Override
+ public void begin(int type) {
+ callback.begin(type);
+ }
+
+ @Override
+ public void end() {
+ callback.end();
+ }
+
+ @Override
+ public void vertex(Object data) {
+ callback.vertex(data);
+ }
+
+ @Override
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData) {
+ callback.combine(coords, data, weight, outData);
+ }
+
+ @Override
+ public void error(int errnum) {
+ callback.error(errnum);
+ }
+ }
+ }
+
+
+ @Override
+ protected String tessError(int err) {
+ return glu.gluErrorString(err);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Font outline
+
+
+ static {
+ SHAPE_TEXT_SUPPORTED = true;
+ SEG_MOVETO = PathIterator.SEG_MOVETO;
+ SEG_LINETO = PathIterator.SEG_LINETO;
+ SEG_QUADTO = PathIterator.SEG_QUADTO;
+ SEG_CUBICTO = PathIterator.SEG_CUBICTO;
+ SEG_CLOSE = PathIterator.SEG_CLOSE;
+ }
+
+
+ @Override
+ protected FontOutline createFontOutline(char ch, Object font) {
+ return new FontOutline(ch, font);
+ }
+
+
+ protected class FontOutline implements PGL.FontOutline {
+ PathIterator iter;
+
+ public FontOutline(char ch, Object font) {
+ char textArray[] = new char[] { ch };
+ Graphics2D graphics = (Graphics2D) pg.parent.getGraphics();
+ FontRenderContext frc = graphics.getFontRenderContext();
+ GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray);
+ Shape shp = gv.getOutline();
+ iter = shp.getPathIterator(null);
+ }
+
+ public boolean isDone() {
+ return iter.isDone();
+ }
+
+ public int currentSegment(float coords[]) {
+ return iter.currentSegment(coords);
+ }
+
+ public void next() {
+ iter.next();
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Constants
+
+ static {
+ FALSE = GL.GL_FALSE;
+ TRUE = GL.GL_TRUE;
+
+ INT = GL2ES2.GL_INT;
+ BYTE = GL.GL_BYTE;
+ SHORT = GL.GL_SHORT;
+ FLOAT = GL.GL_FLOAT;
+ BOOL = GL2ES2.GL_BOOL;
+ UNSIGNED_INT = GL.GL_UNSIGNED_INT;
+ UNSIGNED_BYTE = GL.GL_UNSIGNED_BYTE;
+ UNSIGNED_SHORT = GL.GL_UNSIGNED_SHORT;
+
+ RGB = GL.GL_RGB;
+ RGBA = GL.GL_RGBA;
+ ALPHA = GL.GL_ALPHA;
+ LUMINANCE = GL.GL_LUMINANCE;
+ LUMINANCE_ALPHA = GL.GL_LUMINANCE_ALPHA;
+
+ UNSIGNED_SHORT_5_6_5 = GL.GL_UNSIGNED_SHORT_5_6_5;
+ UNSIGNED_SHORT_4_4_4_4 = GL.GL_UNSIGNED_SHORT_4_4_4_4;
+ UNSIGNED_SHORT_5_5_5_1 = GL.GL_UNSIGNED_SHORT_5_5_5_1;
+
+ RGBA4 = GL.GL_RGBA4;
+ RGB5_A1 = GL.GL_RGB5_A1;
+ RGB565 = GL.GL_RGB565;
+ RGB8 = GL.GL_RGB8;
+ RGBA8 = GL.GL_RGBA8;
+ ALPHA8 = GL.GL_ALPHA8;
+
+ READ_ONLY = GL2GL3.GL_READ_ONLY;
+ WRITE_ONLY = GL.GL_WRITE_ONLY;
+ READ_WRITE = GL2GL3.GL_READ_WRITE;
+
+ TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO;
+ TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD;
+
+ GENERATE_MIPMAP_HINT = GL.GL_GENERATE_MIPMAP_HINT;
+ FASTEST = GL.GL_FASTEST;
+ NICEST = GL.GL_NICEST;
+ DONT_CARE = GL.GL_DONT_CARE;
+
+ VENDOR = GL.GL_VENDOR;
+ RENDERER = GL.GL_RENDERER;
+ VERSION = GL.GL_VERSION;
+ EXTENSIONS = GL.GL_EXTENSIONS;
+ SHADING_LANGUAGE_VERSION = GL2ES2.GL_SHADING_LANGUAGE_VERSION;
+
+ MAX_SAMPLES = GL2ES3.GL_MAX_SAMPLES;
+ SAMPLES = GL.GL_SAMPLES;
+
+ ALIASED_LINE_WIDTH_RANGE = GL.GL_ALIASED_LINE_WIDTH_RANGE;
+ ALIASED_POINT_SIZE_RANGE = GL.GL_ALIASED_POINT_SIZE_RANGE;
+
+ DEPTH_BITS = GL.GL_DEPTH_BITS;
+ STENCIL_BITS = GL.GL_STENCIL_BITS;
+
+ CCW = GL.GL_CCW;
+ CW = GL.GL_CW;
+
+ VIEWPORT = GL.GL_VIEWPORT;
+
+ ARRAY_BUFFER = GL.GL_ARRAY_BUFFER;
+ ELEMENT_ARRAY_BUFFER = GL.GL_ELEMENT_ARRAY_BUFFER;
+
+ MAX_VERTEX_ATTRIBS = GL2ES2.GL_MAX_VERTEX_ATTRIBS;
+
+ STATIC_DRAW = GL.GL_STATIC_DRAW;
+ DYNAMIC_DRAW = GL.GL_DYNAMIC_DRAW;
+ STREAM_DRAW = GL2ES2.GL_STREAM_DRAW;
+
+ BUFFER_SIZE = GL.GL_BUFFER_SIZE;
+ BUFFER_USAGE = GL.GL_BUFFER_USAGE;
+
+ POINTS = GL.GL_POINTS;
+ LINE_STRIP = GL.GL_LINE_STRIP;
+ LINE_LOOP = GL.GL_LINE_LOOP;
+ LINES = GL.GL_LINES;
+ TRIANGLE_FAN = GL.GL_TRIANGLE_FAN;
+ TRIANGLE_STRIP = GL.GL_TRIANGLE_STRIP;
+ TRIANGLES = GL.GL_TRIANGLES;
+
+ CULL_FACE = GL.GL_CULL_FACE;
+ FRONT = GL.GL_FRONT;
+ BACK = GL.GL_BACK;
+ FRONT_AND_BACK = GL.GL_FRONT_AND_BACK;
+
+ POLYGON_OFFSET_FILL = GL.GL_POLYGON_OFFSET_FILL;
+
+ UNPACK_ALIGNMENT = GL.GL_UNPACK_ALIGNMENT;
+ PACK_ALIGNMENT = GL.GL_PACK_ALIGNMENT;
+
+ TEXTURE_2D = GL.GL_TEXTURE_2D;
+ TEXTURE_RECTANGLE = GL2GL3.GL_TEXTURE_RECTANGLE;
+
+ TEXTURE_BINDING_2D = GL.GL_TEXTURE_BINDING_2D;
+ TEXTURE_BINDING_RECTANGLE = GL2GL3.GL_TEXTURE_BINDING_RECTANGLE;
+
+ MAX_TEXTURE_SIZE = GL.GL_MAX_TEXTURE_SIZE;
+ TEXTURE_MAX_ANISOTROPY = GL.GL_TEXTURE_MAX_ANISOTROPY_EXT;
+ MAX_TEXTURE_MAX_ANISOTROPY = GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
+
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+ MAX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_TEXTURE_IMAGE_UNITS;
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
+
+ NUM_COMPRESSED_TEXTURE_FORMATS = GL.GL_NUM_COMPRESSED_TEXTURE_FORMATS;
+ COMPRESSED_TEXTURE_FORMATS = GL.GL_COMPRESSED_TEXTURE_FORMATS;
+
+ NEAREST = GL.GL_NEAREST;
+ LINEAR = GL.GL_LINEAR;
+ LINEAR_MIPMAP_NEAREST = GL.GL_LINEAR_MIPMAP_NEAREST;
+ LINEAR_MIPMAP_LINEAR = GL.GL_LINEAR_MIPMAP_LINEAR;
+
+ CLAMP_TO_EDGE = GL.GL_CLAMP_TO_EDGE;
+ REPEAT = GL.GL_REPEAT;
+
+ TEXTURE0 = GL.GL_TEXTURE0;
+ TEXTURE1 = GL.GL_TEXTURE1;
+ TEXTURE2 = GL.GL_TEXTURE2;
+ TEXTURE3 = GL.GL_TEXTURE3;
+ TEXTURE_MIN_FILTER = GL.GL_TEXTURE_MIN_FILTER;
+ TEXTURE_MAG_FILTER = GL.GL_TEXTURE_MAG_FILTER;
+ TEXTURE_WRAP_S = GL.GL_TEXTURE_WRAP_S;
+ TEXTURE_WRAP_T = GL.GL_TEXTURE_WRAP_T;
+ TEXTURE_WRAP_R = GL2ES2.GL_TEXTURE_WRAP_R;
+
+ TEXTURE_CUBE_MAP = GL.GL_TEXTURE_CUBE_MAP;
+ TEXTURE_CUBE_MAP_POSITIVE_X = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ TEXTURE_CUBE_MAP_POSITIVE_Y = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+ TEXTURE_CUBE_MAP_POSITIVE_Z = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+ TEXTURE_CUBE_MAP_NEGATIVE_X = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
+ TEXTURE_CUBE_MAP_NEGATIVE_Y = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ TEXTURE_CUBE_MAP_NEGATIVE_Z = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+
+ VERTEX_SHADER = GL2ES2.GL_VERTEX_SHADER;
+ FRAGMENT_SHADER = GL2ES2.GL_FRAGMENT_SHADER;
+ INFO_LOG_LENGTH = GL2ES2.GL_INFO_LOG_LENGTH;
+ SHADER_SOURCE_LENGTH = GL2ES2.GL_SHADER_SOURCE_LENGTH;
+ COMPILE_STATUS = GL2ES2.GL_COMPILE_STATUS;
+ LINK_STATUS = GL2ES2.GL_LINK_STATUS;
+ VALIDATE_STATUS = GL2ES2.GL_VALIDATE_STATUS;
+ SHADER_TYPE = GL2ES2.GL_SHADER_TYPE;
+ DELETE_STATUS = GL2ES2.GL_DELETE_STATUS;
+
+ FLOAT_VEC2 = GL2ES2.GL_FLOAT_VEC2;
+ FLOAT_VEC3 = GL2ES2.GL_FLOAT_VEC3;
+ FLOAT_VEC4 = GL2ES2.GL_FLOAT_VEC4;
+ FLOAT_MAT2 = GL2ES2.GL_FLOAT_MAT2;
+ FLOAT_MAT3 = GL2ES2.GL_FLOAT_MAT3;
+ FLOAT_MAT4 = GL2ES2.GL_FLOAT_MAT4;
+ INT_VEC2 = GL2ES2.GL_INT_VEC2;
+ INT_VEC3 = GL2ES2.GL_INT_VEC3;
+ INT_VEC4 = GL2ES2.GL_INT_VEC4;
+ BOOL_VEC2 = GL2ES2.GL_BOOL_VEC2;
+ BOOL_VEC3 = GL2ES2.GL_BOOL_VEC3;
+ BOOL_VEC4 = GL2ES2.GL_BOOL_VEC4;
+ SAMPLER_2D = GL2ES2.GL_SAMPLER_2D;
+ SAMPLER_CUBE = GL2ES2.GL_SAMPLER_CUBE;
+
+ LOW_FLOAT = GL2ES2.GL_LOW_FLOAT;
+ MEDIUM_FLOAT = GL2ES2.GL_MEDIUM_FLOAT;
+ HIGH_FLOAT = GL2ES2.GL_HIGH_FLOAT;
+ LOW_INT = GL2ES2.GL_LOW_INT;
+ MEDIUM_INT = GL2ES2.GL_MEDIUM_INT;
+ HIGH_INT = GL2ES2.GL_HIGH_INT;
+
+ CURRENT_VERTEX_ATTRIB = GL2ES2.GL_CURRENT_VERTEX_ATTRIB;
+
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING;
+ VERTEX_ATTRIB_ARRAY_ENABLED = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_ENABLED;
+ VERTEX_ATTRIB_ARRAY_SIZE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_SIZE;
+ VERTEX_ATTRIB_ARRAY_STRIDE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_STRIDE;
+ VERTEX_ATTRIB_ARRAY_TYPE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_TYPE;
+ VERTEX_ATTRIB_ARRAY_NORMALIZED = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED;
+ VERTEX_ATTRIB_ARRAY_POINTER = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_POINTER;
+
+ BLEND = GL.GL_BLEND;
+ ONE = GL.GL_ONE;
+ ZERO = GL.GL_ZERO;
+ SRC_ALPHA = GL.GL_SRC_ALPHA;
+ DST_ALPHA = GL.GL_DST_ALPHA;
+ ONE_MINUS_SRC_ALPHA = GL.GL_ONE_MINUS_SRC_ALPHA;
+ ONE_MINUS_DST_COLOR = GL.GL_ONE_MINUS_DST_COLOR;
+ ONE_MINUS_SRC_COLOR = GL.GL_ONE_MINUS_SRC_COLOR;
+ DST_COLOR = GL.GL_DST_COLOR;
+ SRC_COLOR = GL.GL_SRC_COLOR;
+
+ SAMPLE_ALPHA_TO_COVERAGE = GL.GL_SAMPLE_ALPHA_TO_COVERAGE;
+ SAMPLE_COVERAGE = GL.GL_SAMPLE_COVERAGE;
+
+ KEEP = GL.GL_KEEP;
+ REPLACE = GL.GL_REPLACE;
+ INCR = GL.GL_INCR;
+ DECR = GL.GL_DECR;
+ INVERT = GL.GL_INVERT;
+ INCR_WRAP = GL.GL_INCR_WRAP;
+ DECR_WRAP = GL.GL_DECR_WRAP;
+ NEVER = GL.GL_NEVER;
+ ALWAYS = GL.GL_ALWAYS;
+
+ EQUAL = GL.GL_EQUAL;
+ LESS = GL.GL_LESS;
+ LEQUAL = GL.GL_LEQUAL;
+ GREATER = GL.GL_GREATER;
+ GEQUAL = GL.GL_GEQUAL;
+ NOTEQUAL = GL.GL_NOTEQUAL;
+
+ FUNC_ADD = GL.GL_FUNC_ADD;
+ FUNC_MIN = GL2ES3.GL_MIN;
+ FUNC_MAX = GL2ES3.GL_MAX;
+ FUNC_REVERSE_SUBTRACT = GL.GL_FUNC_REVERSE_SUBTRACT;
+ FUNC_SUBTRACT = GL.GL_FUNC_SUBTRACT;
+
+ DITHER = GL.GL_DITHER;
+
+ CONSTANT_COLOR = GL2ES2.GL_CONSTANT_COLOR;
+ CONSTANT_ALPHA = GL2ES2.GL_CONSTANT_ALPHA;
+ ONE_MINUS_CONSTANT_COLOR = GL2ES2.GL_ONE_MINUS_CONSTANT_COLOR;
+ ONE_MINUS_CONSTANT_ALPHA = GL2ES2.GL_ONE_MINUS_CONSTANT_ALPHA;
+ SRC_ALPHA_SATURATE = GL.GL_SRC_ALPHA_SATURATE;
+
+ SCISSOR_TEST = GL.GL_SCISSOR_TEST;
+ STENCIL_TEST = GL.GL_STENCIL_TEST;
+ DEPTH_TEST = GL.GL_DEPTH_TEST;
+ DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK;
+ ALPHA_TEST = GL2ES1.GL_ALPHA_TEST;
+
+ COLOR_BUFFER_BIT = GL.GL_COLOR_BUFFER_BIT;
+ DEPTH_BUFFER_BIT = GL.GL_DEPTH_BUFFER_BIT;
+ STENCIL_BUFFER_BIT = GL.GL_STENCIL_BUFFER_BIT;
+
+ FRAMEBUFFER = GL.GL_FRAMEBUFFER;
+ COLOR_ATTACHMENT0 = GL.GL_COLOR_ATTACHMENT0;
+ COLOR_ATTACHMENT1 = GL2ES2.GL_COLOR_ATTACHMENT1;
+ COLOR_ATTACHMENT2 = GL2ES2.GL_COLOR_ATTACHMENT2;
+ COLOR_ATTACHMENT3 = GL2ES2.GL_COLOR_ATTACHMENT3;
+ RENDERBUFFER = GL.GL_RENDERBUFFER;
+ DEPTH_ATTACHMENT = GL.GL_DEPTH_ATTACHMENT;
+ STENCIL_ATTACHMENT = GL.GL_STENCIL_ATTACHMENT;
+ READ_FRAMEBUFFER = GL2ES3.GL_READ_FRAMEBUFFER;
+ DRAW_FRAMEBUFFER = GL2ES3.GL_DRAW_FRAMEBUFFER;
+
+ RGBA8 = GL.GL_RGBA8;
+ DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8;
+
+ DEPTH_COMPONENT = GL2ES2.GL_DEPTH_COMPONENT;
+ DEPTH_COMPONENT16 = GL.GL_DEPTH_COMPONENT16;
+ DEPTH_COMPONENT24 = GL.GL_DEPTH_COMPONENT24;
+ DEPTH_COMPONENT32 = GL.GL_DEPTH_COMPONENT32;
+
+ STENCIL_INDEX = GL2ES2.GL_STENCIL_INDEX;
+ STENCIL_INDEX1 = GL.GL_STENCIL_INDEX1;
+ STENCIL_INDEX4 = GL.GL_STENCIL_INDEX4;
+ STENCIL_INDEX8 = GL.GL_STENCIL_INDEX8;
+
+ DEPTH_STENCIL = GL.GL_DEPTH_STENCIL;
+
+ FRAMEBUFFER_COMPLETE = GL.GL_FRAMEBUFFER_COMPLETE;
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ FRAMEBUFFER_INCOMPLETE_FORMATS = GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS;
+ FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
+ FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
+ FRAMEBUFFER_UNSUPPORTED = GL.GL_FRAMEBUFFER_UNSUPPORTED;
+
+ FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE;
+ FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL;
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE;
+
+ RENDERBUFFER_WIDTH = GL.GL_RENDERBUFFER_WIDTH;
+ RENDERBUFFER_HEIGHT = GL.GL_RENDERBUFFER_HEIGHT;
+ RENDERBUFFER_RED_SIZE = GL.GL_RENDERBUFFER_RED_SIZE;
+ RENDERBUFFER_GREEN_SIZE = GL.GL_RENDERBUFFER_GREEN_SIZE;
+ RENDERBUFFER_BLUE_SIZE = GL.GL_RENDERBUFFER_BLUE_SIZE;
+ RENDERBUFFER_ALPHA_SIZE = GL.GL_RENDERBUFFER_ALPHA_SIZE;
+ RENDERBUFFER_DEPTH_SIZE = GL.GL_RENDERBUFFER_DEPTH_SIZE;
+ RENDERBUFFER_STENCIL_SIZE = GL.GL_RENDERBUFFER_STENCIL_SIZE;
+ RENDERBUFFER_INTERNAL_FORMAT = GL.GL_RENDERBUFFER_INTERNAL_FORMAT;
+
+ MULTISAMPLE = GL.GL_MULTISAMPLE;
+ POINT_SMOOTH = GL2ES1.GL_POINT_SMOOTH;
+ LINE_SMOOTH = GL.GL_LINE_SMOOTH;
+ POLYGON_SMOOTH = GL2GL3.GL_POLYGON_SMOOTH;
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Special Functions
+
+ @Override
+ public void flush() {
+ gl.glFlush();
+ }
+
+ @Override
+ public void finish() {
+ gl.glFinish();
+ }
+
+ @Override
+ public void hint(int target, int hint) {
+ gl.glHint(target, hint);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // State and State Requests
+
+ @Override
+ public void enable(int value) {
+ if (-1 < value) {
+ gl.glEnable(value);
+ }
+ }
+
+ @Override
+ public void disable(int value) {
+ if (-1 < value) {
+ gl.glDisable(value);
+ }
+ }
+
+ @Override
+ public void getBooleanv(int value, IntBuffer data) {
+ if (-1 < value) {
+ if (byteBuffer.capacity() < data.capacity()) {
+ byteBuffer = allocateDirectByteBuffer(data.capacity());
+ }
+ gl.glGetBooleanv(value, byteBuffer);
+ for (int i = 0; i < data.capacity(); i++) {
+ data.put(i, byteBuffer.get(i));
+ }
+ } else {
+ fillIntBuffer(data, 0, data.capacity() - 1, 0);
+ }
+ }
+
+ @Override
+ public void getIntegerv(int value, IntBuffer data) {
+ if (-1 < value) {
+ gl.glGetIntegerv(value, data);
+ } else {
+ fillIntBuffer(data, 0, data.capacity() - 1, 0);
+ }
+ }
+
+ @Override
+ public void getFloatv(int value, FloatBuffer data) {
+ if (-1 < value) {
+ gl.glGetFloatv(value, data);
+ } else {
+ fillFloatBuffer(data, 0, data.capacity() - 1, 0);
+ }
+ }
+
+ @Override
+ public boolean isEnabled(int value) {
+ return gl.glIsEnabled(value);
+ }
+
+ @Override
+ public String getString(int name) {
+ return gl.glGetString(name);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Error Handling
+
+ @Override
+ public int getError() {
+ return gl.glGetError();
+ }
+
+ @Override
+ public String errorString(int err) {
+ return glu.gluErrorString(err);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Buffer Objects
+
+ @Override
+ public void genBuffers(int n, IntBuffer buffers) {
+ gl.glGenBuffers(n, buffers);
+ }
+
+ @Override
+ public void deleteBuffers(int n, IntBuffer buffers) {
+ gl.glDeleteBuffers(n, buffers);
+ }
+
+ @Override
+ public void bindBuffer(int target, int buffer) {
+ gl.glBindBuffer(target, buffer);
+ }
+
+ @Override
+ public void bufferData(int target, int size, Buffer data, int usage) {
+ gl.glBufferData(target, size, data, usage);
+ }
+
+ @Override
+ public void bufferSubData(int target, int offset, int size, Buffer data) {
+ gl.glBufferSubData(target, offset, size, data);
+ }
+
+ @Override
+ public void isBuffer(int buffer) {
+ gl.glIsBuffer(buffer);
+ }
+
+ @Override
+ public void getBufferParameteriv(int target, int value, IntBuffer data) {
+ gl.glGetBufferParameteriv(target, value, data);
+ }
+
+ @Override
+ public ByteBuffer mapBuffer(int target, int access) {
+ return gl2.glMapBuffer(target, access);
+ }
+
+ @Override
+ public ByteBuffer mapBufferRange(int target, int offset, int length, int access) {
+ if (gl2x != null) {
+ return gl2x.glMapBufferRange(target, offset, length, access);
+ } else if (gl3 != null) {
+ return gl3.glMapBufferRange(target, offset, length, access);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glMapBufferRange()"));
+ }
+ }
+
+ @Override
+ public void unmapBuffer(int target) {
+ gl2.glUnmapBuffer(target);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Viewport and Clipping
+
+ @Override
+ public void depthRangef(float n, float f) {
+ gl.glDepthRangef(n, f);
+ }
+
+ @Override
+ public void viewport(int x, int y, int w, int h) {
+ gl.glViewport(x, y, w, h);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Reading Pixels
+
+ @Override
+ protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) {
+ gl.glReadPixels(x, y, width, height, format, type, buffer);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Vertices
+
+ @Override
+ public void vertexAttrib1f(int index, float value) {
+ gl2.glVertexAttrib1f(index, value);
+ }
+
+ @Override
+ public void vertexAttrib2f(int index, float value0, float value1) {
+ gl2.glVertexAttrib2f(index, value0, value1);
+ }
+
+ @Override
+ public void vertexAttrib3f(int index, float value0, float value1, float value2) {
+ gl2.glVertexAttrib3f(index, value0, value1, value2);
+ }
+
+ @Override
+ public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) {
+ gl2.glVertexAttrib4f(index, value0, value1, value2, value3);
+ }
+
+ @Override
+ public void vertexAttrib1fv(int index, FloatBuffer values) {
+ gl2.glVertexAttrib1fv(index, values);
+ }
+
+ @Override
+ public void vertexAttrib2fv(int index, FloatBuffer values) {
+ gl2.glVertexAttrib2fv(index, values);
+ }
+
+ @Override
+ public void vertexAttrib3fv(int index, FloatBuffer values) {
+ gl2.glVertexAttrib3fv(index, values);
+ }
+
+ @Override
+ public void vertexAttri4fv(int index, FloatBuffer values) {
+ gl2.glVertexAttrib4fv(index, values);
+ }
+
+ @Override
+ public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) {
+ gl2.glVertexAttribPointer(index, size, type, normalized, stride, offset);
+ }
+
+ @Override
+ public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) {
+ if (gl2x != null) {
+ gl2x.glVertexAttribPointer(index, size, type, normalized, stride, data);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glVertexAttribPointer()"));
+ }
+ }
+
+ @Override
+ public void enableVertexAttribArray(int index) {
+ gl2.glEnableVertexAttribArray(index);
+ }
+
+ @Override
+ public void disableVertexAttribArray(int index) {
+ gl2.glDisableVertexAttribArray(index);
+ }
+
+ @Override
+ public void drawArrays(int mode, int first, int count) {
+ gl.glDrawArrays(mode, first, count);
+ }
+
+ @Override
+ public void drawElements(int mode, int count, int type, int offset) {
+ gl.glDrawElements(mode, count, type, offset);
+ }
+
+ @Override
+ public void drawElements(int mode, int count, int type, Buffer indices) {
+ if (gl2x != null) {
+ gl2x.glDrawElements(mode, count, type, indices);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glDrawElements()"));
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Rasterization
+
+ @Override
+ public void lineWidth(float width) {
+ gl.glLineWidth(width);
+ }
+
+ @Override
+ public void frontFace(int dir) {
+ gl.glFrontFace(dir);
+ }
+
+ @Override
+ public void cullFace(int mode) {
+ gl.glCullFace(mode);
+ }
+
+ @Override
+ public void polygonOffset(float factor, float units) {
+ gl.glPolygonOffset(factor, units);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Pixel Rectangles
+
+ @Override
+ public void pixelStorei(int pname, int param) {
+ gl.glPixelStorei(pname, param);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Texturing
+
+ @Override
+ public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) {
+ gl.glTexImage2D(target, level, internalFormat, width, height, border, format, type, data);
+ }
+
+ @Override
+ public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) {
+ gl.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
+ }
+
+ @Override
+ public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data) {
+ gl.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, data);
+ }
+
+ @Override
+ public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height) {
+ gl.glCopyTexSubImage2D(target, level, x, y, xOffset, xOffset, width, height);
+ }
+
+ @Override
+ public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data) {
+ gl.glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data);
+ }
+
+ @Override
+ public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data) {
+ gl.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, imageSize, data);
+ }
+
+ @Override
+ public void texParameteri(int target, int pname, int param) {
+ gl.glTexParameteri(target, pname, param);
+ }
+
+ @Override
+ public void texParameterf(int target, int pname, float param) {
+ gl.glTexParameterf(target, pname, param);
+ }
+
+ @Override
+ public void texParameteriv(int target, int pname, IntBuffer params) {
+ gl.glTexParameteriv(target, pname, params);
+ }
+
+ @Override
+ public void texParameterfv(int target, int pname, FloatBuffer params) {
+ gl.glTexParameterfv(target, pname, params);
+ }
+
+ @Override
+ public void generateMipmap(int target) {
+ gl.glGenerateMipmap(target);
+ }
+
+ @Override
+ public void genTextures(int n, IntBuffer textures) {
+ gl.glGenTextures(n, textures);
+ }
+
+ @Override
+ public void deleteTextures(int n, IntBuffer textures) {
+ gl.glDeleteTextures(n, textures);
+ }
+
+ @Override
+ public void getTexParameteriv(int target, int pname, IntBuffer params) {
+ gl.glGetTexParameteriv(target, pname, params);
+ }
+
+ @Override
+ public void getTexParameterfv(int target, int pname, FloatBuffer params) {
+ gl.glGetTexParameterfv(target, pname, params);
+ }
+
+ @Override
+ public boolean isTexture(int texture) {
+ return gl.glIsTexture(texture);
+ }
+
+ @Override
+ protected void activeTextureImpl(int texture) {
+ gl.glActiveTexture(texture);
+ }
+
+ @Override
+ protected void bindTextureImpl(int target, int texture) {
+ gl.glBindTexture(target, texture);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Shaders and Programs
+
+ @Override
+ public int createShader(int type) {
+ return gl2.glCreateShader(type);
+ }
+
+ @Override
+ public void shaderSource(int shader, String source) {
+ gl2.glShaderSource(shader, 1, new String[] { source }, (int[]) null, 0);
+ }
+
+ @Override
+ public void compileShader(int shader) {
+ gl2.glCompileShader(shader);
+ }
+
+ @Override
+ public void releaseShaderCompiler() {
+ gl2.glReleaseShaderCompiler();
+ }
+
+ @Override
+ public void deleteShader(int shader) {
+ gl2.glDeleteShader(shader);
+ }
+
+ @Override
+ public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) {
+ gl2.glShaderBinary(count, shaders, binaryFormat, binary, length);
+ }
+
+ @Override
+ public int createProgram() {
+ return gl2.glCreateProgram();
+ }
+
+ @Override
+ public void attachShader(int program, int shader) {
+ gl2.glAttachShader(program, shader);
+ }
+
+ @Override
+ public void detachShader(int program, int shader) {
+ gl2.glDetachShader(program, shader);
+ }
+
+ @Override
+ public void linkProgram(int program) {
+ gl2.glLinkProgram(program);
+ }
+
+ @Override
+ public void useProgram(int program) {
+ gl2.glUseProgram(program);
+ }
+
+ @Override
+ public void deleteProgram(int program) {
+ gl2.glDeleteProgram(program);
+ }
+
+ @Override
+ public String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type) {
+ int[] tmp = {0, 0, 0};
+ byte[] namebuf = new byte[1024];
+ gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0);
+ size.put(tmp[1]);
+ type.put(tmp[2]);
+ String name = new String(namebuf, 0, tmp[0]);
+ return name;
+ }
+
+ @Override
+ public int getAttribLocation(int program, String name) {
+ return gl2.glGetAttribLocation(program, name);
+ }
+
+ @Override
+ public void bindAttribLocation(int program, int index, String name) {
+ gl2.glBindAttribLocation(program, index, name);
+ }
+
+ @Override
+ public int getUniformLocation(int program, String name) {
+ return gl2.glGetUniformLocation(program, name);
+ }
+
+ @Override
+ public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) {
+ int[] tmp= {0, 0, 0};
+ byte[] namebuf = new byte[1024];
+ gl2.glGetActiveUniform(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0);
+ size.put(tmp[1]);
+ type.put(tmp[2]);
+ String name = new String(namebuf, 0, tmp[0]);
+ return name;
+ }
+
+ @Override
+ public void uniform1i(int location, int value) {
+ gl2.glUniform1i(location, value);
+ }
+
+ @Override
+ public void uniform2i(int location, int value0, int value1) {
+ gl2.glUniform2i(location, value0, value1);
+ }
+
+ @Override
+ public void uniform3i(int location, int value0, int value1, int value2) {
+ gl2.glUniform3i(location, value0, value1, value2);
+ }
+
+ @Override
+ public void uniform4i(int location, int value0, int value1, int value2, int value3) {
+ gl2.glUniform4i(location, value0, value1, value2, value3);
+ }
+
+ @Override
+ public void uniform1f(int location, float value) {
+ gl2.glUniform1f(location, value);
+ }
+
+ @Override
+ public void uniform2f(int location, float value0, float value1) {
+ gl2.glUniform2f(location, value0, value1);
+ }
+
+ @Override
+ public void uniform3f(int location, float value0, float value1, float value2) {
+ gl2.glUniform3f(location, value0, value1, value2);
+ }
+
+ @Override
+ public void uniform4f(int location, float value0, float value1, float value2, float value3) {
+ gl2.glUniform4f(location, value0, value1, value2, value3);
+ }
+
+ @Override
+ public void uniform1iv(int location, int count, IntBuffer v) {
+ gl2.glUniform1iv(location, count, v);
+ }
+
+ @Override
+ public void uniform2iv(int location, int count, IntBuffer v) {
+ gl2.glUniform2iv(location, count, v);
+ }
+
+ @Override
+ public void uniform3iv(int location, int count, IntBuffer v) {
+ gl2.glUniform3iv(location, count, v);
+ }
+
+ @Override
+ public void uniform4iv(int location, int count, IntBuffer v) {
+ gl2.glUniform4iv(location, count, v);
+ }
+
+ @Override
+ public void uniform1fv(int location, int count, FloatBuffer v) {
+ gl2.glUniform1fv(location, count, v);
+ }
+
+ @Override
+ public void uniform2fv(int location, int count, FloatBuffer v) {
+ gl2.glUniform2fv(location, count, v);
+ }
+
+ @Override
+ public void uniform3fv(int location, int count, FloatBuffer v) {
+ gl2.glUniform3fv(location, count, v);
+ }
+
+ @Override
+ public void uniform4fv(int location, int count, FloatBuffer v) {
+ gl2.glUniform4fv(location, count, v);
+ }
+
+ @Override
+ public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) {
+ gl2.glUniformMatrix2fv(location, count, transpose, mat);
+ }
+
+ @Override
+ public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) {
+ gl2.glUniformMatrix3fv(location, count, transpose, mat);
+ }
+
+ @Override
+ public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) {
+ gl2.glUniformMatrix4fv(location, count, transpose, mat);
+ }
+
+ @Override
+ public void validateProgram(int program) {
+ gl2.glValidateProgram(program);
+ }
+
+ @Override
+ public boolean isShader(int shader) {
+ return gl2.glIsShader(shader);
+ }
+
+ @Override
+ public void getShaderiv(int shader, int pname, IntBuffer params) {
+ gl2.glGetShaderiv(shader, pname, params);
+ }
+
+ @Override
+ public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) {
+ gl2.glGetAttachedShaders(program, maxCount, count, shaders);
+ }
+
+ @Override
+ public String getShaderInfoLog(int shader) {
+ int[] val = { 0 };
+ gl2.glGetShaderiv(shader, GL2ES2.GL_INFO_LOG_LENGTH, val, 0);
+ int length = val[0];
+
+ byte[] log = new byte[length];
+ gl2.glGetShaderInfoLog(shader, length, val, 0, log, 0);
+ return new String(log);
+ }
+
+ @Override
+ public String getShaderSource(int shader) {
+ int[] len = {0};
+ byte[] buf = new byte[1024];
+ gl2.glGetShaderSource(shader, 1024, len, 0, buf, 0);
+ return new String(buf, 0, len[0]);
+ }
+
+ @Override
+ public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) {
+ gl2.glGetShaderPrecisionFormat(shaderType, precisionType, range, precision);
+ }
+
+ @Override
+ public void getVertexAttribfv(int index, int pname, FloatBuffer params) {
+ gl2.glGetVertexAttribfv(index, pname, params);
+ }
+
+ @Override
+ public void getVertexAttribiv(int index, int pname, IntBuffer params) {
+ gl2.glGetVertexAttribiv(index, pname, params);
+ }
+
+ @Override
+ public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetVertexAttribPointerv()"));
+ }
+
+ @Override
+ public void getUniformfv(int program, int location, FloatBuffer params) {
+ gl2.glGetUniformfv(program, location, params);
+ }
+
+ @Override
+ public void getUniformiv(int program, int location, IntBuffer params) {
+ gl2.glGetUniformiv(program, location, params);
+ }
+
+ @Override
+ public boolean isProgram(int program) {
+ return gl2.glIsProgram(program);
+ }
+
+ @Override
+ public void getProgramiv(int program, int pname, IntBuffer params) {
+ gl2.glGetProgramiv(program, pname, params);
+ }
+
+ @Override
+ public String getProgramInfoLog(int program) {
+ int[] val = { 0 };
+ gl2.glGetShaderiv(program, GL2ES2.GL_INFO_LOG_LENGTH, val, 0);
+ int length = val[0];
+
+ if (0 < length) {
+ byte[] log = new byte[length];
+ gl2.glGetProgramInfoLog(program, length, val, 0, log, 0);
+ return new String(log);
+ } else {
+ return "Unknow error";
+ }
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Per-Fragment Operations
+
+ @Override
+ public void scissor(int x, int y, int w, int h) {
+ gl.glScissor(x, y, w, h);
+ }
+
+ @Override
+ public void sampleCoverage(float value, boolean invert) {
+ gl2.glSampleCoverage(value, invert);
+ }
+
+ @Override
+ public void stencilFunc(int func, int ref, int mask) {
+ gl2.glStencilFunc(func, ref, mask);
+ }
+
+ @Override
+ public void stencilFuncSeparate(int face, int func, int ref, int mask) {
+ gl2.glStencilFuncSeparate(face, func, ref, mask);
+ }
+
+ @Override
+ public void stencilOp(int sfail, int dpfail, int dppass) {
+ gl2.glStencilOp(sfail, dpfail, dppass);
+ }
+
+ @Override
+ public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) {
+ gl2.glStencilOpSeparate(face, sfail, dpfail, dppass);
+ }
+
+ @Override
+ public void depthFunc(int func) {
+ gl.glDepthFunc(func);
+ }
+
+ @Override
+ public void blendEquation(int mode) {
+ gl.glBlendEquation(mode);
+ }
+
+ @Override
+ public void blendEquationSeparate(int modeRGB, int modeAlpha) {
+ gl.glBlendEquationSeparate(modeRGB, modeAlpha);
+ }
+
+ @Override
+ public void blendFunc(int src, int dst) {
+ gl.glBlendFunc(src, dst);
+ }
+
+ @Override
+ public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
+ gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+
+ @Override
+ public void blendColor(float red, float green, float blue, float alpha) {
+ gl2.glBlendColor(red, green, blue, alpha);
+ }
+
+ @Override
+ public void alphaFunc(int func, float ref) {
+ if (gl2x != null) {
+ gl2x.glAlphaFunc(func, ref);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glAlphaFunc()"));
+ }
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Whole Framebuffer Operations
+
+ @Override
+ public void colorMask(boolean r, boolean g, boolean b, boolean a) {
+ gl.glColorMask(r, g, b, a);
+ }
+
+ @Override
+ public void depthMask(boolean mask) {
+ gl.glDepthMask(mask);
+ }
+
+ @Override
+ public void stencilMask(int mask) {
+ gl.glStencilMask(mask);
+ }
+
+ @Override
+ public void stencilMaskSeparate(int face, int mask) {
+ gl2.glStencilMaskSeparate(face, mask);
+ }
+
+ @Override
+ public void clear(int buf) {
+ gl.glClear(buf);
+ }
+
+ @Override
+ public void clearColor(float r, float g, float b, float a) {
+ gl.glClearColor(r, g, b, a);
+ }
+
+ @Override
+ public void clearDepth(float d) {
+ gl.glClearDepthf(d);
+ }
+
+ @Override
+ public void clearStencil(int s) {
+ gl.glClearStencil(s);
+ }
+
+ ///////////////////////////////////////////////////////////
+
+ // Framebuffers Objects
+
+ @Override
+ public void bindFramebuffer(int target, int framebuffer) {
+ gl.glBindFramebuffer(target, framebuffer);
+ }
+
+ @Override
+ public void deleteFramebuffers(int n, IntBuffer framebuffers) {
+ gl.glDeleteFramebuffers(n, framebuffers);
+ }
+
+ @Override
+ public void genFramebuffers(int n, IntBuffer framebuffers) {
+ gl.glGenFramebuffers(n, framebuffers);
+ }
+
+ @Override
+ public void bindRenderbuffer(int target, int renderbuffer) {
+ gl.glBindRenderbuffer(target, renderbuffer);
+ }
+
+ @Override
+ public void deleteRenderbuffers(int n, IntBuffer renderbuffers) {
+ gl.glDeleteRenderbuffers(n, renderbuffers);
+ }
+
+ @Override
+ public void genRenderbuffers(int n, IntBuffer renderbuffers) {
+ gl.glGenRenderbuffers(n, renderbuffers);
+ }
+
+ @Override
+ public void renderbufferStorage(int target, int internalFormat, int width, int height) {
+ gl.glRenderbufferStorage(target, internalFormat, width, height);
+ }
+
+ @Override
+ public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) {
+ gl.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer);
+ }
+
+ @Override
+ public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) {
+ gl.glFramebufferTexture2D(target, attachment, texTarget, texture, level);
+ }
+
+ @Override
+ public int checkFramebufferStatus(int target) {
+ return gl.glCheckFramebufferStatus(target);
+ }
+
+ @Override
+ public boolean isFramebuffer(int framebuffer) {
+ return gl2.glIsFramebuffer(framebuffer);
+ }
+
+ @Override
+ public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) {
+ gl2.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+ }
+
+ @Override
+ public boolean isRenderbuffer(int renderbuffer) {
+ return gl2.glIsRenderbuffer(renderbuffer);
+ }
+
+ @Override
+ public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) {
+ gl2.glGetRenderbufferParameteriv(target, pname, params);
+ }
+
+ @Override
+ public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
+ if (gl2x != null) {
+ gl2x.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ } else if (gl3 != null) {
+ gl3.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glBlitFramebuffer()"));
+ }
+ }
+
+ @Override
+ public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) {
+ if (gl2x != null) {
+ gl2x.glRenderbufferStorageMultisample(target, samples, format, width, height);
+ } else if (gl3 != null) {
+ gl3.glRenderbufferStorageMultisample(target, samples, format, width, height);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glRenderbufferStorageMultisample()"));
+ }
+ }
+
+ @Override
+ public void readBuffer(int buf) {
+ if (gl2x != null) {
+ gl2x.glReadBuffer(buf);
+ } else if (gl3 != null) {
+ gl3.glReadBuffer(buf);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glReadBuffer()"));
+ }
+ }
+
+ @Override
+ public void drawBuffer(int buf) {
+ if (gl2x != null) {
+ gl2x.glDrawBuffer(buf);
+ } else if (gl3 != null) {
+ gl3.glDrawBuffer(buf);
+ } else {
+ throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glDrawBuffer()"));
+ }
+ }
+}
diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java
index 03eca7517..87c8e311b 100644
--- a/core/src/processing/opengl/PShader.java
+++ b/core/src/processing/opengl/PShader.java
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2011-12 Ben Fry and Casey Reas
+ Copyright (c) 2011-13 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,6 @@ package processing.opengl;
import processing.core.*;
-import java.io.IOException;
import java.net.URL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
@@ -39,27 +38,52 @@ import java.util.HashMap;
*
* @webref rendering:shaders
*/
-public class PShader {
- // shaders constants
- static protected final int COLOR = 0;
- static protected final int LIGHT = 1;
- static protected final int TEXTURE = 2;
- static protected final int TEXLIGHT = 3;
- static protected final int LINE = 4;
- static protected final int POINT = 5;
+public class PShader implements PConstants {
+ static protected final int POINT = 0;
+ static protected final int LINE = 1;
+ static protected final int POLY = 2;
+ static protected final int COLOR = 3;
+ static protected final int LIGHT = 4;
+ static protected final int TEXTURE = 5;
+ static protected final int TEXLIGHT = 6;
+
+ static protected String pointShaderAttrRegexp =
+ "attribute *vec2 *offset";
+ static protected String lineShaderAttrRegexp =
+ "attribute *vec4 *direction";
+ static protected String pointShaderDefRegexp =
+ "#define *PROCESSING_POINT_SHADER";
+ static protected String lineShaderDefRegexp =
+ "#define *PROCESSING_LINE_SHADER";
+ static protected String colorShaderDefRegexp =
+ "#define *PROCESSING_COLOR_SHADER";
+ static protected String lightShaderDefRegexp =
+ "#define *PROCESSING_LIGHT_SHADER";
+ static protected String texShaderDefRegexp =
+ "#define *PROCESSING_TEXTURE_SHADER";
+ static protected String texlightShaderDefRegexp =
+ "#define *PROCESSING_TEXLIGHT_SHADER";
+ static protected String polyShaderDefRegexp =
+ "#define *PROCESSING_POLYGON_SHADER";
+ static protected String triShaderAttrRegexp =
+ "#define *PROCESSING_TRIANGLES_SHADER";
+ static protected String quadShaderAttrRegexp =
+ "#define *PROCESSING_QUADS_SHADER";
protected PApplet parent;
// The main renderer associated to the parent PApplet.
- protected PGraphicsOpenGL pgMain;
+ //protected PGraphicsOpenGL pgMain;
// We need a reference to the renderer since a shader might
// be called by different renderers within a single application
// (the one corresponding to the main surface, or other offscreen
// renderers).
- protected PGraphicsOpenGL pgCurrent;
-
+ protected PGraphicsOpenGL pg;
protected PGL pgl;
protected int context; // The context that created this shader.
+ // The shader type: POINT, LINE, POLY, etc.
+ protected int type;
+
public int glProgram;
public int glVertex;
public int glFragment;
@@ -70,8 +94,8 @@ public class PShader {
protected String vertexFilename;
protected String fragmentFilename;
- protected String vertexShaderSource;
- protected String fragmentShaderSource;
+ protected String[] vertexShaderSource;
+ protected String[] fragmentShaderSource;
protected boolean bound;
@@ -84,9 +108,51 @@ public class PShader {
protected IntBuffer intBuffer;
protected FloatBuffer floatBuffer;
+ // Uniforms common to all shader types
+ protected int transformMatLoc;
+ protected int modelviewMatLoc;
+ protected int projectionMatLoc;
+ protected int bufferLoc;
+ protected int bufferUnit;
+ protected int viewportLoc;
+
+ // Uniforms only for lines and points
+ protected int perspectiveLoc;
+ protected int scaleLoc;
+
+ // Lighting uniforms
+ protected int lightCountLoc;
+ protected int lightPositionLoc;
+ protected int lightNormalLoc;
+ protected int lightAmbientLoc;
+ protected int lightDiffuseLoc;
+ protected int lightSpecularLoc;
+ protected int lightFalloffLoc;
+ protected int lightSpotLoc;
+
+ // Texturing uniforms
+ protected Texture texture;
+ protected int texUnit;
+ protected int textureLoc;
+ protected int texMatrixLoc;
+ protected int texOffsetLoc;
+ protected float[] tcmat;
+
+ // Vertex attributes
+ protected int vertexLoc;
+ protected int colorLoc;
+ protected int normalLoc;
+ protected int texCoordLoc;
+ protected int normalMatLoc;
+ protected int directionLoc;
+ protected int offsetLoc;
+ protected int ambientLoc;
+ protected int specularLoc;
+ protected int emissiveLoc;
+ protected int shininessLoc;
+
public PShader() {
parent = null;
- pgMain = null;
pgl = null;
context = -1;
@@ -103,13 +169,14 @@ public class PShader {
floatBuffer = PGL.allocateFloatBuffer(1);
bound = false;
+
+ type = -1;
}
public PShader(PApplet parent) {
this();
this.parent = parent;
- pgMain = (PGraphicsOpenGL) parent.g;
pgl = PGraphicsOpenGL.pgl;
context = pgl.createEmptyContext();
}
@@ -125,13 +192,14 @@ public class PShader {
*/
public PShader(PApplet parent, String vertFilename, String fragFilename) {
this.parent = parent;
- pgMain = (PGraphicsOpenGL) parent.g;
pgl = PGraphicsOpenGL.pgl;
this.vertexURL = null;
this.fragmentURL = null;
this.vertexFilename = vertFilename;
this.fragmentFilename = fragFilename;
+ fragmentShaderSource = pgl.loadFragmentShader(fragFilename);
+ vertexShaderSource = pgl.loadVertexShader(vertFilename);
glProgram = 0;
glVertex = 0;
@@ -139,6 +207,20 @@ public class PShader {
intBuffer = PGL.allocateIntBuffer(1);
floatBuffer = PGL.allocateFloatBuffer(1);
+
+ int vertType = getShaderType(vertexShaderSource, -1);
+ int fragType = getShaderType(fragmentShaderSource, -1);
+ if (vertType == -1 && fragType == -1) {
+ type = PShader.POLY;
+ } else if (vertType == -1) {
+ type = fragType;
+ } else if (fragType == -1) {
+ type = vertType;
+ } else if (fragType == vertType) {
+ type = vertType;
+ } else {
+ PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES);
+ }
}
@@ -148,13 +230,14 @@ public class PShader {
*/
public PShader(PApplet parent, URL vertURL, URL fragURL) {
this.parent = parent;
- pgMain = (PGraphicsOpenGL) parent.g;
pgl = PGraphicsOpenGL.pgl;
this.vertexURL = vertURL;
this.fragmentURL = fragURL;
this.vertexFilename = null;
this.fragmentFilename = null;
+ fragmentShaderSource = pgl.loadFragmentShader(fragURL);
+ vertexShaderSource = pgl.loadVertexShader(vertURL);
glProgram = 0;
glVertex = 0;
@@ -162,6 +245,53 @@ public class PShader {
intBuffer = PGL.allocateIntBuffer(1);
floatBuffer = PGL.allocateFloatBuffer(1);
+
+ int vertType = getShaderType(vertexShaderSource, -1);
+ int fragType = getShaderType(fragmentShaderSource, -1);
+ if (vertType == -1 && fragType == -1) {
+ type = PShader.POLY;
+ } else if (vertType == -1) {
+ type = fragType;
+ } else if (fragType == -1) {
+ type = vertType;
+ } else if (fragType == vertType) {
+ type = vertType;
+ } else {
+ PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES);
+ }
+ }
+
+ public PShader(PApplet parent, String[] vertSource, String[] fragSource) {
+ this.parent = parent;
+ pgl = PGraphicsOpenGL.pgl;
+
+ this.vertexURL = null;
+ this.fragmentURL = null;
+ this.vertexFilename = null;
+ this.fragmentFilename = null;
+ vertexShaderSource = vertSource;
+ fragmentShaderSource = fragSource;
+
+ glProgram = 0;
+ glVertex = 0;
+ glFragment = 0;
+
+ intBuffer = PGL.allocateIntBuffer(1);
+ floatBuffer = PGL.allocateFloatBuffer(1);
+
+ int vertType = getShaderType(vertexShaderSource, -1);
+ int fragType = getShaderType(fragmentShaderSource, -1);
+ if (vertType == -1 && fragType == -1) {
+ type = PShader.POLY;
+ } else if (vertType == -1) {
+ type = fragType;
+ } else if (fragType == -1) {
+ type = vertType;
+ } else if (fragType == vertType) {
+ type = vertType;
+ } else {
+ PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES);
+ }
}
@@ -185,21 +315,34 @@ public class PShader {
public void setVertexShader(String vertFilename) {
this.vertexFilename = vertFilename;
+ vertexShaderSource = pgl.loadFragmentShader(vertFilename);
}
public void setVertexShader(URL vertURL) {
this.vertexURL = vertURL;
+ vertexShaderSource = pgl.loadVertexShader(vertURL);
+ }
+
+
+ public void setVertexShader(String[] vertSource) {
+ vertexShaderSource = vertSource;
}
public void setFragmentShader(String fragFilename) {
this.fragmentFilename = fragFilename;
+ fragmentShaderSource = pgl.loadVertexShader(fragFilename);
}
public void setFragmentShader(URL fragURL) {
this.fragmentURL = fragURL;
+ fragmentShaderSource = pgl.loadVertexShader(fragURL);
+ }
+
+ public void setFragmentShader(String[] fragSource) {
+ fragmentShaderSource = fragSource;
}
@@ -214,6 +357,8 @@ public class PShader {
consumeUniforms();
bindTextures();
}
+
+ if (hasType()) bindTyped();
}
@@ -221,6 +366,8 @@ public class PShader {
* Unbinds the shader program.
*/
public void unbind() {
+ if (hasType()) unbindTyped();
+
if (bound) {
unbindTextures();
pgl.useProgram(0);
@@ -264,7 +411,7 @@ public class PShader {
* @param w fourth component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[4], vec4)
*/
public void set(String name, int x, int y, int z, int w) {
- setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z });
+ setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z, w });
}
@@ -296,10 +443,34 @@ public class PShader {
}
+ public void set(String name, boolean x) {
+ setUniformImpl(name, UniformValue.INT1, new int[] { (x)?1:0 });
+ }
+
+
+ public void set(String name, boolean x, boolean y) {
+ setUniformImpl(name, UniformValue.INT2,
+ new int[] { (x)?1:0, (y)?1:0 });
+ }
+
+
+ public void set(String name, boolean x, boolean y, boolean z) {
+ setUniformImpl(name, UniformValue.INT3,
+ new int[] { (x)?1:0, (y)?1:0, (z)?1:0 });
+ }
+
+
+ public void set(String name, boolean x, boolean y, boolean z, boolean w) {
+ setUniformImpl(name, UniformValue.INT4,
+ new int[] { (x)?1:0, (y)?1:0, (z)?1:0, (w)?1:0 });
+ }
+
+
public void set(String name, int[] vec) {
set(name, vec, 1);
}
+
/**
* @param ncoords number of coordinates per element, max 4
*/
@@ -343,6 +514,21 @@ public class PShader {
}
}
+
+ public void set(String name, boolean[] vec) {
+ set(name, vec, 1);
+ }
+
+
+ public void set(String name, boolean[] boolvec, int ncoords) {
+ int[] vec = new int[boolvec.length];
+ for (int i = 0; i < boolvec.length; i++) {
+ vec[i] = (boolvec[i])?1:0;
+ }
+ set(name, vec, ncoords);
+ }
+
+
/**
* @param mat matrix of values
*/
@@ -383,6 +569,23 @@ public class PShader {
}
+ /**
+ * Extra initialization method that can be used by subclasses, called after
+ * compiling and attaching the vertex and fragment shaders, and before
+ * linking the shader program.
+ *
+ */
+ protected void setup() {
+ }
+
+
+ protected void draw(int idxId, int count, int offset) {
+ pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, idxId);
+ pgl.drawElements(PGL.TRIANGLES, count, PGL.INDEX_TYPE,
+ offset * PGL.SIZEOF_INDEX);
+ pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ }
+
/**
* Returns the ID location of the attribute parameter given its name.
@@ -563,7 +766,7 @@ public class PShader {
pgl.uniform3i(loc, v[0], v[1], v[2]);
} else if (val.type == UniformValue.INT4) {
int[] v = ((int[])val.value);
- pgl.uniform4i(loc, v[0], v[1], v[2], v[4]);
+ pgl.uniform4i(loc, v[0], v[1], v[2], v[3]);
} else if (val.type == UniformValue.FLOAT1) {
float[] v = ((float[])val.value);
pgl.uniform1f(loc, v[0]);
@@ -622,7 +825,7 @@ public class PShader {
pgl.uniformMatrix4fv(loc, 1, false, floatBuffer);
} else if (val.type == UniformValue.SAMPLER2D) {
PImage img = (PImage)val.value;
- Texture tex = pgMain.getTexture(img);
+ Texture tex = PGraphicsOpenGL.pgPrimary.getTexture(img);
if (textures == null) textures = new HashMap();
textures.put(loc, tex);
@@ -685,54 +888,30 @@ public class PShader {
}
}
-
- protected int getLastTexUnit() {
- if (texUnits == null) return -1;
- else return texUnits.size() - 1;
- }
-
protected void init() {
if (glProgram == 0 || contextIsOutdated()) {
context = pgl.getCurrentContext();
glProgram = PGraphicsOpenGL.createGLSLProgramObject(context);
- boolean hasVert = false;
- if (vertexFilename != null) {
- hasVert = loadVertexShader(vertexFilename);
- } else if (vertexURL != null) {
- hasVert = loadVertexShader(vertexURL);
- } else {
- PGraphics.showException("Vertex shader filenames and URLs are " +
- "both null!");
- }
-
- boolean hasFrag = false;
- if (fragmentFilename != null) {
- hasFrag = loadFragmentShader(fragmentFilename);
- } else if (fragmentURL != null) {
- hasFrag = loadFragmentShader(fragmentURL);
- } else {
- PGraphics.showException("Fragment shader filenames and URLs are " +
- "both null!");
- }
-
boolean vertRes = true;
- if (hasVert) {
+ if (hasVertexShader()) {
vertRes = compileVertexShader();
+ } else {
+ PGraphics.showException("Doesn't have a vertex shader");
}
boolean fragRes = true;
- if (hasFrag) {
+ if (hasFragmentShader()) {
fragRes = compileFragmentShader();
+ } else {
+ PGraphics.showException("Doesn't have a fragment shader");
}
if (vertRes && fragRes) {
- if (hasVert) {
- pgl.attachShader(glProgram, glVertex);
- }
- if (hasFrag) {
- pgl.attachShader(glProgram, glFragment);
- }
+ pgl.attachShader(glProgram, glVertex);
+ pgl.attachShader(glProgram, glFragment);
+ setup();
+
pgl.linkProgram(glProgram);
pgl.getProgramiv(glProgram, PGL.LINK_STATUS, intBuffer);
@@ -769,69 +948,22 @@ public class PShader {
}
- /**
- * Loads and compiles the vertex shader contained in file.
- *
- * @param file String
- */
- protected boolean loadVertexShader(String filename) {
- vertexShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
- return vertexShaderSource != null;
+
+ protected boolean hasVertexShader() {
+ return vertexShaderSource != null && 0 < vertexShaderSource.length;
}
-
- /**
- * Loads and compiles the vertex shader contained in the URL.
- *
- * @param file String
- */
- protected boolean loadVertexShader(URL url) {
- try {
- vertexShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()),
- "\n");
- return vertexShaderSource != null;
- } catch (IOException e) {
- PGraphics.showException("Cannot load vertex shader " + url.getFile());
- return false;
- }
+ protected boolean hasFragmentShader() {
+ return fragmentShaderSource != null && 0 < fragmentShaderSource.length;
}
-
- /**
- * Loads and compiles the fragment shader contained in file.
- *
- * @param file String
- */
- protected boolean loadFragmentShader(String filename) {
- fragmentShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
- return fragmentShaderSource != null;
- }
-
-
- /**
- * Loads and compiles the fragment shader contained in the URL.
- *
- * @param url URL
- */
- protected boolean loadFragmentShader(URL url) {
- try {
- fragmentShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()),
- "\n");
- return fragmentShaderSource != null;
- } catch (IOException e) {
- PGraphics.showException("Cannot load fragment shader " + url.getFile());
- return false;
- }
- }
-
-
/**
* @param shaderSource a string containing the shader's code
*/
protected boolean compileVertexShader() {
glVertex = PGraphicsOpenGL.createGLSLVertShaderObject(context);
- pgl.shaderSource(glVertex, vertexShaderSource);
+ pgl.shaderSource(glVertex, PApplet.join(vertexShaderSource, "\n"));
pgl.compileShader(glVertex);
pgl.getShaderiv(glVertex, PGL.COMPILE_STATUS, intBuffer);
@@ -852,7 +984,7 @@ public class PShader {
protected boolean compileFragmentShader() {
glFragment = PGraphicsOpenGL.createGLSLFragShaderObject(context);
- pgl.shaderSource(glFragment, fragmentShaderSource);
+ pgl.shaderSource(glFragment, PApplet.join(fragmentShaderSource, "\n"));
pgl.compileShader(glFragment);
pgl.getShaderiv(glFragment, PGL.COMPILE_STATUS, intBuffer);
@@ -867,16 +999,6 @@ public class PShader {
}
- protected void setRenderer(PGraphicsOpenGL pg) {
- pgCurrent = pg;
- }
-
- protected void loadAttributes() { }
-
-
- protected void loadUniforms() { }
-
-
protected void dispose() {
if (glVertex != 0) {
PGraphicsOpenGL.deleteGLSLVertShaderObject(glVertex, context);
@@ -892,6 +1014,411 @@ public class PShader {
}
}
+ static protected int getShaderType(String[] source, int defaultType) {
+ for (int i = 0; i < source.length; i++) {
+ String line = source[i].trim();
+ if (PApplet.match(line, pointShaderAttrRegexp) != null)
+ return PShader.POINT;
+ else if (PApplet.match(line, lineShaderAttrRegexp) != null)
+ return PShader.LINE;
+ else if (PApplet.match(line, pointShaderDefRegexp) != null)
+ return PShader.POINT;
+ else if (PApplet.match(line, lineShaderDefRegexp) != null)
+ return PShader.LINE;
+ else if (PApplet.match(line, colorShaderDefRegexp) != null)
+ return PShader.COLOR;
+ else if (PApplet.match(line, lightShaderDefRegexp) != null)
+ return PShader.LIGHT;
+ else if (PApplet.match(line, texShaderDefRegexp) != null)
+ return PShader.TEXTURE;
+ else if (PApplet.match(line, texlightShaderDefRegexp) != null)
+ return PShader.TEXLIGHT;
+ else if (PApplet.match(line, polyShaderDefRegexp) != null)
+ return PShader.POLY;
+ else if (PApplet.match(line, triShaderAttrRegexp) != null)
+ return PShader.POLY;
+ else if (PApplet.match(line, quadShaderAttrRegexp) != null)
+ return PShader.POLY;
+ }
+ return defaultType;
+ }
+
+
+ // ***************************************************************************
+ //
+ // Processing specific
+
+ protected int getType() {
+ return type;
+ }
+
+ protected void setType(int type) {
+ this.type = type;
+ }
+
+ protected boolean hasType() {
+ return POINT <= type && type <= TEXLIGHT;
+ }
+
+ protected boolean isPointShader() {
+ return type == POINT;
+ }
+
+ protected boolean isLineShader() {
+ return type == LINE;
+ }
+
+ protected boolean isPolyShader() {
+ return POLY <= type && type <= TEXLIGHT;
+ }
+
+ protected boolean checkPolyType(int type) {
+ if (getType() == PShader.POLY) return true;
+
+ if (getType() != type) {
+ if (type == TEXLIGHT) {
+ PGraphics.showWarning(PGraphicsOpenGL.NO_TEXLIGHT_SHADER_ERROR);
+ } else if (type == LIGHT) {
+ PGraphics.showWarning(PGraphicsOpenGL.NO_LIGHT_SHADER_ERROR);
+ } else if (type == TEXTURE) {
+ PGraphics.showWarning(PGraphicsOpenGL.NO_TEXTURE_SHADER_ERROR);
+ } else if (type == COLOR) {
+ PGraphics.showWarning(PGraphicsOpenGL.NO_COLOR_SHADER_ERROR);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ protected int getLastTexUnit() {
+ return texUnits == null ? -1 : texUnits.size() - 1;
+ }
+
+ protected void setRenderer(PGraphicsOpenGL pg) {
+ this.pg = pg;
+ }
+
+ boolean loadedAttributes = false;
+ protected void loadAttributes() {
+ if (loadedAttributes) return;
+
+ vertexLoc = getAttributeLoc("vertex");
+ if (vertexLoc == -1) vertexLoc = getAttributeLoc("position");
+
+ colorLoc = getAttributeLoc("color");
+ texCoordLoc = getAttributeLoc("texCoord");
+ normalLoc = getAttributeLoc("normal");
+
+ ambientLoc = getAttributeLoc("ambient");
+ specularLoc = getAttributeLoc("specular");
+ emissiveLoc = getAttributeLoc("emissive");
+ shininessLoc = getAttributeLoc("shininess");
+
+ directionLoc = getAttributeLoc("direction");
+
+ offsetLoc = getAttributeLoc("offset");
+
+ directionLoc = getAttributeLoc("direction");
+ offsetLoc = getAttributeLoc("offset");
+
+ loadedAttributes = true;
+ }
+
+
+ boolean loadedUniforms = false;
+ protected void loadUniforms() {
+ if (loadedUniforms) return;
+ transformMatLoc = getUniformLoc("transform");
+ if (transformMatLoc == -1)
+ transformMatLoc = getUniformLoc("transformMatrix");
+
+ modelviewMatLoc = getUniformLoc("modelview");
+ if (modelviewMatLoc == -1)
+ modelviewMatLoc = getUniformLoc("modelviewMatrix");
+
+ projectionMatLoc = getUniformLoc("projection");
+ if (projectionMatLoc == -1)
+ projectionMatLoc = getUniformLoc("projectionMatrix");
+
+ viewportLoc = getUniformLoc("viewport");
+ bufferLoc = getUniformLoc("buffer");
+
+ normalMatLoc = getUniformLoc("normalMatrix");
+
+ lightCountLoc = getUniformLoc("lightCount");
+ lightPositionLoc = getUniformLoc("lightPosition");
+ lightNormalLoc = getUniformLoc("lightNormal");
+ lightAmbientLoc = getUniformLoc("lightAmbient");
+ lightDiffuseLoc = getUniformLoc("lightDiffuse");
+ lightSpecularLoc = getUniformLoc("lightSpecular");
+ lightFalloffLoc = getUniformLoc("lightFalloff");
+ lightSpotLoc = getUniformLoc("lightSpot");
+
+ textureLoc = getUniformLoc("texture");
+ if (textureLoc == -1) {
+ textureLoc = getUniformLoc("texMap");
+ }
+
+ texMatrixLoc = getUniformLoc("texMatrix");
+ texOffsetLoc = getUniformLoc("texOffset");
+
+ perspectiveLoc = getUniformLoc("perspective");
+ scaleLoc = getUniformLoc("scale");
+ loadedUniforms = true;
+ }
+
+
+ protected void setCommonUniforms() {
+ if (-1 < transformMatLoc) {
+ pg.updateGLProjmodelview();
+ setUniformMatrix(transformMatLoc, pg.glProjmodelview);
+ }
+
+ if (-1 < modelviewMatLoc) {
+ pg.updateGLModelview();
+ setUniformMatrix(modelviewMatLoc, pg.glModelview);
+ }
+
+ if (-1 < projectionMatLoc) {
+ pg.updateGLProjection();
+ setUniformMatrix(projectionMatLoc, pg.glProjection);
+ }
+
+ if (-1 < viewportLoc) {
+ float x = pg.viewport.get(0);
+ float y = pg.viewport.get(1);
+ float w = pg.viewport.get(2);
+ float h = pg.viewport.get(3);
+ setUniformValue(viewportLoc, x, y, w, h);
+ }
+
+ if (-1 < bufferLoc) {
+ bufferUnit = getLastTexUnit() + 1;
+ setUniformValue(bufferLoc, bufferUnit);
+ pgl.activeTexture(PGL.TEXTURE0 + bufferUnit);
+ pg.bindFrontTexture();
+ } else {
+ bufferUnit = -1;
+ }
+ }
+
+ protected void bindTyped() {
+ if (pg == null) {
+ setRenderer(PGraphicsOpenGL.pgCurrent);
+ loadAttributes();
+ loadUniforms();
+ }
+ setCommonUniforms();
+
+ if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc);
+ if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc);
+ if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc);
+ if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc);
+
+ if (-1 < normalMatLoc) {
+ pg.updateGLNormal();
+ setUniformMatrix(normalMatLoc, pg.glNormal);
+ }
+
+ if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc);
+ if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc);
+ if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc);
+ if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc);
+
+ int count = pg.lightCount;
+ setUniformValue(lightCountLoc, count);
+ if (0 < count) {
+ setUniformVector(lightPositionLoc, pg.lightPosition, 4, count);
+ setUniformVector(lightNormalLoc, pg.lightNormal, 3, count);
+ setUniformVector(lightAmbientLoc, pg.lightAmbient, 3, count);
+ setUniformVector(lightDiffuseLoc, pg.lightDiffuse, 3, count);
+ setUniformVector(lightSpecularLoc, pg.lightSpecular, 3, count);
+ setUniformVector(lightFalloffLoc, pg.lightFalloffCoefficients,
+ 3, count);
+ setUniformVector(lightSpotLoc, pg.lightSpotParameters, 2, count);
+ }
+
+ if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc);
+
+ if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc);
+
+ if (-1 < perspectiveLoc) {
+ if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) &&
+ pg.nonOrthoProjection()) {
+ setUniformValue(perspectiveLoc, 1);
+ } else {
+ setUniformValue(perspectiveLoc, 0);
+ }
+ }
+
+ if (-1 < scaleLoc) {
+ if (pg.getHint(DISABLE_OPTIMIZED_STROKE)) {
+ setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f);
+ } else {
+ float f = PGL.STROKE_DISPLACEMENT;
+ if (pg.orthoProjection()) {
+ setUniformValue(scaleLoc, 1, 1, f);
+ } else {
+ setUniformValue(scaleLoc, f, f, f);
+ }
+ }
+ }
+ }
+
+ protected void unbindTyped() {
+ if (-1 < offsetLoc) pgl.disableVertexAttribArray(offsetLoc);
+
+ if (-1 < directionLoc) pgl.disableVertexAttribArray(directionLoc);
+
+ if (-1 < textureLoc && texture != null) {
+ pgl.activeTexture(PGL.TEXTURE0 + texUnit);
+ texture.unbind();
+ pgl.activeTexture(PGL.TEXTURE0);
+ texture = null;
+ }
+
+ if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc);
+ if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc);
+ if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc);
+ if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc);
+
+ if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc);
+ if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc);
+ if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc);
+ if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc);
+
+ if (-1 < bufferLoc) {
+ pgl.requestFBOLayer();
+ pgl.activeTexture(PGL.TEXTURE0 + bufferUnit);
+ pg.unbindFrontTexture();
+ pgl.activeTexture(PGL.TEXTURE0);
+ }
+
+ pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
+ }
+
+ protected void setTexture(Texture tex) {
+ texture = tex;
+
+ float scaleu = 1;
+ float scalev = 1;
+ float dispu = 0;
+ float dispv = 0;
+
+ if (tex != null) {
+ if (tex.invertedX()) {
+ scaleu = -1;
+ dispu = 1;
+ }
+
+ if (tex.invertedY()) {
+ scalev = -1;
+ dispv = 1;
+ }
+
+ scaleu *= tex.maxTexcoordU();
+ dispu *= tex.maxTexcoordU();
+ scalev *= tex.maxTexcoordV();
+ dispv *= tex.maxTexcoordV();
+
+ setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
+
+ if (-1 < textureLoc) {
+ texUnit = -1 < bufferUnit ? bufferUnit + 1 : getLastTexUnit() + 1;
+ setUniformValue(textureLoc, texUnit);
+ pgl.activeTexture(PGL.TEXTURE0 + texUnit);
+ tex.bind();
+ }
+ }
+
+ if (-1 < texMatrixLoc) {
+ if (tcmat == null) {
+ tcmat = new float[16];
+ }
+ tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu;
+ tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv;
+ tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0;
+ tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0;
+ setUniformMatrix(texMatrixLoc, tcmat);
+ }
+ }
+
+
+ protected boolean supportsTexturing() {
+ return -1 < textureLoc;
+ }
+
+ protected boolean supportLighting() {
+ return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc;
+ }
+
+ protected boolean accessTexCoords() {
+ return -1 < texCoordLoc;
+ }
+
+ protected boolean accessNormals() {
+ return -1 < normalLoc;
+ }
+
+ protected boolean accessLightAttribs() {
+ return -1 < ambientLoc || -1 < specularLoc || -1 < emissiveLoc ||
+ -1 < shininessLoc;
+ }
+
+ protected void setVertexAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset);
+ }
+
+ protected void setColorAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset);
+ }
+
+ protected void setNormalAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset);
+ }
+
+ protected void setTexcoordAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset);
+ }
+
+ protected void setAmbientAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset);
+ }
+
+ protected void setSpecularAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset);
+ }
+
+ protected void setEmissiveAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset);
+ }
+
+ protected void setShininessAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset);
+ }
+
+ protected void setLineAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset);
+ }
+
+ protected void setPointAttribute(int vboId, int size, int type,
+ int stride, int offset) {
+ setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset);
+ }
+
+
+ // ***************************************************************************
+ //
// Class to store a user-specified value for a uniform parameter
// in the shader
protected class UniformValue {
diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java
index 0d9cbd2fe..704bbdea5 100644
--- a/core/src/processing/opengl/PShapeOpenGL.java
+++ b/core/src/processing/opengl/PShapeOpenGL.java
@@ -31,9 +31,6 @@ import processing.core.PMatrix2D;
import processing.core.PMatrix3D;
import processing.core.PShape;
import processing.core.PVector;
-import processing.opengl.PGraphicsOpenGL.LineShader;
-import processing.opengl.PGraphicsOpenGL.PointShader;
-import processing.opengl.PGraphicsOpenGL.BaseShader;
import processing.opengl.PGraphicsOpenGL.IndexCache;
import processing.opengl.PGraphicsOpenGL.InGeometry;
import processing.opengl.PGraphicsOpenGL.TessGeometry;
@@ -41,6 +38,7 @@ import processing.opengl.PGraphicsOpenGL.Tessellator;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Stack;
/**
* This class holds a 3D model composed of vertices, normals, colors
@@ -155,6 +153,7 @@ public class PShapeOpenGL extends PShape {
// Geometric transformations.
protected PMatrix transform;
+ protected Stack transformStack;
// ........................................................
@@ -162,12 +161,9 @@ public class PShapeOpenGL extends PShape {
protected boolean tessellated;
protected boolean needBufferInit = false;
-// protected boolean polyBuffersCreated = false;
-// protected boolean lineBuffersCreated = false;
-// protected boolean pointBuffersCreated = false;
- protected boolean isSolid;
- protected boolean isClosed;
+ // Flag to indicate if the shape can have holes or not.
+ protected boolean solid;
protected boolean breakShape = false;
protected boolean shapeCreated = false;
@@ -187,9 +183,13 @@ public class PShapeOpenGL extends PShape {
// Bezier and Catmull-Rom curves
- protected int bezierDetail = 20;
- protected int curveDetail = 20;
- protected float curveTightness = 0;
+ protected int bezierDetail;
+ protected int curveDetail;
+ protected float curveTightness;
+
+ protected int savedBezierDetail;
+ protected int savedCurveDetail;
+ protected float savedCurveTightness;
// ........................................................
@@ -261,13 +261,37 @@ public class PShapeOpenGL extends PShape {
protected int firstModifiedPointAttribute;
protected int lastModifiedPointAttribute;
+ // ........................................................
+
+ // Saved style variables to style can be re-enabled after disableStyle,
+ // although it won't work if properties are defined on a per-vertex basis.
+
+ protected boolean savedStroke;
+ protected int savedStrokeColor;
+ protected float savedStrokeWeight;
+ protected int savedStrokeCap;
+ protected int savedStrokeJoin;
+
+ protected boolean savedFill;
+ protected int savedFillColor;
+
+ protected boolean savedTint;
+ protected int savedTintColor;
+
+ protected int savedAmbientColor;
+ protected int savedSpecularColor;
+ protected int savedEmissiveColor;
+ protected float savedShininess;
+
+ protected int savedTextureMode;
+
PShapeOpenGL() {
}
public PShapeOpenGL(PApplet parent, int family) {
- pg = (PGraphicsOpenGL)parent.g;
+ pg = PGraphicsOpenGL.pgCurrent;
pgl = PGraphicsOpenGL.pgl;
context = pgl.createEmptyContext();
@@ -298,7 +322,7 @@ public class PShapeOpenGL extends PShape {
this.tessellated = false;
if (family == GEOMETRY || family == PRIMITIVE || family == PATH) {
- inGeo = pg.newInGeometry(PGraphicsOpenGL.RETAINED);
+ inGeo = PGraphicsOpenGL.newInGeometry(pg, PGraphicsOpenGL.RETAINED);
}
// Style parameters are retrieved from the current values in the renderer.
@@ -330,6 +354,18 @@ public class PShapeOpenGL extends PShape {
emissiveColor = pg.emissiveColor;
shininess = pg.shininess;
+ sphereDetailU = pg.sphereDetailU;
+ sphereDetailV = pg.sphereDetailV;
+
+ bezierDetail = pg.bezierDetail;
+ curveDetail = pg.curveDetail;
+ curveTightness = pg.curveTightness;
+
+ // The rect and ellipse modes are set to CORNER since it is the expected
+ // mode for svg shapes.
+ rectMode = CORNER;
+ ellipseMode = CORNER;
+
normalX = normalY = 0;
normalZ = 1;
@@ -337,7 +373,7 @@ public class PShapeOpenGL extends PShape {
// To make sure that the first vertex is marked as a break.
// Same behavior as in the immediate mode.
- breakShape = true;
+ breakShape = false;
if (family == GROUP) {
// GROUP shapes are always marked as ended.
@@ -948,21 +984,27 @@ public class PShapeOpenGL extends PShape {
child.solid(solid);
}
} else {
- isSolid = solid;
+ this.solid = solid;
}
}
@Override
- public void beginContour() {
- super.beginContour();
+ protected void beginContourImpl() {
breakShape = true;
}
+ @Override
+ protected void endContourImpl() {
+ }
+
+
@Override
public void vertex(float x, float y) {
vertexImpl(x, y, 0, 0, 0);
+ if (image != null)
+ PGraphics.showWarning(PGraphicsOpenGL.MISSING_UV_TEXCOORDS_ERROR);
}
@@ -975,6 +1017,8 @@ public class PShapeOpenGL extends PShape {
@Override
public void vertex(float x, float y, float z) {
vertexImpl(x, y, z, 0, 0);
+ if (image != null)
+ PGraphics.showWarning(PGraphicsOpenGL.MISSING_UV_TEXCOORDS_ERROR);
}
@@ -1022,24 +1066,23 @@ public class PShapeOpenGL extends PShape {
}
inGeo.addVertex(x, y, z,
- fcolor,
- normalX, normalY, normalZ,
- u, v,
- scolor, sweight,
- ambientColor, specularColor, emissiveColor, shininess,
- vertexCode());
+ fcolor,
+ normalX, normalY, normalZ,
+ u, v,
+ scolor, sweight,
+ ambientColor, specularColor, emissiveColor, shininess,
+ VERTEX, vertexBreak());
markForTessellation();
}
- protected int vertexCode() {
- int code = VERTEX;
+ protected boolean vertexBreak() {
if (breakShape) {
- code = BREAK;
breakShape = false;
+ return true;
}
- return code;
+ return false;
}
@@ -1079,7 +1122,7 @@ public class PShapeOpenGL extends PShape {
// size, which might lead to arrays larger than the vertex counts.
inGeo.trim();
- isClosed = mode == CLOSE;
+ close = mode == CLOSE;
markForTessellation();
shapeCreated = true;
}
@@ -1121,7 +1164,11 @@ public class PShapeOpenGL extends PShape {
@Override
public void translate(float tx, float ty) {
- transform(TRANSLATE, tx, ty);
+ if (is3D) {
+ transform(TRANSLATE, tx, ty, 0);
+ } else {
+ transform(TRANSLATE, tx, ty);
+ }
}
@@ -1163,13 +1210,21 @@ public class PShapeOpenGL extends PShape {
@Override
public void scale(float s) {
- transform(SCALE, s, s);
+ if (is3D) {
+ transform(SCALE, s, s, s);
+ } else {
+ transform(SCALE, s, s);
+ }
}
@Override
public void scale(float x, float y) {
- transform(SCALE, x, y);
+ if (is3D) {
+ transform(SCALE, x, y, 1);
+ } else {
+ transform(SCALE, x, y);
+ }
}
@@ -1208,46 +1263,31 @@ public class PShapeOpenGL extends PShape {
@Override
public void resetMatrix() {
- if (shapeCreated && matrix != null) {
+ if (shapeCreated && matrix != null && transformStack != null) {
if (family == GROUP) {
updateTessellation();
}
- boolean res = matrix.invert();
- if (res) {
- if (tessellated) {
- applyMatrixImpl(matrix);
+ if (tessellated) {
+ PMatrix mat = popTransform();
+ while (mat != null) {
+ boolean res = mat.invert();
+ if (res) {
+ applyMatrixImpl(mat);
+ } else {
+ PGraphics.showWarning("Transformation applied on the shape cannot be inverted");
+ }
+ mat = popTransform();
}
- matrix = null;
- } else {
- PGraphics.showWarning("The transformation matrix cannot be inverted");
}
+ matrix.reset();
+ transformStack.clear();
}
}
protected void transform(int type, float... args) {
- int dimensions;
- if (type == ROTATE) {
- dimensions = args.length == 1 ? 2 : 3;
- } else if (type == MATRIX) {
- dimensions = args.length == 6 ? 2 : 3;
- } else {
- dimensions = args.length;
- }
- transformImpl(type, dimensions, args);
- }
-
-
- protected void transformImpl(int type, int ncoords, float... args) {
- checkMatrix(ncoords);
- calcTransform(type, ncoords, args);
- if (tessellated) {
- applyMatrixImpl(transform);
- }
- }
-
-
- protected void calcTransform(int type, int dimensions, float... args) {
+ int dimensions = is3D ? 3 : 2;
+ checkMatrix(dimensions);
if (transform == null) {
if (dimensions == 2) {
transform = new PMatrix2D();
@@ -1258,30 +1298,37 @@ public class PShapeOpenGL extends PShape {
transform.reset();
}
+ int ncoords = args.length;
+ if (type == ROTATE) {
+ ncoords = args.length == 1 ? 2 : 3;
+ } else if (type == MATRIX) {
+ ncoords = args.length == 6 ? 2 : 3;
+ }
+
switch (type) {
case TRANSLATE:
- if (dimensions == 3) {
+ if (ncoords == 3) {
transform.translate(args[0], args[1], args[2]);
} else {
transform.translate(args[0], args[1]);
}
break;
case ROTATE:
- if (dimensions == 3) {
+ if (ncoords == 3) {
transform.rotate(args[0], args[1], args[2], args[3]);
} else {
transform.rotate(args[0]);
}
break;
case SCALE:
- if (dimensions == 3) {
+ if (ncoords == 3) {
transform.scale(args[0], args[1], args[2]);
} else {
transform.scale(args[0], args[1]);
}
break;
case MATRIX:
- if (dimensions == 3) {
+ if (ncoords == 3) {
transform.set(args[ 0], args[ 1], args[ 2], args[ 3],
args[ 4], args[ 5], args[ 6], args[ 7],
args[ 8], args[ 9], args[10], args[11],
@@ -1293,9 +1340,29 @@ public class PShapeOpenGL extends PShape {
break;
}
matrix.apply(transform);
+ pushTransform();
+ if (tessellated) applyMatrixImpl(transform);
}
+ protected void pushTransform() {
+ if (transformStack == null) transformStack = new Stack();
+ PMatrix mat;
+ if (transform instanceof PMatrix2D) {
+ mat = new PMatrix2D();
+ } else {
+ mat = new PMatrix3D();
+ }
+ mat.set(transform);
+ transformStack.push(mat);
+ }
+
+
+ protected PMatrix popTransform() {
+ if (transformStack == null || transformStack.size() == 0) return null;
+ return transformStack.pop();
+ }
+
protected void applyMatrixImpl(PMatrix matrix) {
if (hasPolys) {
tessGeo.applyMatrixOnPolyGeometry(matrix,
@@ -1331,7 +1398,10 @@ public class PShapeOpenGL extends PShape {
@Override
public void bezierDetail(int detail) {
bezierDetail = detail;
- pg.bezierDetail(detail);
+ if (0 < inGeo.codeCount) {
+ markForTessellation();
+ }
+ //pg.bezierDetail(detail); // setting the detail in the renderer, WTF??
}
@@ -1362,9 +1432,16 @@ public class PShapeOpenGL extends PShape {
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
inGeo.addBezierVertex(x2, y2, z2,
- x3, y3, z3,
- x4, y4, z4,
- fill, stroke, bezierDetail, vertexCode(), kind);
+ x3, y3, z3,
+ x4, y4, z4, vertexBreak());
+
+// inGeo.addVertex(x2, y2, z2, BEZIER_VERTEX, vertexBreak());
+// inGeo.addVertex(x3, y3, z3, BEZIER_VERTEX, false);
+// inGeo.addVertex(x4, y4, z4, BEZIER_VERTEX, false);
+//// inGeo.addBezierVertex(x2, y2, z2,
+// x3, y3, z3,
+// x4, y4, z4,
+// fill, stroke, bezierDetail, vertexCode(), kind);
}
@@ -1390,8 +1467,12 @@ public class PShapeOpenGL extends PShape {
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
inGeo.addQuadraticVertex(cx, cy, cz,
- x3, y3, z3,
- fill, stroke, bezierDetail, vertexCode(), kind);
+ x3, y3, z3, vertexBreak());
+// inGeo.addVertex(cx, cy, cz, QUADRATIC_VERTEX, vertexBreak());
+// inGeo.addVertex(x3, y3, z3, QUADRATIC_VERTEX, false);
+// inGeo.addQuadraticVertex(cx, cy, cz,
+// x3, y3, z3,
+// fill, stroke, bezierDetail, vertexCode(), kind);
}
@@ -1405,14 +1486,20 @@ public class PShapeOpenGL extends PShape {
@Override
public void curveDetail(int detail) {
curveDetail = detail;
- pg.curveDetail(detail);
+// pg.curveDetail(detail);
+ if (0 < inGeo.codeCount) {
+ markForTessellation();
+ }
}
@Override
public void curveTightness(float tightness) {
curveTightness = tightness;
- pg.curveTightness(tightness);
+// pg.curveTightness(tightness);
+ if (0 < inGeo.codeCount) {
+ markForTessellation();
+ }
}
@@ -1432,8 +1519,10 @@ public class PShapeOpenGL extends PShape {
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addCurveVertex(x, y, z,
- fill, stroke, curveDetail, vertexCode(), kind);
+ inGeo.addCurveVertex(x, y, z, vertexBreak());
+// inGeo.addVertex(x, y, z, CURVE_VERTEX, vertexBreak());
+// inGeo.addCurveVertex(x, y, z,
+// fill, stroke, curveDetail, vertexCode(), kind);
}
@@ -1805,7 +1894,7 @@ public class PShapeOpenGL extends PShape {
} else if (this.stroke != stroke) {
if (this.stroke) {
// Disabling stroke on a shape previously with
- // stroke needs a re-tesellation in order to remove
+ // stroke needs a re-tessellation in order to remove
// the additional geometry of lines and/or points.
markForTessellation();
stroke = false;
@@ -1926,7 +2015,7 @@ public class PShapeOpenGL extends PShape {
root.setModifiedLineAttributes(firstLineVertex, lastLineVertex);
} else if (is2D()) {
// Changing the stroke weight on a 2D shape needs a
- // re-tesellation in order to replace the old line
+ // re-tessellation in order to replace the old line
// geometry.
markForTessellation();
}
@@ -1940,7 +2029,7 @@ public class PShapeOpenGL extends PShape {
root.setModifiedPointAttributes(firstPointVertex, lastPointVertex);
} else if (is2D()) {
// Changing the stroke weight on a 2D shape needs a
- // re-tesellation in order to replace the old point
+ // re-tessellation in order to replace the old point
// geometry.
markForTessellation();
}
@@ -1976,7 +2065,7 @@ public class PShapeOpenGL extends PShape {
} else {
if (is2D() && strokeJoin != join) {
// Changing the stroke join on a 2D shape needs a
- // re-tesellation in order to replace the old join
+ // re-tessellation in order to replace the old join
// geometry.
markForTessellation();
}
@@ -2000,7 +2089,7 @@ public class PShapeOpenGL extends PShape {
} else {
if (is2D() && strokeCap != cap) {
// Changing the stroke cap on a 2D shape needs a
- // re-tesellation in order to replace the old cap
+ // re-tessellation in order to replace the old cap
// geometry.
markForTessellation();
}
@@ -2260,6 +2349,50 @@ public class PShapeOpenGL extends PShape {
markForTessellation();
}
+ ///////////////////////////////////////////////////////////
+
+ //
+
+ // Vertex codes
+
+
+ @Override
+ public int[] getVertexCodes() {
+ if (family == GROUP) return null;
+ else {
+ if (family == PRIMITIVE || family == PATH) {
+ // the input geometry of primitive and path shapes is built during
+ // tessellation
+ updateTessellation();
+ }
+ if (inGeo.codes == null) return null;
+ return inGeo.codes;
+ }
+ }
+
+
+ @Override
+ public int getVertexCodeCount() {
+ if (family == GROUP) return 0;
+ else {
+ if (family == PRIMITIVE || family == PATH) {
+ // the input geometry of primitive and path shapes is built during
+ // tessellation
+ updateTessellation();
+ }
+ return inGeo.codeCount;
+ }
+ }
+
+
+ /**
+ * One of VERTEX, BEZIER_VERTEX, CURVE_VERTEX, or BREAK.
+ */
+ @Override
+ public int getVertexCode(int index) {
+ return inGeo.codes[index];
+ }
+
///////////////////////////////////////////////////////////
@@ -2267,6 +2400,7 @@ public class PShapeOpenGL extends PShape {
// Tessellated geometry getter.
+
@Override
public PShape getTessellation() {
updateTessellation();
@@ -2362,6 +2496,34 @@ public class PShapeOpenGL extends PShape {
}
+ ///////////////////////////////////////////////////////////
+
+ //
+
+ // Geometry utils
+
+ // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+ @Override
+ public boolean contains(float x, float y) {
+ if (family == PATH) {
+ boolean c = false;
+ for (int i = 0, j = inGeo.vertexCount-1; i < inGeo.vertexCount; j = i++) {
+ if (((inGeo.vertices[3 * i + 1] > y) != (inGeo.vertices[3 * j + 1] > y)) &&
+ (x <
+ (inGeo.vertices[3 * j]-inGeo.vertices[3 * i]) *
+ (y-inGeo.vertices[3 * i + 1]) /
+ (inGeo.vertices[3 * j + 1]-inGeo.vertices[3 * i + 1]) +
+ inGeo.vertices[3 * i])) {
+ c = !c;
+ }
+ }
+ return c;
+ } else {
+ throw new IllegalArgumentException("The contains() method is only implemented for paths.");
+ }
+ }
+
+
///////////////////////////////////////////////////////////
//
@@ -2441,7 +2603,7 @@ public class PShapeOpenGL extends PShape {
protected void tessellate() {
if (root == this && parent == null) {
if (tessGeo == null) {
- tessGeo = pg.newTessGeometry(PGraphicsOpenGL.RETAINED);
+ tessGeo = PGraphicsOpenGL.newTessGeometry(pg, PGraphicsOpenGL.RETAINED);
}
tessGeo.clear();
@@ -2481,12 +2643,13 @@ public class PShapeOpenGL extends PShape {
tessellator.setInGeometry(inGeo);
tessellator.setTessGeometry(tessGeo);
tessellator.setFill(fill || image != null);
+ tessellator.setTexCache(null, null, null);
tessellator.setStroke(stroke);
tessellator.setStrokeColor(strokeColor);
tessellator.setStrokeWeight(strokeWeight);
tessellator.setStrokeCap(strokeCap);
tessellator.setStrokeJoin(strokeJoin);
- tessellator.setTexCache(null, null, null);
+ tessellator.setRenderer(pg);
tessellator.setTransform(matrix);
tessellator.set3D(is3D());
@@ -2520,9 +2683,18 @@ public class PShapeOpenGL extends PShape {
if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals();
tessellator.tessellateQuadStrip();
} else if (kind == POLYGON) {
- if (stroke) inGeo.addPolygonEdges(isClosed);
- tessellator.tessellatePolygon(isSolid, isClosed,
+ boolean bez = inGeo.hasBezierVertex();
+ boolean quad = inGeo.hasQuadraticVertex();
+ boolean curv = inGeo.hasCurveVertex();
+ if (bez || quad) saveBezierVertexSettings();
+ if (curv) {
+ saveCurveVertexSettings();
+ tessellator.resetCurveVertexCount();
+ }
+ tessellator.tessellatePolygon(solid, close,
normalMode == NORMAL_MODE_AUTO);
+ if (bez ||quad) restoreBezierVertexSettings();
+ if (curv) restoreCurveVertexSettings();
}
} else if (family == PRIMITIVE) {
// The input geometry needs to be cleared because the geometry
@@ -2669,7 +2841,7 @@ public class PShapeOpenGL extends PShape {
x2, y2, 0,
x3, y3, 0,
x4, y4, 0,
- fill, stroke);
+ stroke);
tessellator.tessellateQuads();
}
@@ -2678,20 +2850,18 @@ public class PShapeOpenGL extends PShape {
float a = 0, b = 0, c = 0, d = 0;
float tl = 0, tr = 0, br = 0, bl = 0;
boolean rounded = false;
- if (params.length == 4) {
+ int mode = rectMode;
+
+ if (params.length == 4 || params.length == 5) {
+ a = params[0];
+ b = params[1];
+ c = params[2];
+ d = params[3];
+ if (params.length == 5) {
+ mode = (int)(params[4]);
+ }
rounded = false;
- a = params[0];
- b = params[1];
- c = params[2];
- d = params[3];
- } else if (params.length == 5) {
- a = params[0];
- b = params[1];
- c = params[2];
- d = params[3];
- tl = tr = br = bl = params[4];
- rounded = true;
- } else if (params.length == 8) {
+ } else if (params.length == 8 || params.length == 9) {
a = params[0];
b = params[1];
c = params[2];
@@ -2700,20 +2870,60 @@ public class PShapeOpenGL extends PShape {
tr = params[5];
br = params[6];
bl = params[7];
+ if (params.length == 9) {
+ mode = (int)(params[8]);
+ }
rounded = true;
}
+ float hradius, vradius;
+ switch (mode) {
+ case CORNERS:
+ break;
+ case CORNER:
+ c += a; d += b;
+ break;
+ case RADIUS:
+ hradius = c;
+ vradius = d;
+ c = a + hradius;
+ d = b + vradius;
+ a -= hradius;
+ b -= vradius;
+ break;
+ case CENTER:
+ hradius = c / 2.0f;
+ vradius = d / 2.0f;
+ c = a + hradius;
+ d = b + vradius;
+ a -= hradius;
+ b -= vradius;
+ }
+
+ if (a > c) {
+ float temp = a; a = c; c = temp;
+ }
+
+ if (b > d) {
+ float temp = b; b = d; d = temp;
+ }
+
+ float maxRounding = PApplet.min((c - a) / 2, (d - b) / 2);
+ if (tl > maxRounding) tl = maxRounding;
+ if (tr > maxRounding) tr = maxRounding;
+ if (br > maxRounding) br = maxRounding;
+ if (bl > maxRounding) bl = maxRounding;
+
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
if (rounded) {
- inGeo.addRect(a, b, c, d,
- tl, tr, br, bl,
- fill, stroke, bezierDetail, CORNER);
+ saveBezierVertexSettings();
+ inGeo.addRect(a, b, c, d, tl, tr, br, bl, stroke);
tessellator.tessellatePolygon(false, true, true);
+ restoreBezierVertexSettings();
} else {
- inGeo.addRect(a, b, c, d,
- fill, stroke, CORNER);
+ inGeo.addRect(a, b, c, d, stroke);
tessellator.tessellateQuads();
}
}
@@ -2721,17 +2931,52 @@ public class PShapeOpenGL extends PShape {
protected void tessellateEllipse() {
float a = 0, b = 0, c = 0, d = 0;
- if (params.length == 4) {
+ int mode = ellipseMode;
+
+ if (4 <= params.length) {
a = params[0];
b = params[1];
c = params[2];
d = params[3];
+ if (params.length == 5) {
+ mode = (int)(params[4]);
+ }
+ }
+
+ float x = a;
+ float y = b;
+ float w = c;
+ float h = d;
+
+ if (mode == CORNERS) {
+ w = c - a;
+ h = d - b;
+
+ } else if (mode == RADIUS) {
+ x = a - c;
+ y = b - d;
+ w = c * 2;
+ h = d * 2;
+
+ } else if (mode == DIAMETER) {
+ x = a - c/2f;
+ y = b - d/2f;
+ }
+
+ if (w < 0) { // undo negative width
+ x += w;
+ w = -w;
+ }
+
+ if (h < 0) { // undo negative height
+ y += h;
+ h = -h;
}
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addEllipse(a, b, c, d, fill, stroke, CORNER);
+ inGeo.addEllipse(x, y, w, h, fill, stroke);
tessellator.tessellateTriangleFan();
}
@@ -2739,25 +2984,61 @@ public class PShapeOpenGL extends PShape {
protected void tessellateArc() {
float a = 0, b = 0, c = 0, d = 0;
float start = 0, stop = 0;
-// int mode = 0;
- if (params.length == 6 || params.length == 7) {
+ int mode = ellipseMode;
+
+ if (6 <= params.length) {
a = params[0];
b = params[1];
c = params[2];
d = params[3];
start = params[4];
stop = params[5];
- // Not using arc mode since PShape only uses CORNER
-// if (params.length == 7) {
-// mode = (int)(params[6]);
-// }
+ if (params.length == 7) {
+ mode = (int)(params[6]);
+ }
}
- inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
- ambientColor, specularColor, emissiveColor, shininess);
- inGeo.setNormal(normalX, normalY, normalZ);
- inGeo.addArc(a, b, c, d, start, stop, fill, stroke, CORNER);
- tessellator.tessellateTriangleFan();
+ float x = a;
+ float y = b;
+ float w = c;
+ float h = d;
+
+ if (mode == CORNERS) {
+ w = c - a;
+ h = d - b;
+
+ } else if (mode == RADIUS) {
+ x = a - c;
+ y = b - d;
+ w = c * 2;
+ h = d * 2;
+
+ } else if (mode == CENTER) {
+ x = a - c/2f;
+ y = b - d/2f;
+ }
+
+ // make sure the loop will exit before starting while
+ if (!Float.isInfinite(start) && !Float.isInfinite(stop)) {
+ // ignore equal and degenerate cases
+ if (stop > start) {
+ // make sure that we're starting at a useful point
+ while (start < 0) {
+ start += TWO_PI;
+ stop += TWO_PI;
+ }
+
+ if (stop - start > TWO_PI) {
+ start = 0;
+ stop = TWO_PI;
+ }
+ inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
+ ambientColor, specularColor, emissiveColor, shininess);
+ inGeo.setNormal(normalX, normalY, normalZ);
+ inGeo.addArc(x, y, w, h, start, stop, fill, stroke, mode);
+ tessellator.tessellateTriangleFan();
+ }
+ }
}
@@ -2779,18 +3060,36 @@ public class PShapeOpenGL extends PShape {
protected void tessellateSphere() {
- // Getting sphere detail from renderer. Is this correct?
- int nu = pg.sphereDetailU;
- int nv = pg.sphereDetailV;
float r = 0;
- if (params.length == 1) {
+ int nu = sphereDetailU;
+ int nv = sphereDetailV;
+ if (1 <= params.length) {
r = params[0];
+ if (params.length == 2) {
+ nu = nv = (int)params[1];
+ } else if (params.length == 3) {
+ nu = (int)params[1];
+ nv = (int)params[2];
+ }
+ }
+
+ if (nu < 3 || nv < 2) {
+ nu = nv = 30;
+ }
+ int savedDetailU = pg.sphereDetailU;
+ int savedDetailV = pg.sphereDetailV;
+ if (pg.sphereDetailU != nu || pg.sphereDetailV != nv) {
+ pg.sphereDetail(nu, nv);
}
inGeo.setMaterial(fillColor, strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor, shininess);
int[] indices = inGeo.addSphere(r, nu, nv, fill, stroke);
tessellator.tessellateTriangles(indices);
+
+ if (savedDetailU != nu || savedDetailV != nv) {
+ pg.sphereDetail(savedDetailU, savedDetailV);
+ }
}
@@ -2801,18 +3100,19 @@ public class PShapeOpenGL extends PShape {
ambientColor, specularColor, emissiveColor, shininess);
if (vertexCodeCount == 0) { // each point is a simple vertex
- if (vertices[0].length == 2) { // tesellating 2D vertices
+ if (vertices[0].length == 2) { // tessellating 2D vertices
for (int i = 0; i < vertexCount; i++) {
- inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX);
+ inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX, false);
}
} else { // drawing 3D vertices
for (int i = 0; i < vertexCount; i++) {
- inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z], VERTEX);
+ inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z],
+ VERTEX, false);
}
}
} else { // coded set of vertices
int idx = 0;
- int code = BREAK;
+ boolean brk = true;
if (vertices[0].length == 2) { // tessellating a 2D path
@@ -2820,16 +3120,16 @@ public class PShapeOpenGL extends PShape {
switch (vertexCodes[j]) {
case VERTEX:
- inGeo.addVertex(vertices[idx][X], vertices[idx][Y], code);
- code = VERTEX;
+ inGeo.addVertex(vertices[idx][X], vertices[idx][Y], VERTEX, brk);
+ brk = false;
idx++;
break;
- case QUAD_BEZIER_VERTEX:
+ case QUADRATIC_VERTEX:
inGeo.addQuadraticVertex(vertices[idx+0][X], vertices[idx+0][Y], 0,
vertices[idx+1][X], vertices[idx+1][Y], 0,
- fill, stroke, bezierDetail, code);
- code = VERTEX;
+ brk);
+ brk = false;
idx += 2;
break;
@@ -2837,20 +3137,19 @@ public class PShapeOpenGL extends PShape {
inGeo.addBezierVertex(vertices[idx+0][X], vertices[idx+0][Y], 0,
vertices[idx+1][X], vertices[idx+1][Y], 0,
vertices[idx+2][X], vertices[idx+2][Y], 0,
- fill, stroke, bezierDetail, code);
- code = VERTEX;
+ brk);
+ brk = false;
idx += 3;
break;
case CURVE_VERTEX:
- inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0,
- fill, stroke, curveDetail, code);
- code = VERTEX;
+ inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0, brk);
+ brk = false;
idx++;
break;
case BREAK:
- code = BREAK;
+ brk = true;
}
}
} else { // tessellating a 3D path
@@ -2859,24 +3158,23 @@ public class PShapeOpenGL extends PShape {
case VERTEX:
inGeo.addVertex(vertices[idx][X], vertices[idx][Y],
- vertices[idx][Z], code);
- code = VERTEX;
+ vertices[idx][Z], brk);
+ brk = false;
idx++;
break;
- case QUAD_BEZIER_VERTEX:
+ case QUADRATIC_VERTEX:
inGeo.addQuadraticVertex(vertices[idx+0][X],
vertices[idx+0][Y],
vertices[idx+0][Z],
vertices[idx+1][X],
vertices[idx+1][Y],
vertices[idx+0][Z],
- fill, stroke, bezierDetail, code);
- code = VERTEX;
+ brk);
+ brk = false;
idx += 2;
break;
-
case BEZIER_VERTEX:
inGeo.addBezierVertex(vertices[idx+0][X],
vertices[idx+0][Y],
@@ -2887,8 +3185,8 @@ public class PShapeOpenGL extends PShape {
vertices[idx+2][X],
vertices[idx+2][Y],
vertices[idx+2][Z],
- fill, stroke, bezierDetail, code);
- code = VERTEX;
+ brk);
+ brk = false;
idx += 3;
break;
@@ -2896,22 +3194,63 @@ public class PShapeOpenGL extends PShape {
inGeo.addCurveVertex(vertices[idx][X],
vertices[idx][Y],
vertices[idx][Z],
- fill, stroke, curveDetail, code);
- code = VERTEX;
+ brk);
+ brk = false;
idx++;
break;
case BREAK:
- code = BREAK;
+ brk = true;
}
}
}
}
- if (stroke) inGeo.addPolygonEdges(isClosed);
- tessellator.tessellatePolygon(false, isClosed, true);
+ boolean bez = inGeo.hasBezierVertex();
+ boolean quad = inGeo.hasQuadraticVertex();
+ boolean curv = inGeo.hasCurveVertex();
+ if (bez || quad) saveBezierVertexSettings();
+ if (curv) {
+ saveCurveVertexSettings();
+ tessellator.resetCurveVertexCount();
+ }
+ tessellator.tessellatePolygon(false, close, true);
+ if (bez || quad) restoreBezierVertexSettings();
+ if (curv) restoreCurveVertexSettings();
}
+ protected void saveBezierVertexSettings() {
+ savedBezierDetail = pg.bezierDetail;
+ if (pg.bezierDetail != bezierDetail) {
+ pg.bezierDetail(bezierDetail);
+ }
+ }
+
+ protected void restoreBezierVertexSettings() {
+ if (savedBezierDetail != bezierDetail) {
+ pg.bezierDetail(savedBezierDetail);
+ }
+ }
+
+ protected void saveCurveVertexSettings() {
+ savedCurveDetail = pg.curveDetail;
+ savedCurveTightness = pg.curveTightness;
+ if (pg.curveDetail != curveDetail) {
+ pg.curveDetail(curveDetail);
+ }
+ if (pg.curveTightness != curveTightness) {
+ pg.curveTightness(curveTightness);
+ }
+ }
+
+ protected void restoreCurveVertexSettings() {
+ if (savedCurveDetail != curveDetail) {
+ pg.curveDetail(savedCurveDetail);
+ }
+ if (savedCurveTightness != curveTightness) {
+ pg.curveTightness(savedCurveTightness);
+ }
+ }
///////////////////////////////////////////////////////////
@@ -3002,7 +3341,6 @@ public class PShapeOpenGL extends PShape {
if (matrix != null) {
// Some geometric transformations were applied on
// this shape before tessellation, so they are applied now.
- //applyMatrixImpl(matrix);
if (hasPolys) {
tessGeo.applyMatrixOnPolyGeometry(matrix,
firstPolyVertex, lastPolyVertex);
@@ -4039,10 +4377,63 @@ public class PShapeOpenGL extends PShape {
return;
}
+ // Saving the current values to use if the style is re-enabled later
+ savedStroke = stroke;
+ savedStrokeColor = strokeColor;
+ savedStrokeWeight = strokeWeight;
+ savedStrokeCap = strokeCap;
+ savedStrokeJoin = strokeJoin;
+ savedFill = fill;
+ savedFillColor = fillColor;
+ savedTint = tint;
+ savedTintColor = tintColor;
+ savedAmbientColor = ambientColor;
+ savedSpecularColor = specularColor;
+ savedEmissiveColor = emissiveColor;
+ savedShininess = shininess;
+ savedTextureMode = textureMode;
+
super.disableStyle();
}
+ @Override
+ public void enableStyle() {
+ if (savedStroke) {
+ setStroke(true);
+ setStroke(savedStrokeColor);
+ setStrokeWeight(savedStrokeWeight);
+ setStrokeCap(savedStrokeCap);
+ setStrokeJoin(savedStrokeJoin);
+ } else {
+ setStroke(false);
+ }
+
+ if (savedFill) {
+ setFill(true);
+ setFill(savedFillColor);
+ } else {
+ setFill(false);
+ }
+
+ if (savedTint) {
+ setTint(true);
+ setTint(savedTintColor);
+ }
+
+ setAmbient(savedAmbientColor);
+ setSpecular(savedSpecularColor);
+ setEmissive(savedEmissiveColor);
+ setShininess(savedShininess);
+
+ if (image != null) {
+ setTextureMode(savedTextureMode);
+ }
+
+ super.enableStyle();
+ }
+
+
// Applies the styles of g.
@Override
protected void styles(PGraphics g) {
@@ -4216,10 +4607,14 @@ public class PShapeOpenGL extends PShape {
protected void renderPolys(PGraphicsOpenGL g, PImage textureImage) {
+ boolean customShader = g.polyShader != null;
+ boolean needNormals = customShader ? g.polyShader.accessNormals() : false;
+ boolean needTexCoords = customShader ? g.polyShader.accessTexCoords() : false;
+
Texture tex = textureImage != null ? g.getTexture(textureImage) : null;
boolean renderingFill = false, renderingStroke = false;
- BaseShader shader = null;
+ PShader shader = null;
IndexCache cache = tessGeo.polyIndexCache;
for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) {
if (is3D() || (tex != null && (firstLineIndexCache == -1 ||
@@ -4275,19 +4670,18 @@ public class PShapeOpenGL extends PShape {
shader.setShininessAttribute(root.glPolyShininess, 1, PGL.FLOAT,
0, voffset * PGL.SIZEOF_FLOAT);
}
-
- if (tex != null) {
+ if (g.lights || needNormals) {
shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT,
0, 3 * voffset * PGL.SIZEOF_FLOAT);
+ }
+
+ if (tex != null || needTexCoords) {
shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT,
0, 2 * voffset * PGL.SIZEOF_FLOAT);
shader.setTexture(tex);
}
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPolyIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(root.glPolyIndex, icount, ioffset);
}
if (shader != null && shader.bound()) {
@@ -4392,7 +4786,7 @@ public class PShapeOpenGL extends PShape {
protected void renderLines(PGraphicsOpenGL g) {
- LineShader shader = g.getLineShader();
+ PShader shader = g.getLineShader();
shader.bind();
IndexCache cache = tessGeo.lineIndexCache;
@@ -4408,10 +4802,7 @@ public class PShapeOpenGL extends PShape {
shader.setLineAttribute(root.glLineAttrib, 4, PGL.FLOAT,
0, 4 * voffset * PGL.SIZEOF_FLOAT);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glLineIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(root.glLineIndex, icount, ioffset);
}
shader.unbind();
@@ -4492,7 +4883,7 @@ public class PShapeOpenGL extends PShape {
protected void renderPoints(PGraphicsOpenGL g) {
- PointShader shader = g.getPointShader();
+ PShader shader = g.getPointShader();
shader.bind();
IndexCache cache = tessGeo.pointIndexCache;
@@ -4508,10 +4899,7 @@ public class PShapeOpenGL extends PShape {
shader.setPointAttribute(root.glPointAttrib, 2, PGL.FLOAT,
0, 2 * voffset * PGL.SIZEOF_FLOAT);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPointIndex);
- pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE,
- ioffset * PGL.SIZEOF_INDEX);
- pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0);
+ shader.draw(root.glPointIndex, icount, ioffset);
}
shader.unbind();
@@ -4544,9 +4932,10 @@ public class PShapeOpenGL extends PShape {
int perim;
if (0 < size) { // round point
weight = +size / 0.5f;
- perim = PApplet.max(PGraphicsOpenGL.MIN_POINT_ACCURACY,
+ perim = PApplet.min(PGraphicsOpenGL.MAX_POINT_ACCURACY,
+ PApplet.max(PGraphicsOpenGL.MIN_POINT_ACCURACY,
(int) (TWO_PI * weight /
- PGraphicsOpenGL.POINT_ACCURACY_FACTOR)) + 1;
+ PGraphicsOpenGL.POINT_ACCURACY_FACTOR))) + 1;
} else { // Square point
weight = -size / 0.5f;
perim = 5;
diff --git a/core/src/processing/opengl/PointVert.glsl b/core/src/processing/opengl/PointVert.glsl
index 7523e3326..c677ce75b 100644
--- a/core/src/processing/opengl/PointVert.glsl
+++ b/core/src/processing/opengl/PointVert.glsl
@@ -20,13 +20,13 @@
#define PROCESSING_POINT_SHADER
-uniform mat4 projection;
-uniform mat4 modelview;
+uniform mat4 projectionMatrix;
+uniform mat4 modelviewMatrix;
uniform vec4 viewport;
uniform int perspective;
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
attribute vec2 offset;
@@ -38,13 +38,13 @@ vec4 windowToClipVector(vec2 window, vec4 viewport, float clipw) {
}
void main() {
- vec4 pos = modelview * vertex;
- vec4 clip = projection * pos;
+ vec4 pos = modelviewMatrix * position;
+ vec4 clip = projectionMatrix * pos;
if (0 < perspective) {
// Perspective correction (points will look thiner as they move away
// from the view position).
- gl_Position = clip + projection * vec4(offset.xy, 0, 0);
+ gl_Position = clip + projectionMatrix * vec4(offset.xy, 0, 0);
} else {
// No perspective correction.
vec4 offset = windowToClipVector(offset.xy, viewport, clip.w);
diff --git a/core/src/processing/opengl/TexlightVert.glsl b/core/src/processing/opengl/TexlightVert.glsl
index ff981c59c..6542bf8fb 100644
--- a/core/src/processing/opengl/TexlightVert.glsl
+++ b/core/src/processing/opengl/TexlightVert.glsl
@@ -20,8 +20,8 @@
#define PROCESSING_TEXLIGHT_SHADER
-uniform mat4 modelview;
-uniform mat4 transform;
+uniform mat4 modelviewMatrix;
+uniform mat4 transformMatrix;
uniform mat3 normalMatrix;
uniform mat4 texMatrix;
@@ -34,7 +34,7 @@ uniform vec3 lightSpecular[8];
uniform vec3 lightFalloff[8];
uniform vec2 lightSpot[8];
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
attribute vec2 texCoord;
@@ -78,10 +78,10 @@ float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine)
void main() {
// Vertex in clip coordinates
- gl_Position = transform * vertex;
+ gl_Position = transformMatrix * position;
// Vertex in eye coordinates
- vec3 ecVertex = vec3(modelview * vertex);
+ vec3 ecVertex = vec3(modelviewMatrix * position);
// Normal vector in eye coordinates
vec3 ecNormal = normalize(normalMatrix * normal);
diff --git a/core/src/processing/opengl/Texture.java b/core/src/processing/opengl/Texture.java
index 82f0a1f19..1c45ef481 100644
--- a/core/src/processing/opengl/Texture.java
+++ b/core/src/processing/opengl/Texture.java
@@ -1,1632 +1,1644 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2011-12 Ben Fry and Casey Reas
-
- 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; either
- version 2.1 of the License, or (at your option) any later version.
-
- 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.opengl;
-
-import processing.core.PApplet;
-import processing.core.PConstants;
-import processing.core.PGraphics;
-//import processing.core.PImage;
-import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
-/**
- * This class wraps an OpenGL texture.
- * By Andres Colubri
- *
- */
-public class Texture implements PConstants {
- // texture constants
-
- /**
- * Texture with normalized UV.
- */
- protected static final int TEX2D = 0;
- /**
- * Texture with un-normalized UV.
- */
- protected static final int TEXRECT = 1;
-
- /** Point sampling: both magnification and minification filtering are set
- * to nearest */
- protected static final int POINT = 2;
- /** Linear sampling: magnification filtering is nearest, minification set
- * to linear */
- protected static final int LINEAR = 3;
- /** Bilinear sampling: both magnification filtering is set to linear and
- * minification either to linear-mipmap-nearest (linear interplation is used
- * within a mipmap, but not between different mipmaps). */
- protected static final int BILINEAR = 4;
- /** Trilinear sampling: magnification filtering set to linear, minification to
- * linear-mipmap-linear, which offers the best mipmap quality since linear
- * interpolation to compute the value in each of two maps and then
- * interpolates linearly between these two value. */
- protected static final int TRILINEAR = 5;
-
- public int width, height;
-
- public int glName;
- public int glTarget;
- public int glFormat;
- public int glMinFilter;
- public int glMagFilter;
- public int glWrapS;
- public int glWrapT;
- public int glWidth;
- public int glHeight;
-
- protected PGL pgl; // The interface between Processing and OpenGL.
- protected int context; // The context that created this texture.
- protected boolean colorBuffer; // true if it is the color attachment of
- // FrameBuffer object.
-
- protected boolean usingMipmaps;
- protected boolean usingRepeat;
- protected float maxTexcoordU;
- protected float maxTexcoordV;
- protected boolean bound;
-
- protected boolean invertedX;
- protected boolean invertedY;
-
- protected int[] rgbaPixels = null;
- protected IntBuffer pixelBuffer = null;
- protected FrameBuffer tempFbo = null;
-
- /** Modified portion of the texture */
- protected boolean modified;
- protected int mx1, my1, mx2, my2;
-
- protected Object bufferSource;
- protected LinkedList bufferCache = null;
- protected Method disposeBufferMethod;
- public static final int MAX_BUFFER_CACHE_SIZE = 3;
-
- ////////////////////////////////////////////////////////////
-
- // Constructors.
-
-
- public Texture() {
- pgl = PGraphicsOpenGL.pgl;
- context = pgl.createEmptyContext();
-
- colorBuffer = false;
-
- glName = 0;
- }
-
-
- /**
- * Creates an instance of PTexture with size width x height. The texture is
- * initialized (empty) to that size.
- * @param width int
- * @param height int
- */
- public Texture(int width, int height) {
- this(width, height, new Parameters());
- }
-
-
- /**
- * Creates an instance of PTexture with size width x height and with the
- * specified parameters. The texture is initialized (empty) to that size.
- * @param width int
- * @param height int
- * @param params Parameters
- */
- public Texture(int width, int height, Object params) {
- pgl = PGraphicsOpenGL.pgl;
- context = pgl.createEmptyContext();
-
- colorBuffer = false;
-
- glName = 0;
-
- init(width, height, (Parameters)params);
- }
-
-
- @Override
- protected void finalize() throws Throwable {
- try {
-// PApplet.println("finalize texture");
- if (glName != 0) {
- PGraphicsOpenGL.finalizeTextureObject(glName, context);
- }
- } finally {
- super.finalize();
- }
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Init, resize methods
-
-
- /**
- * Sets the size of the image and texture to width x height. If the texture is
- * already initialized, it first destroys the current OpenGL texture object
- * and then creates a new one with the specified size.
- * @param width int
- * @param height int
- */
- public void init(int width, int height) {
- Parameters params;
- if (0 < glName) {
- // Re-initializing a pre-existing texture.
- // We use the current parameters as default:
- params = getParameters();
- } else {
- // Just built-in default parameters otherwise:
- params = new Parameters();
- }
- init(width, height, params);
- }
-
-
- /**
- * Sets the size of the image and texture to width x height, and the
- * parameters of the texture to params. If the texture is already initialized,
- * it first destroys the current OpenGL texture object and then creates a new
- * one with the specified size.
- * @param width int
- * @param height int
- * @param params GLTextureParameters
- */
- public void init(int width, int height, Parameters params) {
- setParameters(params);
- setSize(width, height);
- allocate();
- }
-
-
- /**
- * Initializes the texture using GL parameters
- */
- public void init(int width, int height,
- int glName, int glTarget, int glFormat,
- int glWidth, int glHeight,
- int glMinFilter, int glMagFilter,
- int glWrapS, int glWrapT) {
- this.width = width;
- this.height = height;
-
- this.glName = glName;
- this.glTarget = glTarget;
- this.glFormat = glFormat;
- this.glWidth = glWidth;
- this.glHeight = glHeight;
- this.glMinFilter = glMinFilter;
- this.glMagFilter = glMagFilter;
- this.glWrapS = glWrapS;
- this.glWrapT = glWrapT;
-
- maxTexcoordU = (float)width / glWidth;
- maxTexcoordV = (float)height / glHeight;
-
- usingMipmaps = glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
- glMinFilter == PGL.LINEAR_MIPMAP_LINEAR;
-
- usingRepeat = glWrapS == PGL.REPEAT || glWrapT == PGL.REPEAT;
- }
-
-
- public void resize(int wide, int high) {
- // Marking the texture object as finalized so it is deleted
- // when creating the new texture.
- dispose();
-
- // Creating new texture with the appropriate size.
- Texture tex = new Texture(wide, high, getParameters());
-
- // Copying the contents of this texture into tex.
- tex.set(this);
-
- // Now, overwriting "this" with tex.
- copyObject(tex);
-
- // Nullifying some utility objects so they are recreated with the
- // appropriate size when needed.
- tempFbo = null;
- }
-
-
- /**
- * Returns true if the texture has been initialized.
- * @return boolean
- */
- public boolean available() {
- return 0 < glName;
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Set methods
-
-
- public void set(Texture tex) {
- copyTexture(tex, 0, 0, tex.width, tex.height, true);
- }
-
-
- public void set(Texture tex, int x, int y, int w, int h) {
- copyTexture(tex, x, y, w, h, true);
- }
-
-
- public void set(int texTarget, int texName, int texWidth, int texHeight,
- int w, int h) {
- copyTexture(texTarget, texName, texWidth, texHeight, 0, 0, w, h, true);
- }
-
-
- public void set(int texTarget, int texName, int texWidth, int texHeight,
- int target, int tex, int x, int y, int w, int h) {
- copyTexture(texTarget, texName, texWidth, texHeight, x, y, w, h, true);
- }
-
-
- public void set(int[] pixels) {
- set(pixels, 0, 0, width, height, ARGB);
- }
-
-
- public void set(int[] pixels, int format) {
- set(pixels, 0, 0, width, height, format);
- }
-
-
- public void set(int[] pixels, int x, int y, int w, int h) {
- set(pixels, x, y, w, h, ARGB);
- }
-
-
- public void set(int[] pixels, int x, int y, int w, int h, int format) {
- if (pixels == null) {
- PGraphics.showWarning("The pixels array is null.");
- return;
- }
- if (pixels.length < w * h) {
- PGraphics.showWarning("The pixel array has a length of " +
- pixels.length + ", but it should be at least " +
- w * h);
- return;
- }
-
- if (pixels.length == 0) {
- // Nothing to do (means that w == h == 0) but not an erroneous situation
- return;
- }
-
- boolean enabledTex = false;
- if (!pgl.texturingIsEnabled(glTarget)) {
- pgl.enableTexturing(glTarget);
- enabledTex = true;
- }
- pgl.bindTexture(glTarget, glName);
-
- if (usingMipmaps) {
- if (PGraphicsOpenGL.autoMipmapGenSupported) {
- // Automatic mipmap generation.
- loadPixels(w * h);
- convertToRGBA(pixels, rgbaPixels, format, w, h);
- updatePixelBuffer(rgbaPixels);
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixelBuffer);
- pgl.generateMipmap(glTarget);
- } else {
- // TODO: finish manual mipmap generation, replacing Bitmap with AWT's BufferedImage,
- // making it work in npot textures (embed npot tex into larger pot tex?), subregions,
- // and moving GLUtils.texImage2D (originally from Android SDK) into PGL.
- // Actually, this whole code should go into PGL, so the Android implementation can
- // use Bitmap, and desktop use BufferedImage.
-
- /*
- if (w != width || h != height) {
- System.err.println("Sorry but I don't know how to generate mipmaps for a subregion.");
- return;
- }
-
- // Code by Mike Miller obtained from here:
- // http://insanitydesign.com/wp/2009/08/01/android-opengl-es-mipmaps/
- int w0 = glWidth;
- int h0 = glHeight;
- int[] argbPixels = new int[w0 * h0];
- convertToARGB(pixels, argbPixels, format);
- int level = 0;
- int denom = 1;
-
- // We create a Bitmap because then we use its built-in filtered downsampling
- // functionality.
- Bitmap bitmap = Bitmap.createBitmap(w0, h0, Config.ARGB_8888);
- bitmap.setPixels(argbPixels, 0, w0, 0, 0, w0, h0);
-
- while (w0 >= 1 || h0 >= 1) {
- //First of all, generate the texture from our bitmap and set it to the according level
- GLUtils.texImage2D(glTarget, level, bitmap, 0);
-
- // We are done.
- if (w0 == 1 && h0 == 1) {
- break;
- }
-
- // Increase the mipmap level
- level++;
- denom *= 2;
-
- // Downsampling bitmap. We must eventually arrive to the 1x1 level,
- // and if the width and height are different, there will be a few 1D
- // texture levels just before.
- // This update formula also allows for NPOT resolutions.
- w0 = PApplet.max(1, PApplet.floor((float)glWidth / denom));
- h0 = PApplet.max(1, PApplet.floor((float)glHeight / denom));
- // (see getScaledInstance in AWT Image)
- Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, w0, h0, true);
-
- // Clean up
- bitmap.recycle();
- bitmap = bitmap2;
- }
- */
-
- loadPixels(w * h);
- convertToRGBA(pixels, rgbaPixels, format, w, h);
- updatePixelBuffer(rgbaPixels);
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixelBuffer);
- }
- } else {
- loadPixels(w * h);
- convertToRGBA(pixels, rgbaPixels, format, w, h);
- updatePixelBuffer(rgbaPixels);
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixelBuffer);
- }
-
- pgl.bindTexture(glTarget, 0);
- if (enabledTex) {
- pgl.disableTexturing(glTarget);
- }
-
- updateTexels(x, y, w, h);
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Native set methods
-
-
- public void setNative(int[] pixels) {
- setNative(pixels, 0, 0, width, height);
- }
-
-
- public void setNative(int[] pixels, int x, int y, int w, int h) {
- updatePixelBuffer(pixels);
- setNative(pixelBuffer, x, y, w, h);
- }
-
-
- public void setNative(IntBuffer pixBuf, int x, int y, int w, int h) {
- if (pixBuf == null) {
- pixBuf = null;
- PGraphics.showWarning("The pixel buffer is null.");
- return;
- }
- if (pixBuf.capacity() < w * h) {
- PGraphics.showWarning("The pixel bufer has a length of " +
- pixBuf.capacity() + ", but it should be at least " +
- w * h);
- return;
- }
-
- if (pixBuf.capacity() == 0) {
- // Nothing to do (means that w == h == 0) but not an erroneous situation
- return;
- }
-
- boolean enabledTex = false;
- if (!pgl.texturingIsEnabled(glTarget)) {
- pgl.enableTexturing(glTarget);
- enabledTex = true;
- }
- pgl.bindTexture(glTarget, glName);
-
- if (usingMipmaps) {
- if (PGraphicsOpenGL.autoMipmapGenSupported) {
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixBuf);
- pgl.generateMipmap(glTarget);
- } else {
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixBuf);
- }
- } else {
- pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
- pixBuf);
- }
-
- pgl.bindTexture(glTarget, 0);
- if (enabledTex) {
- pgl.disableTexturing(glTarget);
- }
-
- updateTexels(x, y, w, h);
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Get methods
-
-
- /**
- * Copy texture to pixels. Involves video memory to main memory transfer (slow).
- */
- public void get(int[] pixels) {
- if (pixels == null) {
- throw new RuntimeException("Trying to copy texture to null pixels array");
- }
- if (pixels.length != width * height) {
- throw new RuntimeException("Trying to copy texture to pixels array of " +
- "wrong size");
- }
-
- if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
- }
-
- // Attaching the texture to the color buffer of a FBO, binding the FBO and
- // reading the pixels from the current draw buffer (which is the color
- // buffer of the FBO).
- tempFbo.setColorBuffer(this);
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(tempFbo);
- tempFbo.readPixels();
- PGraphicsOpenGL.popFramebuffer();
-
- tempFbo.getPixels(pixels);
- convertToARGB(pixels);
-
- if (invertedX) flipArrayOnX(pixels, 1);
- if (invertedY) flipArrayOnY(pixels, 1);
- }
-
-
- /**
- * Copies the contents of the texture to the pixels array.
- * @param pixels
- */
-// public void loadPixels(int[] pixels) {
-// if (hasBuffers()) {
-// // Updates the texture AND the pixels array of the image at the same time,
-// // getting the pixels directly from the buffer data (and thus avoiding
-// // expensive transfer between video and main memory).
-// bufferUpdate(pixels);
-// }
-//
-// if (isModified()) {
-// // Regular pixel copy from texture.
-// get(pixels);
-// }
-//
-// setModified(false);
-// }
-
-
- ////////////////////////////////////////////////////////////
-
- // Put methods (the source texture is not resized to cover the entire
- // destination).
-
-
- public void put(Texture tex) {
- copyTexture(tex, 0, 0, tex.width, tex.height, false);
- }
-
-
- public void put(Texture tex, int x, int y, int w, int h) {
- copyTexture(tex, x, y, w, h, false);
- }
-
-
- public void put(int texTarget, int texName, int texWidth, int texHeight,
- int w, int h) {
- copyTexture(texTarget, texName, texWidth, texHeight, 0, 0, w, h, false);
- }
-
-
- public void put(int texTarget, int texName, int texWidth, int texHeight,
- int target, int tex, int x, int y, int w, int h) {
- copyTexture(texTarget, texName, texWidth, texHeight, x, y, w, h, false);
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Get OpenGL parameters
-
-
- /**
- * Returns true or false whether or not the texture is using mipmaps.
- * @return boolean
- */
- public boolean usingMipmaps() {
- return usingMipmaps;
- }
-
-
- public void usingMipmaps(boolean mipmaps, int sampling) {
- if (mipmaps) {
- if (glMinFilter != PGL.LINEAR_MIPMAP_NEAREST &&
- glMinFilter != PGL.LINEAR_MIPMAP_LINEAR) {
- if (sampling == POINT) {
- glMagFilter = PGL.NEAREST;
- glMinFilter = PGL.NEAREST;
- } else if (sampling == LINEAR) {
- glMagFilter = PGL.NEAREST;
- glMinFilter =
- PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
- } else if (sampling == BILINEAR) {
- glMagFilter = PGL.LINEAR;
- glMinFilter =
- PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
- } else if (sampling == TRILINEAR) {
- glMagFilter = PGL.LINEAR;
- glMinFilter =
- PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_LINEAR : PGL.LINEAR;
- } else {
- throw new RuntimeException("Unknown texture filtering mode");
- }
- }
-
- usingMipmaps = true;
- } else {
- if (glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
- glMinFilter == PGL.LINEAR_MIPMAP_LINEAR) {
- glMinFilter = PGL.LINEAR;
- }
- usingMipmaps = false;
- }
-
- bind();
- pgl.texParameteri(glTarget, PGL.TEXTURE_MIN_FILTER, glMinFilter);
- pgl.texParameteri(glTarget, PGL.TEXTURE_MAG_FILTER, glMagFilter);
- if (usingMipmaps) {
- if (PGraphicsOpenGL.autoMipmapGenSupported) {
- pgl.generateMipmap(glTarget);
- } else {
- // TODO: need manual generation here..
- }
- }
- unbind();
- }
-
-
- /**
- * Returns true or false whether or not the texture is using repeat wrap mode
- * along either U or V directions.
- * @return boolean
- */
- public boolean usingRepeat() {
- return usingRepeat;
- }
-
-
- public void usingRepeat(boolean repeat) {
- if (repeat) {
- glWrapS = PGL.REPEAT;
- glWrapT = PGL.REPEAT;
- usingRepeat = true;
- } else {
- glWrapS = PGL.CLAMP_TO_EDGE;
- glWrapT = PGL.CLAMP_TO_EDGE;
- usingRepeat = false;
- }
-
- bind();
- pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_S, glWrapS);
- pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_T, glWrapT);
- unbind();
- }
-
-
- /**
- * Returns the maximum possible value for the texture coordinate U
- * (horizontal).
- * @return float
- */
- public float maxTexcoordU() {
- return maxTexcoordU;
- }
-
-
- /**
- * Returns the maximum possible value for the texture coordinate V (vertical).
- * @return float
- */
- public float maxTexcoordV() {
- return maxTexcoordV;
- }
-
-
- /**
- * Returns true if the texture is inverted along the horizontal direction.
- * @return boolean;
- */
- public boolean invertedX() {
- return invertedX;
- }
-
-
- /**
- * Sets the texture as inverted or not along the horizontal direction.
- * @param v boolean;
- */
- public void invertedX(boolean v) {
- invertedX = v;
- }
-
-
- /**
- * Returns true if the texture is inverted along the vertical direction.
- * @return boolean;
- */
- public boolean invertedY() {
- return invertedY;
- }
-
-
- /**
- * Sets the texture as inverted or not along the vertical direction.
- * @param v boolean;
- */
- public void invertedY(boolean v) {
- invertedY = v;
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Bind/unbind
-
-
- public void bind() {
- // Binding a texture automatically enables texturing for the
- // texture target from that moment onwards. Unbinding the texture
- // won't disable texturing.
- if (!pgl.texturingIsEnabled(glTarget)) {
- pgl.enableTexturing(glTarget);
- }
- pgl.bindTexture(glTarget, glName);
- bound = true;
- }
-
-
- public void unbind() {
- if (pgl.textureIsBound(glTarget, glName)) {
- // We don't want to unbind another texture
- // that might be bound instead of this one.
- if (!pgl.texturingIsEnabled(glTarget)) {
- pgl.enableTexturing(glTarget);
- pgl.bindTexture(glTarget, 0);
- pgl.disableTexturing(glTarget);
- } else {
- pgl.bindTexture(glTarget, 0);
- }
- }
- bound = false;
- }
-
-
- public boolean bound() {
- // A true result might not necessarily mean that texturing is enabled
- // (a texture can be bound to the target, but texturing is disabled).
- return bound;
- }
-
-
- //////////////////////////////////////////////////////////////
-
- // Modified flag
-
-
- public boolean isModified() {
- return modified;
- }
-
-
- public void setModified() {
- modified = true;
- }
-
-
- public void setModified(boolean m) {
- modified = m;
- }
-
-
- public int getModifiedX1() {
- return mx1;
- }
-
-
- public int getModifiedX2() {
- return mx2;
- }
-
-
- public int getModifiedY1() {
- return my1;
- }
-
-
- public int getModifiedY2() {
- return my2;
- }
-
-
- public void updateTexels() {
- updateTexelsImpl(0, 0, width, height);
- }
-
-
- public void updateTexels(int x, int y, int w, int h) {
- updateTexelsImpl(x, y, w, h);
- }
-
-
- protected void updateTexelsImpl(int x, int y, int w, int h) {
- int x2 = x + w;
- int y2 = y + h;
-
- if (!modified) {
- mx1 = PApplet.max(0, x);
- mx2 = PApplet.min(width - 1, x2);
- my1 = PApplet.max(0, y);
- my2 = PApplet.min(height - 1, y2);
- modified = true;
-
- } else {
- if (x < mx1) mx1 = PApplet.max(0, x);
- if (x > mx2) mx2 = PApplet.min(width - 1, x);
- if (y < my1) my1 = PApplet.max(0, y);
- if (y > my2) my2 = y;
-
- if (x2 < mx1) mx1 = PApplet.max(0, x2);
- if (x2 > mx2) mx2 = PApplet.min(width - 1, x2);
- if (y2 < my1) my1 = PApplet.max(0, y2);
- if (y2 > my2) my2 = PApplet.min(height - 1, y2);
- }
- }
-
-
- protected void loadPixels(int len) {
- if (rgbaPixels == null || rgbaPixels.length < len) {
- rgbaPixels = new int[len];
- }
- }
-
-
- protected void updatePixelBuffer(int[] pixels) {
- pixelBuffer = PGL.updateIntBuffer(pixelBuffer, pixels, true);
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Buffer sink interface.
-
-
- public void setBufferSource(Object source) {
- bufferSource = source;
- getSourceMethods();
- }
-
-
- public void copyBufferFromSource(Object natRef, ByteBuffer byteBuf,
- int w, int h) {
- if (bufferCache == null) {
- bufferCache = new LinkedList();
- }
-
- if (bufferCache.size() + 1 <= MAX_BUFFER_CACHE_SIZE) {
- bufferCache.add(new BufferData(natRef, byteBuf.asIntBuffer(), w, h));
- } else {
- // The buffer cache reached the maximum size, so we just dispose
- // the new buffer.
- try {
- disposeBufferMethod.invoke(bufferSource, new Object[] { natRef });
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
-
- public boolean hasBufferSource() {
- return bufferSource != null;
- }
-
-
- public boolean hasBuffers() {
- return bufferSource != null && bufferCache != null &&
- 0 < bufferCache.size();
- }
-
-
- protected boolean bufferUpdate() {
- BufferData data = null;
- try {
- data = bufferCache.remove(0);
- } catch (NoSuchElementException ex) {
- PGraphics.showWarning("Don't have pixel data to copy to texture");
- }
-
- if (data != null) {
- if ((data.w != width) || (data.h != height)) {
- init(data.w, data.h);
- }
- setNative(data.rgbBuf, 0, 0, width, height);
-
- data.dispose();
-
- return true;
- } else {
- return false;
- }
- }
-
-
- protected boolean bufferUpdate(int[] pixels) {
- BufferData data = null;
- try {
- data = bufferCache.remove(0);
- } catch (NoSuchElementException ex) {
- PGraphics.showWarning("Don't have pixel data to copy to texture");
- }
-
- if (data != null) {
- if ((data.w != width) || (data.h != height)) {
- init(data.w, data.h);
- }
- setNative(data.rgbBuf, 0, 0, width, height);
-
- data.rgbBuf.get(pixels);
- convertToARGB(pixels);
-
- data.dispose();
-
- return true;
- } else {
- return false;
- }
- }
-
-
- protected void getSourceMethods() {
- try {
- disposeBufferMethod = bufferSource.getClass().
- getMethod("disposeBuffer", new Class[] { Object.class });
- } catch (Exception e) {
- throw new RuntimeException("Provided source object doesn't have a " +
- "disposeBuffer method.");
- }
- }
-
-
- ////////////////////////////////////////////////////////////
-
- // Utilities
-
-
- /**
- * Flips intArray along the X axis.
- * @param intArray int[]
- * @param mult int
- */
- protected void flipArrayOnX(int[] intArray, int mult) {
- int index = 0;
- int xindex = mult * (width - 1);
- for (int x = 0; x < width / 2; x++) {
- for (int y = 0; y < height; y++) {
- int i = index + mult * y * width;
- int j = xindex + mult * y * width;
-
- for (int c = 0; c < mult; c++) {
- int temp = intArray[i];
- intArray[i] = intArray[j];
- intArray[j] = temp;
-
- i++;
- j++;
- }
-
- }
- index += mult;
- xindex -= mult;
- }
- }
-
-
- /**
- * Flips intArray along the Y axis.
- * @param intArray int[]
- * @param mult int
- */
- protected void flipArrayOnY(int[] intArray, int mult) {
- int index = 0;
- int yindex = mult * (height - 1) * width;
- for (int y = 0; y < height / 2; y++) {
- for (int x = 0; x < mult * width; x++) {
- int temp = intArray[index];
- intArray[index] = intArray[yindex];
- intArray[yindex] = temp;
-
- index++;
- yindex++;
- }
- yindex -= mult * width * 2;
- }
- }
-
-
- /**
- * Reorders a pixel array in the given format into the order required by
- * OpenGL (RGBA). Both arrays are assumed to be of the same length. The width
- * and height parameters are used in the YUV420 to RBGBA conversion.
- * @param intArray int[]
- * @param tIntArray int[]
- * @param arrayFormat int
- * @param w int
- * @param h int
- */
- protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat,
- int w, int h) {
- if (PGL.BIG_ENDIAN) {
- switch (arrayFormat) {
- case ALPHA:
-
- // Converting from xxxA into RGBA. RGB is set to white
- // (0xFFFFFF, i.e.: (255, 255, 255))
- for (int i = 0; i< intArray.length; i++) {
- tIntArray[i] = 0xFFFFFF00 | intArray[i];
- }
- break;
-
- case RGB:
-
- // Converting xRGB into RGBA. A is set to 0xFF (255, full opacity).
- for (int i = 0; i< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = (pixel << 8) | 0xFF;
- }
- break;
-
- case ARGB:
-
- // Converting ARGB into RGBA. Shifting RGB to 8 bits to the left,
- // and bringing A to the first byte.
- for (int i = 0; i< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
- }
- break;
- }
-
- } else {
- // LITTLE_ENDIAN
- // ARGB native, and RGBA opengl means ABGR on windows
- // for the most part just need to swap two components here
- // the sun.cpu.endian here might be "false", oddly enough..
- // (that's why just using an "else", rather than check for "little")
-
- switch (arrayFormat) {
- case ALPHA:
-
- // Converting xxxA into ARGB, with RGB set to white.
- for (int i = 0; i< intArray.length; i++) {
- tIntArray[i] = (intArray[i] << 24) | 0x00FFFFFF;
- }
- break;
-
- case RGB:
-
- // We need to convert xRGB into ABGR,
- // so R and B must be swapped, and the x just made 0xFF.
- for (int i = 0; i< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = 0xFF000000 |
- ((pixel & 0xFF) << 16) |
- ((pixel & 0xFF0000) >> 16) |
- (pixel & 0x0000FF00);
- }
- break;
-
- case ARGB:
-
- // We need to convert ARGB into ABGR,
- // so R and B must be swapped, A and G just brought back in.
- for (int i = 0; i < intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = ((pixel & 0xFF) << 16) |
- ((pixel & 0xFF0000) >> 16) |
- (pixel & 0xFF00FF00);
- }
- break;
-
- }
-
- }
- }
-
-
- /**
- * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be
- * of size width * height.
- * @param intArray int[]
- */
- protected void convertToARGB(int[] intArray) {
- int t = 0;
- int p = 0;
- if (PGL.BIG_ENDIAN) {
-
- // RGBA to ARGB conversion: shifting RGB 8 bits to the right,
- // and placing A 24 bits to the left.
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel = intArray[p++];
- intArray[t++] = (pixel >> 8) | ((pixel << 24) & 0xFF000000);
- }
- }
-
- } else {
-
- // We have to convert ABGR into ARGB, so R and B must be swapped,
- // A and G just brought back in.
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel = intArray[p++];
- intArray[t++] = ((pixel & 0xFF) << 16) |
- ((pixel & 0xFF0000) >> 16) |
- (pixel & 0xFF00FF00);
-
- }
- }
- }
- }
-
-
- ///////////////////////////////////////////////////////////
-
- // Allocate/release texture.
-
-
- protected void setSize(int w, int h) {
- width = w;
- height = h;
-
- if (PGraphicsOpenGL.npotTexSupported) {
- glWidth = w;
- glHeight = h;
- } else {
- glWidth = PGL.nextPowerOfTwo(w);
- glHeight = PGL.nextPowerOfTwo(h);
- }
-
- if (glWidth > PGraphicsOpenGL.maxTextureSize ||
- glHeight > PGraphicsOpenGL.maxTextureSize) {
- glWidth = glHeight = 0;
- throw new RuntimeException("Image width and height cannot be" +
- " larger than " +
- PGraphicsOpenGL.maxTextureSize +
- " with this graphics card.");
- }
-
- // If non-power-of-two textures are not supported, and the specified width
- // or height is non-power-of-two, then glWidth (glHeight) will be greater
- // than w (h) because it is chosen to be the next power of two, and this
- // quotient will give the appropriate maximum texture coordinate value given
- // this situation.
- maxTexcoordU = (float)width / glWidth;
- maxTexcoordV = (float)height / glHeight;
- }
-
-
- /**
- * Allocates the opengl texture object.
- */
- protected void allocate() {
- dispose(); // Just in the case this object is being re-allocated.
-
- boolean enabledTex = false;
- if (!pgl.texturingIsEnabled(glTarget)) {
- pgl.enableTexturing(glTarget);
- enabledTex = true;
- }
-
- context = pgl.getCurrentContext();
- glName = PGraphicsOpenGL.createTextureObject(context);
-
- pgl.bindTexture(glTarget, glName);
- pgl.texParameteri(glTarget, PGL.TEXTURE_MIN_FILTER, glMinFilter);
- pgl.texParameteri(glTarget, PGL.TEXTURE_MAG_FILTER, glMagFilter);
- pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_S, glWrapS);
- pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_T, glWrapT);
- if (PGraphicsOpenGL.anisoSamplingSupported) {
- pgl.texParameterf(glTarget, PGL.TEXTURE_MAX_ANISOTROPY,
- PGraphicsOpenGL.maxAnisoAmount);
- }
-
- // First, we use glTexImage2D to set the full size of the texture (glW/glH
- // might be diff from w/h in the case that the GPU doesn't support NPOT
- // textures)
- pgl.texImage2D(glTarget, 0, glFormat, glWidth, glHeight, 0,
- PGL.RGBA, PGL.UNSIGNED_BYTE, null);
-
- // Makes sure that the texture buffer in video memory doesn't contain
- // any garbage.
- pgl.initTexture(glTarget, PGL.RGBA, width, height);
-
- pgl.bindTexture(glTarget, 0);
- if (enabledTex) {
- pgl.disableTexturing(glTarget);
- }
- bound = false;
- }
-
-
- /**
- * Marks the texture object for deletion.
- */
- protected void dispose() {
- if (glName != 0) {
- PGraphicsOpenGL.finalizeTextureObject(glName, context);
- glName = 0;
- }
- }
-
-
- protected boolean contextIsOutdated() {
- boolean outdated = !pgl.contextIsCurrent(context);
- if (outdated) {
- // Removing the texture object from the renderer's list so it
- // doesn't get deleted by OpenGL. The texture object was
- // automatically disposed when the old context was destroyed.
- PGraphicsOpenGL.removeTextureObject(glName, context);
-
- // And then set the id to zero, so it doesn't try to be
- // deleted when the object's finalizer is invoked by the GC.
- glName = 0;
- }
- return outdated;
- }
-
-
- public void colorBuffer(boolean value) {
- colorBuffer = value;
- }
-
-
- public boolean colorBuffer() {
- return colorBuffer;
- }
-
-
- ///////////////////////////////////////////////////////////
-
- // Utilities.
-
-
- // Copies source texture tex into this.
- protected void copyTexture(Texture tex, int x, int y, int w, int h,
- boolean scale) {
- if (tex == null) {
- throw new RuntimeException("Source texture is null");
- }
-
- if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
- }
-
- // This texture is the color (destination) buffer of the FBO.
- tempFbo.setColorBuffer(this);
- tempFbo.disableDepthTest();
-
- // FBO copy:
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(tempFbo);
- // Clear the color buffer to make sure that the alpha of the
- pgl.clearColor(0, 0, 0, 0);
- pgl.clear(PGL.COLOR_BUFFER_BIT);
- if (scale) {
- // Rendering tex into "this", and scaling the source rectangle
- // to cover the entire destination region.
- pgl.drawTexture(tex.glTarget, tex.glName,
- tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
- x, y, w, h, 0, 0, width, height);
-
- } else {
- // Rendering tex into "this" but without scaling so the contents
- // of the source texture fall in the corresponding texels of the
- // destination.
- pgl.drawTexture(tex.glTarget, tex.glName,
- tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
- x, y, w, h, x, y, w, h);
- }
- PGraphicsOpenGL.popFramebuffer();
- updateTexels(x, y, w, h);
- }
-
-
- // Copies source texture tex into this.
- protected void copyTexture(int texTarget, int texName,
- int texWidth, int texHeight,
- int x, int y, int w, int h, boolean scale) {
- if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
- }
-
- // This texture is the color (destination) buffer of the FBO.
- tempFbo.setColorBuffer(this);
- tempFbo.disableDepthTest();
-
- // FBO copy:
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(tempFbo);
- if (scale) {
- // Rendering tex into "this", and scaling the source rectangle
- // to cover the entire destination region.
- pgl.drawTexture(texTarget, texName,
- texWidth, texHeight, tempFbo.width, tempFbo.height,
- x, y, w, h, 0, 0, width, height);
-
- } else {
- // Rendering tex into "this" but without scaling so the contents
- // of the source texture fall in the corresponding texels of the
- // destination.
- pgl.drawTexture(texTarget, texName,
- texWidth, texHeight, tempFbo.width, tempFbo.height,
- x, y, w, h, x, y, w, h);
- }
- PGraphicsOpenGL.popFramebuffer();
- updateTexels(x, y, w, h);
- }
-
-
- protected void copyObject(Texture src) {
- // The OpenGL texture of this object is replaced with the one from the
- // source object, so we delete the former to avoid resource wasting.
- dispose();
-
- width = src.width;
- height = src.height;
-
- glName = src.glName;
- glTarget = src.glTarget;
- glFormat = src.glFormat;
- glMinFilter = src.glMinFilter;
- glMagFilter = src.glMagFilter;
-
- glWidth= src.glWidth;
- glHeight = src.glHeight;
-
- usingMipmaps = src.usingMipmaps;
- usingRepeat = src.usingRepeat;
- maxTexcoordU = src.maxTexcoordU;
- maxTexcoordV = src.maxTexcoordV;
-
- invertedX = src.invertedX;
- invertedY = src.invertedY;
- }
-
-
- ///////////////////////////////////////////////////////////
-
- // Parameter handling
-
-
- public Parameters getParameters() {
- Parameters res = new Parameters();
-
- if (glTarget == PGL.TEXTURE_2D) {
- res.target = TEX2D;
- }
-
- if (glFormat == PGL.RGB) {
- res.format = RGB;
- } else if (glFormat == PGL.RGBA) {
- res.format = ARGB;
- } else if (glFormat == PGL.ALPHA) {
- res.format = ALPHA;
- }
-
- if (glMagFilter == PGL.NEAREST && glMinFilter == PGL.NEAREST) {
- res.sampling = POINT;
- res.mipmaps = false;
- } else if (glMagFilter == PGL.NEAREST && glMinFilter == PGL.LINEAR) {
- res.sampling = LINEAR;
- res.mipmaps = false;
- } else if (glMagFilter == PGL.NEAREST &&
- glMinFilter == PGL.LINEAR_MIPMAP_NEAREST) {
- res.sampling = LINEAR;
- res.mipmaps = true;
- } else if (glMagFilter == PGL.LINEAR && glMinFilter == PGL.LINEAR) {
- res.sampling = BILINEAR;
- res.mipmaps = false;
- } else if (glMagFilter == PGL.LINEAR &&
- glMinFilter == PGL.LINEAR_MIPMAP_NEAREST) {
- res.sampling = BILINEAR;
- res.mipmaps = true;
- } else if (glMagFilter == PGL.LINEAR &&
- glMinFilter == PGL.LINEAR_MIPMAP_LINEAR) {
- res.sampling = TRILINEAR;
- res.mipmaps = true;
- }
-
- if (glWrapS == PGL.CLAMP_TO_EDGE) {
- res.wrapU = CLAMP;
- } else if (glWrapS == PGL.REPEAT) {
- res.wrapU = REPEAT;
- }
-
- if (glWrapT == PGL.CLAMP_TO_EDGE) {
- res.wrapV = CLAMP;
- } else if (glWrapT == PGL.REPEAT) {
- res.wrapV = REPEAT;
- }
-
- return res;
- }
-
-
- /**
- * Sets texture target and internal format according to the target and
- * type specified.
- * @param target int
- * @param params GLTextureParameters
- */
- protected void setParameters(Parameters params) {
- if (params.target == TEX2D) {
- glTarget = PGL.TEXTURE_2D;
- } else {
- throw new RuntimeException("Unknown texture target");
- }
-
- if (params.format == RGB) {
- glFormat = PGL.RGB;
- } else if (params.format == ARGB) {
- glFormat = PGL.RGBA;
- } else if (params.format == ALPHA) {
- glFormat = PGL.ALPHA;
- } else {
- throw new RuntimeException("Unknown texture format");
- }
-
- if (params.sampling == POINT) {
- glMagFilter = PGL.NEAREST;
- glMinFilter = PGL.NEAREST;
- } else if (params.sampling == LINEAR) {
- glMagFilter = PGL.NEAREST;
- glMinFilter = params.mipmaps && PGL.MIPMAPS_ENABLED ?
- PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
- } else if (params.sampling == BILINEAR) {
- glMagFilter = PGL.LINEAR;
- glMinFilter = params.mipmaps && PGL.MIPMAPS_ENABLED ?
- PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
- } else if (params.sampling == TRILINEAR) {
- glMagFilter = PGL.LINEAR;
- glMinFilter = params.mipmaps && PGL.MIPMAPS_ENABLED ?
- PGL.LINEAR_MIPMAP_LINEAR : PGL.LINEAR;
- } else {
- throw new RuntimeException("Unknown texture filtering mode");
- }
-
- if (params.wrapU == CLAMP) {
- glWrapS = PGL.CLAMP_TO_EDGE;
- } else if (params.wrapU == REPEAT) {
- glWrapS = PGL.REPEAT;
- } else {
- throw new RuntimeException("Unknown wrapping mode");
- }
-
- if (params.wrapV == CLAMP) {
- glWrapT = PGL.CLAMP_TO_EDGE;
- } else if (params.wrapV == REPEAT) {
- glWrapT = PGL.REPEAT;
- } else {
- throw new RuntimeException("Unknown wrapping mode");
- }
-
- usingMipmaps = glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
- glMinFilter == PGL.LINEAR_MIPMAP_LINEAR;
-
- usingRepeat = glWrapS == PGL.REPEAT || glWrapT == PGL.REPEAT;
-
- invertedX = false;
- invertedY = false;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
-
- // Parameters object
-
-
- /**
- * This class stores the parameters for a texture: target, internal format,
- * minimization filter and magnification filter.
- */
- static public class Parameters {
- /**
- * Texture target.
- */
- public int target;
-
- /**
- * Texture internal format.
- */
- public int format;
-
- /**
- * Texture filtering (POINT, LINEAR, BILINEAR or TRILINEAR).
- */
- public int sampling;
-
- /**
- * Use mipmaps or not.
- */
- public boolean mipmaps;
-
- /**
- * Wrapping mode along U.
- */
- public int wrapU;
-
- /**
- * Wrapping mode along V.
- */
- public int wrapV;
-
- /**
- * Sets all the parameters to default values.
- */
- public Parameters() {
- this.target = TEX2D;
- this.format = ARGB;
- this.sampling = BILINEAR;
- this.mipmaps = true;
- this.wrapU = CLAMP;
- this.wrapV = CLAMP;
- }
-
- public Parameters(int format) {
- this.target = TEX2D;
- this.format = format;
- this.sampling = BILINEAR;
- this.mipmaps = true;
- this.wrapU = CLAMP;
- this.wrapV = CLAMP;
- }
-
- public Parameters(int format, int sampling) {
- this.target = TEX2D;
- this.format = format;
- this.sampling = sampling;
- this.mipmaps = true;
- this.wrapU = CLAMP;
- this.wrapV = CLAMP;
- }
-
- public Parameters(int format, int sampling, boolean mipmaps) {
- this.target = TEX2D;
- this.format = format;
- this.mipmaps = mipmaps;
- if (sampling == TRILINEAR && !mipmaps) {
- this.sampling = BILINEAR;
- } else {
- this.sampling = sampling;
- }
- this.wrapU = CLAMP;
- this.wrapV = CLAMP;
- }
-
- public Parameters(int format, int sampling, boolean mipmaps, int wrap) {
- this.target = TEX2D;
- this.format = format;
- this.mipmaps = mipmaps;
- if (sampling == TRILINEAR && !mipmaps) {
- this.sampling = BILINEAR;
- } else {
- this.sampling = sampling;
- }
- this.wrapU = wrap;
- this.wrapV = wrap;
- }
-
- public Parameters(Parameters src) {
- set(src);
- }
-
- public void set(int format) {
- this.format = format;
- }
-
- public void set(int format, int sampling) {
- this.format = format;
- this.sampling = sampling;
- }
-
- public void set(int format, int sampling, boolean mipmaps) {
- this.format = format;
- this.sampling = sampling;
- this.mipmaps = mipmaps;
- }
-
- public void set(Parameters src) {
- this.target = src.target;
- this.format = src.format;
- this.sampling = src.sampling;
- this.mipmaps = src.mipmaps;
- this.wrapU = src.wrapU;
- this.wrapV = src.wrapV;
- }
- }
-
- /**
- * This class stores a buffer copied from the buffer source.
- *
- */
- protected class BufferData {
- int w, h;
- // Native buffer object.
- Object natBuf;
- // Buffer viewed as int.
- IntBuffer rgbBuf;
-
- BufferData(Object nat, IntBuffer rgb, int w, int h) {
- natBuf = nat;
- rgbBuf = rgb;
- this.w = w;
- this.h = h;
- }
-
- void dispose() {
- try {
- // Disposing the native buffer.
- disposeBufferMethod.invoke(bufferSource, new Object[] { natBuf });
- natBuf = null;
- rgbBuf = null;
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-}
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2011-12 Ben Fry and Casey Reas
+
+ 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; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ 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.opengl;
+
+import processing.core.PApplet;
+import processing.core.PConstants;
+import processing.core.PGraphics;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+/**
+ * This class wraps an OpenGL texture.
+ * By Andres Colubri
+ *
+ */
+public class Texture implements PConstants {
+ /**
+ * Texture with normalized UV.
+ */
+ protected static final int TEX2D = 0;
+ /**
+ * Texture with un-normalized UV.
+ */
+ protected static final int TEXRECT = 1;
+
+ /** Point sampling: both magnification and minification filtering are set
+ * to nearest */
+ protected static final int POINT = 2;
+ /** Linear sampling: magnification filtering is nearest, minification set
+ * to linear */
+ protected static final int LINEAR = 3;
+ /** Bilinear sampling: both magnification filtering is set to linear and
+ * minification either to linear-mipmap-nearest (linear interplation is used
+ * within a mipmap, but not between different mipmaps). */
+ protected static final int BILINEAR = 4;
+ /** Trilinear sampling: magnification filtering set to linear, minification to
+ * linear-mipmap-linear, which offers the best mipmap quality since linear
+ * interpolation to compute the value in each of two maps and then
+ * interpolates linearly between these two value. */
+ protected static final int TRILINEAR = 5;
+
+
+ // This constant controls how many times pixelBuffer and rgbaPixels can be
+ // accessed before they are not released anymore. The idea is that if they
+ // have been used only a few times, it doesn't make sense to keep them around.
+ protected static final int MAX_UPDATES = 10;
+
+ // The minimum amount of free JVM's memory (in MB) before pixelBuffer and
+ // rgbaPixels are released every time after they are used.
+ protected static final int MIN_MEMORY = 5;
+
+ public int width, height;
+
+ public int glName;
+ public int glTarget;
+ public int glFormat;
+ public int glMinFilter;
+ public int glMagFilter;
+ public int glWrapS;
+ public int glWrapT;
+ public int glWidth;
+ public int glHeight;
+
+ protected PGL pgl; // The interface between Processing and OpenGL.
+ protected int context; // The context that created this texture.
+ protected boolean colorBuffer; // true if it is the color attachment of
+ // FrameBuffer object.
+
+ protected boolean usingMipmaps;
+ protected boolean usingRepeat;
+ protected float maxTexcoordU;
+ protected float maxTexcoordV;
+ protected boolean bound;
+
+ protected boolean invertedX;
+ protected boolean invertedY;
+
+ protected int[] rgbaPixels = null;
+ protected IntBuffer pixelBuffer = null;
+ protected FrameBuffer tempFbo = null;
+ protected int pixBufUpdateCount = 0;
+ protected int rgbaPixUpdateCount = 0;
+
+ /** Modified portion of the texture */
+ protected boolean modified;
+ protected int mx1, my1, mx2, my2;
+
+ protected Object bufferSource;
+ protected LinkedList bufferCache = null;
+ protected LinkedList usedBuffers = null;
+ protected Method disposeBufferMethod;
+ public static final int MAX_BUFFER_CACHE_SIZE = 3;
+
+ ////////////////////////////////////////////////////////////
+
+ // Constructors.
+
+
+ public Texture() {
+ pgl = PGraphicsOpenGL.pgl;
+ context = pgl.createEmptyContext();
+
+ colorBuffer = false;
+
+ glName = 0;
+ }
+
+
+ /**
+ * Creates an instance of PTexture with size width x height. The texture is
+ * initialized (empty) to that size.
+ * @param width int
+ * @param height int
+ */
+ public Texture(int width, int height) {
+ this(width, height, new Parameters());
+ }
+
+
+ /**
+ * Creates an instance of PTexture with size width x height and with the
+ * specified parameters. The texture is initialized (empty) to that size.
+ * @param width int
+ * @param height int
+ * @param params Parameters
+ */
+ public Texture(int width, int height, Object params) {
+ pgl = PGraphicsOpenGL.pgl;
+ context = pgl.createEmptyContext();
+
+ colorBuffer = false;
+
+ glName = 0;
+
+ init(width, height, (Parameters)params);
+ }
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (glName != 0) {
+ PGraphicsOpenGL.finalizeTextureObject(glName, context);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Init, resize methods
+
+
+ /**
+ * Sets the size of the image and texture to width x height. If the texture is
+ * already initialized, it first destroys the current OpenGL texture object
+ * and then creates a new one with the specified size.
+ * @param width int
+ * @param height int
+ */
+ public void init(int width, int height) {
+ Parameters params;
+ if (0 < glName) {
+ // Re-initializing a pre-existing texture.
+ // We use the current parameters as default:
+ params = getParameters();
+ } else {
+ // Just built-in default parameters otherwise:
+ params = new Parameters();
+ }
+ init(width, height, params);
+ }
+
+
+ /**
+ * Sets the size of the image and texture to width x height, and the
+ * parameters of the texture to params. If the texture is already initialized,
+ * it first destroys the current OpenGL texture object and then creates a new
+ * one with the specified size.
+ * @param width int
+ * @param height int
+ * @param params GLTextureParameters
+ */
+ public void init(int width, int height, Parameters params) {
+ setParameters(params);
+ setSize(width, height);
+ allocate();
+ }
+
+
+ /**
+ * Initializes the texture using GL parameters
+ */
+ public void init(int width, int height,
+ int glName, int glTarget, int glFormat,
+ int glWidth, int glHeight,
+ int glMinFilter, int glMagFilter,
+ int glWrapS, int glWrapT) {
+ this.width = width;
+ this.height = height;
+
+ this.glName = glName;
+ this.glTarget = glTarget;
+ this.glFormat = glFormat;
+ this.glWidth = glWidth;
+ this.glHeight = glHeight;
+ this.glMinFilter = glMinFilter;
+ this.glMagFilter = glMagFilter;
+ this.glWrapS = glWrapS;
+ this.glWrapT = glWrapT;
+
+ maxTexcoordU = (float)width / glWidth;
+ maxTexcoordV = (float)height / glHeight;
+
+ usingMipmaps = glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
+ glMinFilter == PGL.LINEAR_MIPMAP_LINEAR;
+
+ usingRepeat = glWrapS == PGL.REPEAT || glWrapT == PGL.REPEAT;
+ }
+
+
+ public void resize(int wide, int high) {
+ // Marking the texture object as finalized so it is deleted
+ // when creating the new texture.
+ dispose();
+
+ // Creating new texture with the appropriate size.
+ Texture tex = new Texture(wide, high, getParameters());
+
+ // Copying the contents of this texture into tex.
+ tex.set(this);
+
+ // Now, overwriting "this" with tex.
+ copyObject(tex);
+
+ // Nullifying some utility objects so they are recreated with the
+ // appropriate size when needed.
+ tempFbo = null;
+ }
+
+
+ /**
+ * Returns true if the texture has been initialized.
+ * @return boolean
+ */
+ public boolean available() {
+ return 0 < glName;
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Set methods
+
+
+ public void set(Texture tex) {
+ copyTexture(tex, 0, 0, tex.width, tex.height, true);
+ }
+
+
+ public void set(Texture tex, int x, int y, int w, int h) {
+ copyTexture(tex, x, y, w, h, true);
+ }
+
+
+ public void set(int texTarget, int texName, int texWidth, int texHeight,
+ int w, int h) {
+ copyTexture(texTarget, texName, texWidth, texHeight, 0, 0, w, h, true);
+ }
+
+
+ public void set(int texTarget, int texName, int texWidth, int texHeight,
+ int target, int tex, int x, int y, int w, int h) {
+ copyTexture(texTarget, texName, texWidth, texHeight, x, y, w, h, true);
+ }
+
+
+ public void set(int[] pixels) {
+ set(pixels, 0, 0, width, height, ARGB);
+ }
+
+
+ public void set(int[] pixels, int format) {
+ set(pixels, 0, 0, width, height, format);
+ }
+
+
+ public void set(int[] pixels, int x, int y, int w, int h) {
+ set(pixels, x, y, w, h, ARGB);
+ }
+
+
+ public void set(int[] pixels, int x, int y, int w, int h, int format) {
+ if (pixels == null) {
+ PGraphics.showWarning("The pixels array is null.");
+ return;
+ }
+ if (pixels.length < w * h) {
+ PGraphics.showWarning("The pixel array has a length of " +
+ pixels.length + ", but it should be at least " +
+ w * h);
+ return;
+ }
+
+ if (pixels.length == 0) {
+ // Nothing to do (means that w == h == 0) but not an erroneous situation
+ return;
+ }
+
+ boolean enabledTex = false;
+ if (!pgl.texturingIsEnabled(glTarget)) {
+ pgl.enableTexturing(glTarget);
+ enabledTex = true;
+ }
+ pgl.bindTexture(glTarget, glName);
+
+ if (usingMipmaps) {
+ if (PGraphicsOpenGL.autoMipmapGenSupported) {
+ // Automatic mipmap generation.
+ loadPixels(w * h);
+ convertToRGBA(pixels, format, w, h);
+ updatePixelBuffer(rgbaPixels);
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixelBuffer);
+ pgl.generateMipmap(glTarget);
+ } else {
+ // TODO: finish manual mipmap generation, replacing Bitmap with AWT's BufferedImage,
+ // making it work in npot textures (embed npot tex into larger pot tex?), subregions,
+ // and moving GLUtils.texImage2D (originally from Android SDK) into PGL.
+ // Actually, this whole code should go into PGL, so the Android implementation can
+ // use Bitmap, and desktop use BufferedImage.
+
+ /*
+ if (w != width || h != height) {
+ System.err.println("Sorry but I don't know how to generate mipmaps for a subregion.");
+ return;
+ }
+
+ // Code by Mike Miller obtained from here:
+ // http://insanitydesign.com/wp/2009/08/01/android-opengl-es-mipmaps/
+ int w0 = glWidth;
+ int h0 = glHeight;
+ int[] argbPixels = new int[w0 * h0];
+ convertToARGB(pixels, argbPixels, format);
+ int level = 0;
+ int denom = 1;
+
+ // We create a Bitmap because then we use its built-in filtered downsampling
+ // functionality.
+ Bitmap bitmap = Bitmap.createBitmap(w0, h0, Config.ARGB_8888);
+ bitmap.setPixels(argbPixels, 0, w0, 0, 0, w0, h0);
+
+ while (w0 >= 1 || h0 >= 1) {
+ //First of all, generate the texture from our bitmap and set it to the according level
+ GLUtils.texImage2D(glTarget, level, bitmap, 0);
+
+ // We are done.
+ if (w0 == 1 && h0 == 1) {
+ break;
+ }
+
+ // Increase the mipmap level
+ level++;
+ denom *= 2;
+
+ // Downsampling bitmap. We must eventually arrive to the 1x1 level,
+ // and if the width and height are different, there will be a few 1D
+ // texture levels just before.
+ // This update formula also allows for NPOT resolutions.
+ w0 = PApplet.max(1, PApplet.floor((float)glWidth / denom));
+ h0 = PApplet.max(1, PApplet.floor((float)glHeight / denom));
+ // (see getScaledInstance in AWT Image)
+ Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, w0, h0, true);
+
+ // Clean up
+ bitmap.recycle();
+ bitmap = bitmap2;
+ }
+ */
+
+ loadPixels(w * h);
+ convertToRGBA(pixels, format, w, h);
+ updatePixelBuffer(rgbaPixels);
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixelBuffer);
+ }
+ } else {
+ loadPixels(w * h);
+ convertToRGBA(pixels, format, w, h);
+ updatePixelBuffer(rgbaPixels);
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixelBuffer);
+ }
+
+ pgl.bindTexture(glTarget, 0);
+ if (enabledTex) {
+ pgl.disableTexturing(glTarget);
+ }
+
+ releasePixelBuffer();
+ releaseRGBAPixels();
+
+ updateTexels(x, y, w, h);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Native set methods
+
+
+ public void setNative(int[] pixels) {
+ setNative(pixels, 0, 0, width, height);
+ }
+
+
+ public void setNative(int[] pixels, int x, int y, int w, int h) {
+ updatePixelBuffer(pixels);
+ setNative(pixelBuffer, x, y, w, h);
+ releasePixelBuffer();
+ }
+
+
+ public void setNative(IntBuffer pixBuf, int x, int y, int w, int h) {
+ if (pixBuf == null) {
+ pixBuf = null;
+ PGraphics.showWarning("The pixel buffer is null.");
+ return;
+ }
+ if (pixBuf.capacity() < w * h) {
+ PGraphics.showWarning("The pixel bufer has a length of " +
+ pixBuf.capacity() + ", but it should be at least " +
+ w * h);
+ return;
+ }
+
+ if (pixBuf.capacity() == 0) {
+ // Nothing to do (means that w == h == 0) but not an erroneous situation
+ return;
+ }
+
+ boolean enabledTex = false;
+ if (!pgl.texturingIsEnabled(glTarget)) {
+ pgl.enableTexturing(glTarget);
+ enabledTex = true;
+ }
+ pgl.bindTexture(glTarget, glName);
+
+ if (usingMipmaps) {
+ if (PGraphicsOpenGL.autoMipmapGenSupported) {
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixBuf);
+ pgl.generateMipmap(glTarget);
+ } else {
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixBuf);
+ }
+ } else {
+ pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
+ pixBuf);
+ }
+
+ pgl.bindTexture(glTarget, 0);
+ if (enabledTex) {
+ pgl.disableTexturing(glTarget);
+ }
+
+ updateTexels(x, y, w, h);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Get methods
+
+
+ /**
+ * Copy texture to pixels. Involves video memory to main memory transfer (slow).
+ */
+ public void get(int[] pixels) {
+ if (pixels == null) {
+ throw new RuntimeException("Trying to copy texture to null pixels array");
+ }
+ if (pixels.length != width * height) {
+ throw new RuntimeException("Trying to copy texture to pixels array of " +
+ "wrong size");
+ }
+
+ if (tempFbo == null) {
+ tempFbo = new FrameBuffer(glWidth, glHeight);
+ }
+
+ // Attaching the texture to the color buffer of a FBO, binding the FBO and
+ // reading the pixels from the current draw buffer (which is the color
+ // buffer of the FBO).
+ tempFbo.setColorBuffer(this);
+ PGraphicsOpenGL.pushFramebuffer();
+ PGraphicsOpenGL.setFramebuffer(tempFbo);
+ tempFbo.readPixels();
+ PGraphicsOpenGL.popFramebuffer();
+
+ tempFbo.getPixels(pixels);
+ convertToARGB(pixels);
+
+ if (invertedX) flipArrayOnX(pixels, 1);
+ if (invertedY) flipArrayOnY(pixels, 1);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Put methods (the source texture is not resized to cover the entire
+ // destination).
+
+
+ public void put(Texture tex) {
+ copyTexture(tex, 0, 0, tex.width, tex.height, false);
+ }
+
+
+ public void put(Texture tex, int x, int y, int w, int h) {
+ copyTexture(tex, x, y, w, h, false);
+ }
+
+
+ public void put(int texTarget, int texName, int texWidth, int texHeight,
+ int w, int h) {
+ copyTexture(texTarget, texName, texWidth, texHeight, 0, 0, w, h, false);
+ }
+
+
+ public void put(int texTarget, int texName, int texWidth, int texHeight,
+ int target, int tex, int x, int y, int w, int h) {
+ copyTexture(texTarget, texName, texWidth, texHeight, x, y, w, h, false);
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Get OpenGL parameters
+
+
+ /**
+ * Returns true or false whether or not the texture is using mipmaps.
+ * @return boolean
+ */
+ public boolean usingMipmaps() {
+ return usingMipmaps;
+ }
+
+
+ public void usingMipmaps(boolean mipmaps, int sampling) {
+ if (mipmaps) {
+ if (glMinFilter != PGL.LINEAR_MIPMAP_NEAREST &&
+ glMinFilter != PGL.LINEAR_MIPMAP_LINEAR) {
+ if (sampling == POINT) {
+ glMagFilter = PGL.NEAREST;
+ glMinFilter = PGL.NEAREST;
+ } else if (sampling == LINEAR) {
+ glMagFilter = PGL.NEAREST;
+ glMinFilter =
+ PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
+ } else if (sampling == BILINEAR) {
+ glMagFilter = PGL.LINEAR;
+ glMinFilter =
+ PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
+ } else if (sampling == TRILINEAR) {
+ glMagFilter = PGL.LINEAR;
+ glMinFilter =
+ PGL.MIPMAPS_ENABLED ? PGL.LINEAR_MIPMAP_LINEAR : PGL.LINEAR;
+ } else {
+ throw new RuntimeException("Unknown texture filtering mode");
+ }
+ }
+
+ usingMipmaps = true;
+ } else {
+ if (glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
+ glMinFilter == PGL.LINEAR_MIPMAP_LINEAR) {
+ glMinFilter = PGL.LINEAR;
+ }
+ usingMipmaps = false;
+ }
+
+ bind();
+ pgl.texParameteri(glTarget, PGL.TEXTURE_MIN_FILTER, glMinFilter);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_MAG_FILTER, glMagFilter);
+ if (usingMipmaps) {
+ if (PGraphicsOpenGL.autoMipmapGenSupported) {
+ pgl.generateMipmap(glTarget);
+ } else {
+ // TODO: need manual generation here..
+ }
+ }
+ unbind();
+ }
+
+
+ /**
+ * Returns true or false whether or not the texture is using repeat wrap mode
+ * along either U or V directions.
+ * @return boolean
+ */
+ public boolean usingRepeat() {
+ return usingRepeat;
+ }
+
+
+ public void usingRepeat(boolean repeat) {
+ if (repeat) {
+ glWrapS = PGL.REPEAT;
+ glWrapT = PGL.REPEAT;
+ usingRepeat = true;
+ } else {
+ glWrapS = PGL.CLAMP_TO_EDGE;
+ glWrapT = PGL.CLAMP_TO_EDGE;
+ usingRepeat = false;
+ }
+
+ bind();
+ pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_S, glWrapS);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_T, glWrapT);
+ unbind();
+ }
+
+
+ /**
+ * Returns the maximum possible value for the texture coordinate U
+ * (horizontal).
+ * @return float
+ */
+ public float maxTexcoordU() {
+ return maxTexcoordU;
+ }
+
+
+ /**
+ * Returns the maximum possible value for the texture coordinate V (vertical).
+ * @return float
+ */
+ public float maxTexcoordV() {
+ return maxTexcoordV;
+ }
+
+
+ /**
+ * Returns true if the texture is inverted along the horizontal direction.
+ * @return boolean;
+ */
+ public boolean invertedX() {
+ return invertedX;
+ }
+
+
+ /**
+ * Sets the texture as inverted or not along the horizontal direction.
+ * @param v boolean;
+ */
+ public void invertedX(boolean v) {
+ invertedX = v;
+ }
+
+
+ /**
+ * Returns true if the texture is inverted along the vertical direction.
+ * @return boolean;
+ */
+ public boolean invertedY() {
+ return invertedY;
+ }
+
+
+ /**
+ * Sets the texture as inverted or not along the vertical direction.
+ * @param v boolean;
+ */
+ public void invertedY(boolean v) {
+ invertedY = v;
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Bind/unbind
+
+
+ public void bind() {
+ // Binding a texture automatically enables texturing for the
+ // texture target from that moment onwards. Unbinding the texture
+ // won't disable texturing.
+ if (!pgl.texturingIsEnabled(glTarget)) {
+ pgl.enableTexturing(glTarget);
+ }
+ pgl.bindTexture(glTarget, glName);
+ bound = true;
+ }
+
+
+ public void unbind() {
+ if (pgl.textureIsBound(glTarget, glName)) {
+ // We don't want to unbind another texture
+ // that might be bound instead of this one.
+ if (!pgl.texturingIsEnabled(glTarget)) {
+ pgl.enableTexturing(glTarget);
+ pgl.bindTexture(glTarget, 0);
+ pgl.disableTexturing(glTarget);
+ } else {
+ pgl.bindTexture(glTarget, 0);
+ }
+ }
+ bound = false;
+ }
+
+
+ public boolean bound() {
+ // A true result might not necessarily mean that texturing is enabled
+ // (a texture can be bound to the target, but texturing is disabled).
+ return bound;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+
+ // Modified flag
+
+
+ public boolean isModified() {
+ return modified;
+ }
+
+
+ public void setModified() {
+ modified = true;
+ }
+
+
+ public void setModified(boolean m) {
+ modified = m;
+ }
+
+
+ public int getModifiedX1() {
+ return mx1;
+ }
+
+
+ public int getModifiedX2() {
+ return mx2;
+ }
+
+
+ public int getModifiedY1() {
+ return my1;
+ }
+
+
+ public int getModifiedY2() {
+ return my2;
+ }
+
+
+ public void updateTexels() {
+ updateTexelsImpl(0, 0, width, height);
+ }
+
+
+ public void updateTexels(int x, int y, int w, int h) {
+ updateTexelsImpl(x, y, w, h);
+ }
+
+
+ protected void updateTexelsImpl(int x, int y, int w, int h) {
+ int x2 = x + w;
+ int y2 = y + h;
+
+ if (!modified) {
+ mx1 = PApplet.max(0, x);
+ mx2 = PApplet.min(width - 1, x2);
+ my1 = PApplet.max(0, y);
+ my2 = PApplet.min(height - 1, y2);
+ modified = true;
+
+ } else {
+ if (x < mx1) mx1 = PApplet.max(0, x);
+ if (x > mx2) mx2 = PApplet.min(width - 1, x);
+ if (y < my1) my1 = PApplet.max(0, y);
+ if (y > my2) my2 = y;
+
+ if (x2 < mx1) mx1 = PApplet.max(0, x2);
+ if (x2 > mx2) mx2 = PApplet.min(width - 1, x2);
+ if (y2 < my1) my1 = PApplet.max(0, y2);
+ if (y2 > my2) my2 = PApplet.min(height - 1, y2);
+ }
+ }
+
+
+ protected void loadPixels(int len) {
+ if (rgbaPixels == null || rgbaPixels.length < len) {
+ rgbaPixels = new int[len];
+ }
+ }
+
+
+ protected void updatePixelBuffer(int[] pixels) {
+ pixelBuffer = PGL.updateIntBuffer(pixelBuffer, pixels, true);
+ pixBufUpdateCount++;
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Buffer sink interface.
+
+
+ public void setBufferSource(Object source) {
+ bufferSource = source;
+ getSourceMethods();
+ }
+
+
+ public void copyBufferFromSource(Object natRef, ByteBuffer byteBuf,
+ int w, int h) {
+ if (bufferCache == null) {
+ bufferCache = new LinkedList();
+ }
+
+ if (bufferCache.size() + 1 <= MAX_BUFFER_CACHE_SIZE) {
+ bufferCache.add(new BufferData(natRef, byteBuf.asIntBuffer(), w, h));
+ } else {
+ // The buffer cache reached the maximum size, so we just dispose
+ // the new buffer by adding it to the list of used buffers.
+ try {
+ usedBuffers.add(new BufferData(natRef, byteBuf.asIntBuffer(), w, h));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ public void disposeSourceBuffer() {
+ if (usedBuffers == null) return;
+
+ while (0 < usedBuffers.size()) {
+ BufferData data = null;
+ try {
+ data = usedBuffers.remove(0);
+ } catch (NoSuchElementException ex) {
+ PGraphics.showWarning("Cannot remove used buffer");
+ }
+ if (data != null) {
+ data.dispose();
+ }
+ }
+ }
+
+ public void getBufferPixels(int[] pixels) {
+ BufferData data = null;
+ if (usedBuffers != null && 0 < usedBuffers.size()) {
+ // the last used buffer is the one currently stored in the opengl the
+ // texture
+ data = usedBuffers.getLast();
+ } else if (bufferCache != null && 0 < bufferCache.size()) {
+ // The first buffer in the cache will be uploaded to the opengl texture
+ // the next time it is rendered
+ data = bufferCache.getFirst();
+ }
+ if (data != null) {
+ data.rgbBuf.rewind();
+ data.rgbBuf.get(pixels);
+ convertToARGB(pixels);
+ }
+ }
+
+
+ public boolean hasBufferSource() {
+ return bufferSource != null;
+ }
+
+
+ public boolean hasBuffers() {
+ return bufferSource != null && bufferCache != null &&
+ 0 < bufferCache.size();
+ }
+
+
+ protected boolean bufferUpdate() {
+ BufferData data = null;
+ try {
+ data = bufferCache.remove(0);
+ } catch (NoSuchElementException ex) {
+ PGraphics.showWarning("Don't have pixel data to copy to texture");
+ }
+
+ if (data != null) {
+ if ((data.w != width) || (data.h != height)) {
+ init(data.w, data.h);
+ }
+ data.rgbBuf.rewind();
+ setNative(data.rgbBuf, 0, 0, width, height);
+
+ // Putting the buffer in the used buffers list to dispose at the end of
+ // draw.
+ if (usedBuffers == null) {
+ usedBuffers = new LinkedList();
+ }
+ usedBuffers.add(data);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ protected void getSourceMethods() {
+ try {
+ disposeBufferMethod = bufferSource.getClass().
+ getMethod("disposeBuffer", new Class[] { Object.class });
+ } catch (Exception e) {
+ throw new RuntimeException("Provided source object doesn't have a " +
+ "disposeBuffer method.");
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////
+
+ // Utilities
+
+
+ /**
+ * Flips intArray along the X axis.
+ * @param intArray int[]
+ * @param mult int
+ */
+ protected void flipArrayOnX(int[] intArray, int mult) {
+ int index = 0;
+ int xindex = mult * (width - 1);
+ for (int x = 0; x < width / 2; x++) {
+ for (int y = 0; y < height; y++) {
+ int i = index + mult * y * width;
+ int j = xindex + mult * y * width;
+
+ for (int c = 0; c < mult; c++) {
+ int temp = intArray[i];
+ intArray[i] = intArray[j];
+ intArray[j] = temp;
+
+ i++;
+ j++;
+ }
+
+ }
+ index += mult;
+ xindex -= mult;
+ }
+ }
+
+
+ /**
+ * Flips intArray along the Y axis.
+ * @param intArray int[]
+ * @param mult int
+ */
+ protected void flipArrayOnY(int[] intArray, int mult) {
+ int index = 0;
+ int yindex = mult * (height - 1) * width;
+ for (int y = 0; y < height / 2; y++) {
+ for (int x = 0; x < mult * width; x++) {
+ int temp = intArray[index];
+ intArray[index] = intArray[yindex];
+ intArray[yindex] = temp;
+
+ index++;
+ yindex++;
+ }
+ yindex -= mult * width * 2;
+ }
+ }
+
+
+ /**
+ * Reorders a pixel array in the given format into the order required by
+ * OpenGL (RGBA) and stores it into rgbaPixels. The width and height
+ * parameters are used in the YUV420 to RBGBA conversion.
+ * @param pixels int[]
+ * @param format int
+ * @param w int
+ * @param h int
+ */
+ protected void convertToRGBA(int[] pixels, int format, int w, int h) {
+ if (PGL.BIG_ENDIAN) {
+ switch (format) {
+ case ALPHA:
+ // Converting from xxxA into RGBA. RGB is set to white
+ // (0xFFFFFF, i.e.: (255, 255, 255))
+ for (int i = 0; i< pixels.length; i++) {
+ rgbaPixels[i] = 0xFFFFFF00 | pixels[i];
+ }
+ break;
+ case RGB:
+ // Converting xRGB into RGBA. A is set to 0xFF (255, full opacity).
+ for (int i = 0; i< pixels.length; i++) {
+ int pixel = pixels[i];
+ rgbaPixels[i] = (pixel << 8) | 0xFF;
+ }
+ break;
+ case ARGB:
+ // Converting ARGB into RGBA. Shifting RGB to 8 bits to the left,
+ // and bringing A to the first byte.
+ for (int i = 0; i< pixels.length; i++) {
+ int pixel = pixels[i];
+ rgbaPixels[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
+ }
+ break;
+ }
+ } else {
+ // LITTLE_ENDIAN
+ // ARGB native, and RGBA opengl means ABGR on windows
+ // for the most part just need to swap two components here
+ // the sun.cpu.endian here might be "false", oddly enough..
+ // (that's why just using an "else", rather than check for "little")
+ switch (format) {
+ case ALPHA:
+ // Converting xxxA into ARGB, with RGB set to white.
+ for (int i = 0; i< pixels.length; i++) {
+ rgbaPixels[i] = (pixels[i] << 24) | 0x00FFFFFF;
+ }
+ break;
+ case RGB:
+ // We need to convert xRGB into ABGR,
+ // so R and B must be swapped, and the x just made 0xFF.
+ for (int i = 0; i< pixels.length; i++) {
+ int pixel = pixels[i];
+ rgbaPixels[i] = 0xFF000000 |
+ ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
+ (pixel & 0x0000FF00);
+ }
+ break;
+ case ARGB:
+ // We need to convert ARGB into ABGR,
+ // so R and B must be swapped, A and G just brought back in.
+ for (int i = 0; i < pixels.length; i++) {
+ int pixel = pixels[i];
+ rgbaPixels[i] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
+ (pixel & 0xFF00FF00);
+ }
+ break;
+ }
+ }
+ rgbaPixUpdateCount++;
+ }
+
+
+ /**
+ * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be
+ * of size width * height.
+ * @param pixels int[]
+ */
+ protected void convertToARGB(int[] pixels) {
+ int t = 0;
+ int p = 0;
+ if (PGL.BIG_ENDIAN) {
+ // RGBA to ARGB conversion: shifting RGB 8 bits to the right,
+ // and placing A 24 bits to the left.
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel = pixels[p++];
+ pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000);
+ }
+ }
+ } else {
+ // We have to convert ABGR into ARGB, so R and B must be swapped,
+ // A and G just brought back in.
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel = pixels[p++];
+ pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
+ (pixel & 0xFF00FF00);
+ }
+ }
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Allocate/release texture.
+
+
+ protected void setSize(int w, int h) {
+ width = w;
+ height = h;
+
+ if (PGraphicsOpenGL.npotTexSupported) {
+ glWidth = w;
+ glHeight = h;
+ } else {
+ glWidth = PGL.nextPowerOfTwo(w);
+ glHeight = PGL.nextPowerOfTwo(h);
+ }
+
+ if (glWidth > PGraphicsOpenGL.maxTextureSize ||
+ glHeight > PGraphicsOpenGL.maxTextureSize) {
+ glWidth = glHeight = 0;
+ throw new RuntimeException("Image width and height cannot be" +
+ " larger than " +
+ PGraphicsOpenGL.maxTextureSize +
+ " with this graphics card.");
+ }
+
+ // If non-power-of-two textures are not supported, and the specified width
+ // or height is non-power-of-two, then glWidth (glHeight) will be greater
+ // than w (h) because it is chosen to be the next power of two, and this
+ // quotient will give the appropriate maximum texture coordinate value given
+ // this situation.
+ maxTexcoordU = (float)width / glWidth;
+ maxTexcoordV = (float)height / glHeight;
+ }
+
+
+ /**
+ * Allocates the opengl texture object.
+ */
+ protected void allocate() {
+ dispose(); // Just in the case this object is being re-allocated.
+
+ boolean enabledTex = false;
+ if (!pgl.texturingIsEnabled(glTarget)) {
+ pgl.enableTexturing(glTarget);
+ enabledTex = true;
+ }
+
+ context = pgl.getCurrentContext();
+ glName = PGraphicsOpenGL.createTextureObject(context);
+
+ pgl.bindTexture(glTarget, glName);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_MIN_FILTER, glMinFilter);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_MAG_FILTER, glMagFilter);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_S, glWrapS);
+ pgl.texParameteri(glTarget, PGL.TEXTURE_WRAP_T, glWrapT);
+ if (PGraphicsOpenGL.anisoSamplingSupported) {
+ pgl.texParameterf(glTarget, PGL.TEXTURE_MAX_ANISOTROPY,
+ PGraphicsOpenGL.maxAnisoAmount);
+ }
+
+ // First, we use glTexImage2D to set the full size of the texture (glW/glH
+ // might be diff from w/h in the case that the GPU doesn't support NPOT
+ // textures)
+ pgl.texImage2D(glTarget, 0, glFormat, glWidth, glHeight, 0,
+ PGL.RGBA, PGL.UNSIGNED_BYTE, null);
+
+ // Makes sure that the texture buffer in video memory doesn't contain
+ // any garbage.
+ pgl.initTexture(glTarget, PGL.RGBA, width, height);
+
+ pgl.bindTexture(glTarget, 0);
+ if (enabledTex) {
+ pgl.disableTexturing(glTarget);
+ }
+ bound = false;
+ }
+
+
+ /**
+ * Marks the texture object for deletion.
+ */
+ protected void dispose() {
+ if (glName != 0) {
+ PGraphicsOpenGL.finalizeTextureObject(glName, context);
+ glName = 0;
+ }
+ }
+
+
+ protected boolean contextIsOutdated() {
+ boolean outdated = !pgl.contextIsCurrent(context);
+ if (outdated) {
+ // Removing the texture object from the renderer's list so it
+ // doesn't get deleted by OpenGL. The texture object was
+ // automatically disposed when the old context was destroyed.
+ PGraphicsOpenGL.removeTextureObject(glName, context);
+
+ // And then set the id to zero, so it doesn't try to be
+ // deleted when the object's finalizer is invoked by the GC.
+ glName = 0;
+ }
+ return outdated;
+ }
+
+
+ public void colorBuffer(boolean value) {
+ colorBuffer = value;
+ }
+
+
+ public boolean colorBuffer() {
+ return colorBuffer;
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Utilities.
+
+
+ // Copies source texture tex into this.
+ protected void copyTexture(Texture tex, int x, int y, int w, int h,
+ boolean scale) {
+ if (tex == null) {
+ throw new RuntimeException("Source texture is null");
+ }
+
+ if (tempFbo == null) {
+ tempFbo = new FrameBuffer(glWidth, glHeight);
+ }
+
+ // This texture is the color (destination) buffer of the FBO.
+ tempFbo.setColorBuffer(this);
+ tempFbo.disableDepthTest();
+
+ // FBO copy:
+ PGraphicsOpenGL.pushFramebuffer();
+ PGraphicsOpenGL.setFramebuffer(tempFbo);
+ // Clear the color buffer to make sure that the alpha channel is set to
+ // full transparency
+ pgl.clearColor(0, 0, 0, 0);
+ pgl.clear(PGL.COLOR_BUFFER_BIT);
+ if (scale) {
+ // Rendering tex into "this", and scaling the source rectangle
+ // to cover the entire destination region.
+ pgl.drawTexture(tex.glTarget, tex.glName,
+ tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
+ x, y, w, h, 0, 0, width, height);
+
+ } else {
+ // Rendering tex into "this" but without scaling so the contents
+ // of the source texture fall in the corresponding texels of the
+ // destination.
+ pgl.drawTexture(tex.glTarget, tex.glName,
+ tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
+ x, y, w, h, x, y, w, h);
+ }
+ PGraphicsOpenGL.popFramebuffer();
+
+ updateTexels(x, y, w, h);
+ }
+
+
+ // Copies source texture tex into this.
+ protected void copyTexture(int texTarget, int texName,
+ int texWidth, int texHeight,
+ int x, int y, int w, int h, boolean scale) {
+ if (tempFbo == null) {
+ tempFbo = new FrameBuffer(glWidth, glHeight);
+ }
+
+ // This texture is the color (destination) buffer of the FBO.
+ tempFbo.setColorBuffer(this);
+ tempFbo.disableDepthTest();
+
+ // FBO copy:
+ PGraphicsOpenGL.pushFramebuffer();
+ PGraphicsOpenGL.setFramebuffer(tempFbo);
+ if (scale) {
+ // Rendering tex into "this", and scaling the source rectangle
+ // to cover the entire destination region.
+ pgl.drawTexture(texTarget, texName,
+ texWidth, texHeight, tempFbo.width, tempFbo.height,
+ x, y, w, h, 0, 0, width, height);
+
+ } else {
+ // Rendering tex into "this" but without scaling so the contents
+ // of the source texture fall in the corresponding texels of the
+ // destination.
+ pgl.drawTexture(texTarget, texName,
+ texWidth, texHeight, tempFbo.width, tempFbo.height,
+ x, y, w, h, x, y, w, h);
+ }
+ PGraphicsOpenGL.popFramebuffer();
+ updateTexels(x, y, w, h);
+ }
+
+
+ protected void copyObject(Texture src) {
+ // The OpenGL texture of this object is replaced with the one from the
+ // source object, so we delete the former to avoid resource wasting.
+ dispose();
+
+ width = src.width;
+ height = src.height;
+
+ glName = src.glName;
+ glTarget = src.glTarget;
+ glFormat = src.glFormat;
+ glMinFilter = src.glMinFilter;
+ glMagFilter = src.glMagFilter;
+
+ glWidth= src.glWidth;
+ glHeight = src.glHeight;
+
+ usingMipmaps = src.usingMipmaps;
+ usingRepeat = src.usingRepeat;
+ maxTexcoordU = src.maxTexcoordU;
+ maxTexcoordV = src.maxTexcoordV;
+
+ invertedX = src.invertedX;
+ invertedY = src.invertedY;
+ }
+
+
+ // Releases the memory used by pixelBuffer either if the buffer hasn't been
+ // used many times yet, or if the JVM is running low in free memory.
+ protected void releasePixelBuffer() {
+ double freeMB = Runtime.getRuntime().freeMemory() / 1E6;
+ if (pixBufUpdateCount < MAX_UPDATES || freeMB < MIN_MEMORY) {
+ pixelBuffer = null;
+ }
+ }
+
+
+ // Releases the memory used by rgbaPixels either if the array hasn't been
+ // used many times yet, or if the JVM is running low in free memory.
+ protected void releaseRGBAPixels() {
+ double freeMB = Runtime.getRuntime().freeMemory() / 1E6;
+ if (rgbaPixUpdateCount < MAX_UPDATES || freeMB < MIN_MEMORY) {
+ rgbaPixels = null;
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Parameter handling
+
+
+ public Parameters getParameters() {
+ Parameters res = new Parameters();
+
+ if (glTarget == PGL.TEXTURE_2D) {
+ res.target = TEX2D;
+ }
+
+ if (glFormat == PGL.RGB) {
+ res.format = RGB;
+ } else if (glFormat == PGL.RGBA) {
+ res.format = ARGB;
+ } else if (glFormat == PGL.ALPHA) {
+ res.format = ALPHA;
+ }
+
+ if (glMagFilter == PGL.NEAREST && glMinFilter == PGL.NEAREST) {
+ res.sampling = POINT;
+ res.mipmaps = false;
+ } else if (glMagFilter == PGL.NEAREST && glMinFilter == PGL.LINEAR) {
+ res.sampling = LINEAR;
+ res.mipmaps = false;
+ } else if (glMagFilter == PGL.NEAREST &&
+ glMinFilter == PGL.LINEAR_MIPMAP_NEAREST) {
+ res.sampling = LINEAR;
+ res.mipmaps = true;
+ } else if (glMagFilter == PGL.LINEAR && glMinFilter == PGL.LINEAR) {
+ res.sampling = BILINEAR;
+ res.mipmaps = false;
+ } else if (glMagFilter == PGL.LINEAR &&
+ glMinFilter == PGL.LINEAR_MIPMAP_NEAREST) {
+ res.sampling = BILINEAR;
+ res.mipmaps = true;
+ } else if (glMagFilter == PGL.LINEAR &&
+ glMinFilter == PGL.LINEAR_MIPMAP_LINEAR) {
+ res.sampling = TRILINEAR;
+ res.mipmaps = true;
+ }
+
+ if (glWrapS == PGL.CLAMP_TO_EDGE) {
+ res.wrapU = CLAMP;
+ } else if (glWrapS == PGL.REPEAT) {
+ res.wrapU = REPEAT;
+ }
+
+ if (glWrapT == PGL.CLAMP_TO_EDGE) {
+ res.wrapV = CLAMP;
+ } else if (glWrapT == PGL.REPEAT) {
+ res.wrapV = REPEAT;
+ }
+
+ return res;
+ }
+
+
+ /**
+ * Sets texture target and internal format according to the target and
+ * type specified.
+ * @param target int
+ * @param params GLTextureParameters
+ */
+ protected void setParameters(Parameters params) {
+ if (params.target == TEX2D) {
+ glTarget = PGL.TEXTURE_2D;
+ } else {
+ throw new RuntimeException("Unknown texture target");
+ }
+
+ if (params.format == RGB) {
+ glFormat = PGL.RGB;
+ } else if (params.format == ARGB) {
+ glFormat = PGL.RGBA;
+ } else if (params.format == ALPHA) {
+ glFormat = PGL.ALPHA;
+ } else {
+ throw new RuntimeException("Unknown texture format");
+ }
+
+ boolean mipmaps = params.mipmaps && PGL.MIPMAPS_ENABLED;
+ if (mipmaps && !PGraphicsOpenGL.autoMipmapGenSupported) {
+ PGraphics.showWarning("Mipmaps were requested but automatic mipmap " +
+ "generation is not supported and manual " +
+ "generation still not implemented, so mipmaps " +
+ "will be disabled.");
+ mipmaps = false;
+ }
+
+ if (params.sampling == POINT) {
+ glMagFilter = PGL.NEAREST;
+ glMinFilter = PGL.NEAREST;
+ } else if (params.sampling == LINEAR) {
+ glMagFilter = PGL.NEAREST;
+ glMinFilter = mipmaps ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
+ } else if (params.sampling == BILINEAR) {
+ glMagFilter = PGL.LINEAR;
+ glMinFilter = mipmaps ? PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
+ } else if (params.sampling == TRILINEAR) {
+ glMagFilter = PGL.LINEAR;
+ glMinFilter = mipmaps ? PGL.LINEAR_MIPMAP_LINEAR : PGL.LINEAR;
+ } else {
+ throw new RuntimeException("Unknown texture filtering mode");
+ }
+
+ if (params.wrapU == CLAMP) {
+ glWrapS = PGL.CLAMP_TO_EDGE;
+ } else if (params.wrapU == REPEAT) {
+ glWrapS = PGL.REPEAT;
+ } else {
+ throw new RuntimeException("Unknown wrapping mode");
+ }
+
+ if (params.wrapV == CLAMP) {
+ glWrapT = PGL.CLAMP_TO_EDGE;
+ } else if (params.wrapV == REPEAT) {
+ glWrapT = PGL.REPEAT;
+ } else {
+ throw new RuntimeException("Unknown wrapping mode");
+ }
+
+ usingMipmaps = glMinFilter == PGL.LINEAR_MIPMAP_NEAREST ||
+ glMinFilter == PGL.LINEAR_MIPMAP_LINEAR;
+
+ usingRepeat = glWrapS == PGL.REPEAT || glWrapT == PGL.REPEAT;
+
+ invertedX = false;
+ invertedY = false;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Parameters object
+
+
+ /**
+ * This class stores the parameters for a texture: target, internal format,
+ * minimization filter and magnification filter.
+ */
+ static public class Parameters {
+ /**
+ * Texture target.
+ */
+ public int target;
+
+ /**
+ * Texture internal format.
+ */
+ public int format;
+
+ /**
+ * Texture filtering (POINT, LINEAR, BILINEAR or TRILINEAR).
+ */
+ public int sampling;
+
+ /**
+ * Use mipmaps or not.
+ */
+ public boolean mipmaps;
+
+ /**
+ * Wrapping mode along U.
+ */
+ public int wrapU;
+
+ /**
+ * Wrapping mode along V.
+ */
+ public int wrapV;
+
+ /**
+ * Sets all the parameters to default values.
+ */
+ public Parameters() {
+ this.target = TEX2D;
+ this.format = ARGB;
+ this.sampling = BILINEAR;
+ this.mipmaps = true;
+ this.wrapU = CLAMP;
+ this.wrapV = CLAMP;
+ }
+
+ public Parameters(int format) {
+ this.target = TEX2D;
+ this.format = format;
+ this.sampling = BILINEAR;
+ this.mipmaps = true;
+ this.wrapU = CLAMP;
+ this.wrapV = CLAMP;
+ }
+
+ public Parameters(int format, int sampling) {
+ this.target = TEX2D;
+ this.format = format;
+ this.sampling = sampling;
+ this.mipmaps = true;
+ this.wrapU = CLAMP;
+ this.wrapV = CLAMP;
+ }
+
+ public Parameters(int format, int sampling, boolean mipmaps) {
+ this.target = TEX2D;
+ this.format = format;
+ this.mipmaps = mipmaps;
+ if (sampling == TRILINEAR && !mipmaps) {
+ this.sampling = BILINEAR;
+ } else {
+ this.sampling = sampling;
+ }
+ this.wrapU = CLAMP;
+ this.wrapV = CLAMP;
+ }
+
+ public Parameters(int format, int sampling, boolean mipmaps, int wrap) {
+ this.target = TEX2D;
+ this.format = format;
+ this.mipmaps = mipmaps;
+ if (sampling == TRILINEAR && !mipmaps) {
+ this.sampling = BILINEAR;
+ } else {
+ this.sampling = sampling;
+ }
+ this.wrapU = wrap;
+ this.wrapV = wrap;
+ }
+
+ public Parameters(Parameters src) {
+ set(src);
+ }
+
+ public void set(int format) {
+ this.format = format;
+ }
+
+ public void set(int format, int sampling) {
+ this.format = format;
+ this.sampling = sampling;
+ }
+
+ public void set(int format, int sampling, boolean mipmaps) {
+ this.format = format;
+ this.sampling = sampling;
+ this.mipmaps = mipmaps;
+ }
+
+ public void set(Parameters src) {
+ this.target = src.target;
+ this.format = src.format;
+ this.sampling = src.sampling;
+ this.mipmaps = src.mipmaps;
+ this.wrapU = src.wrapU;
+ this.wrapV = src.wrapV;
+ }
+ }
+
+ /**
+ * This class stores a buffer copied from the buffer source.
+ *
+ */
+ protected class BufferData {
+ int w, h;
+ // Native buffer object.
+ Object natBuf;
+ // Buffer viewed as int.
+ IntBuffer rgbBuf;
+
+ BufferData(Object nat, IntBuffer rgb, int w, int h) {
+ natBuf = nat;
+ rgbBuf = rgb;
+ this.w = w;
+ this.h = h;
+ }
+
+ void dispose() {
+ try {
+ // Disposing the native buffer.
+ disposeBufferMethod.invoke(bufferSource, new Object[] { natBuf });
+ natBuf = null;
+ rgbBuf = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/processing/opengl/TextureVert.glsl b/core/src/processing/opengl/TextureVert.glsl
index 5260321fb..87f101536 100644
--- a/core/src/processing/opengl/TextureVert.glsl
+++ b/core/src/processing/opengl/TextureVert.glsl
@@ -20,10 +20,10 @@
#define PROCESSING_TEXTURE_SHADER
-uniform mat4 transform;
+uniform mat4 transformMatrix;
uniform mat4 texMatrix;
-attribute vec4 vertex;
+attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
@@ -31,7 +31,7 @@ varying vec4 vertColor;
varying vec4 vertTexCoord;
void main() {
- gl_Position = transform * vertex;
+ gl_Position = transformMatrix * position;
vertColor = color;
vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
diff --git a/core/todo.txt b/core/todo.txt
index 5cd384a37..c6d6d570b 100644
--- a/core/todo.txt
+++ b/core/todo.txt
@@ -1,16 +1,47 @@
-0219 core (2.0.1)
+0224 core
+X PImage resize() causes PImage not to be rendered in JAVA2D
+X https://github.com/processing/processing/issues/2179
+
+fixed in 2.1
+X draw() called again before finishing on OS X (retina issue)
+X https://github.com/processing/processing/issues/1709
high
-_ draw() called again before finishing on OS X (retina issue)
-_ https://github.com/processing/processing/issues/1709
-_ screen stops updating sometimes with retina
-_ https://github.com/processing/processing/issues/1699
+_ zero alpha values still a problem with retina renderer
+_ https://github.com/processing/processing/issues/2030
+_ Sort out blending differences with P2D/P3D
+_ https://github.com/processing/processing/issues/1844
+_ 'collector' class.. Dict that points to a list
+_ String as a key, int/float/string list as values
+_ blendMode(ADD) is broken with default renderer
+_ https://github.com/processing/processing/issues/2012
+_ may have been introduced between 2.0b7 and 2.0b8
+_ add option to have full screen span across screens
+_ display=all in cmd line
+_ sketchDisplay() -> 0 for all, or 1, 2, 3...
+_ test PGraphicsRetina2D w/ 7u40
+_ make sure that 7u40 doesn't reintroduce starvation issue on retina Macs
_ Linux sometimes not responding correctly w/ the size() command
_ https://github.com/processing/processing/issues/1672
_ clean up requestFocus() stuff
_ make sure it works with retina/canvas/strategy as well
+_ finish PFont.getShape() implementation
+_ needs to have a way to set width/height properly
+_ draw(s) doesn't work on the returned PShape
+_ TGA files writing strangely
+_ https://github.com/processing/processing/issues/2096
+table
+_ addRow() is not efficient, probably need to do the doubling
+_ or have a setIncrement() function?
+_ it would default to 1 on tables loaded from a file
+_ and default to doubling when created with "new Table"
+_ row count and array size are combined.. need to break apart
+_ match and iterators
+_ add match version that returns table that's only a pointer to original
+_ save the constructor for the version that actually copies data
+_ the table pointer version will be speedy and allow chaining
decisions/misc
_ add options for image.save() (or saveImage?)
@@ -45,10 +76,6 @@ _ the registered method for size() also needs to be called
_ get() or copy()? for vectors, image, etc.
_ toArray(), toArray(float[]), toVectorArray(), toVectorArray(PVector[])
_ toColorArray(), toColorArray(float[])...
-_ load/save methods.. is it save("blah.svg") or saveSVG("blah.svg")
-X also works that way with tables
-X decision: useExtension() or something like that
-_ require people to put things in the data folder
_ make sure that loadXxxx() methods are used after init()
_ nasty errors when loadImage/Font/createFont/etc used outside
_ decision: add error messages where possible
@@ -297,6 +324,8 @@ _ http://code.google.com/p/processing/issues/detail?id=182
CORE / PShape
+_ major refactoring for PShape/PShapeOpenGL
+_ https://github.com/processing/processing/issues/1623
_ PShape should be cached as well
_ major surgery to put loadShape() back into PApplet/PGraphics
_ then have the OpenGL or Java2D versions as cached objects
@@ -371,6 +400,9 @@ _ i.e. M with several coords means moveto followed by many linetos
_ also curveto with multiple sets of points is ignored
_ document somehow.. svg viewer will be discontinued
_ http://www.adobe.com/svg/eol.html
+_ PShape getVertex() not implemented properly for SVG files
+X https://code.google.com/p/processing/issues/detail?id=1558
+_ https://github.com/processing/processing/issues/1596
CORE / PVector
@@ -446,7 +478,9 @@ _ shared intf for 3D view data across PGraphicsOpenGL and PGraphicsAndroid3D
_ libraries have to do a lot of casting
_ opengl isn't drawing rectangles out to raw properly with fonts
_ when not in textMode(SHAPE) should have rects
-
+_ InvScreenX, Y, Z to convert screen (mouse) coordinates to model coordinates
+_ https://github.com/processing/processing/issues/1609
+X https://code.google.com/p/processing/issues/detail?id=1571
CORE / Mac OS X
@@ -458,6 +492,9 @@ _ -Xdock:icon=
CORE / Events
+_ Implement a way to disable automatic key repeat
+_ https://github.com/processing/processing/issues/1622
+X https://code.google.com/p/processing/issues/detail?id=1584
_ touch events.. can't do MouseEvent et al with Android
_ http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
_ http://www.html5rocks.com/en/mobile/touch.html
@@ -467,8 +504,6 @@ _ touchEvent(), gestureEvent()?
LIBRARIES / PDF
-_ pdf not rendering unicode with beginRecord()
-_ http://code.google.com/p/processing/issues/detail?id=90
_ beginRecord() doesn't use current settings of the sketch
_ sometimes reported as a bug, but probably not a good way to
_ consistently carry these over
diff --git a/done.txt b/done.txt
index c914961d9..100f787e8 100644
--- a/done.txt
+++ b/done.txt
@@ -1,3 +1,351 @@
+0223 pde (2.1)
+X reset font smoothing for everyone to its default by changing the pref
+X To reset everyone's default, replaced editor.antialias with editor.smooth
+X for 2.1. Fonts are unusably gross on OS X (and Linux) w/o smoothing and
+X the Oracle JVM, and many longtime users have anti-aliasing turned off.
+X https://github.com/processing/processing/issues/2164
+X https://github.com/processing/processing/issues/2160
+X Add option to not embed the Java runtime (saves space, but breakage)
+X return code needs to be 1 instead of 0 w/ Commander
+X https://github.com/processing/processing/issues/1798#issuecomment-26711847
+X additional font tweaks due to decreased legibility with Oracle Java
+X type looks a little feeble on OS X with non-retina machines
+X https://github.com/processing/processing/issues/2135
+X should we increase the size of the mode dropdown?
+X processing-java broken in 2.1 beta 1 on OS X
+X https://github.com/processing/processing/issues/2159
+X need to use the embedded Java, different classpath, etc
+X also might be time to put something in to check the version
+
+
+0222 pde (2.1b1)
+X MovieMaker needs to be compiling as 1.6
+X deal with null/missing folders for Tools and Modes
+X https://github.com/processing/processing/issues/2068
+o bad JS mode causing crash on startup
+X https://github.com/processing/processing/issues/2088
+X looks like issue that was covered in 2.0.3 changes
+X non-compliant libraries cause crash on "Add Library"
+X https://github.com/processing/processing/issues/2026
+X Open new PDE maximized when current PDE is maximized
+X https://github.com/processing/processing/issues/1984
+X https://github.com/processing/processing/pull/2037
+X incorporate the new serial library
+X https://github.com/processing/processing/pull/2093
+X cmd-left is bringing up the text area popup
+X https://github.com/processing/processing/issues/2103
+X still having right-click issues (re-opened)
+X https://github.com/processing/processing/issues/2103
+X bad tool brings down the environment
+X http://code.google.com/p/processing/issues/detail?id=798
+X https://github.com/processing/processing/issues/836
+
+cleaning
+o the first time someone hides a tab, put up a msg explaining what it does
+o "don't warn me about this anymore"
+X removed this feature a while back
+o document the move of the auto format menu
+o in the book(s)? in the reference?
+o jer: opengl2 tutorial
+o jer: android tutorial
+o probably later: examples into categories based on difficulty
+o add ratings/difficult level to examples online and in the pde
+o go through examples, figure out how to do many on the site w/ js instead
+X import p5 reference into the javadoc
+o freeze after splash screen on OS X (looks like core.jar in the path)
+X https://github.com/processing/processing/issues/1872
+X can't really fix this
+
+fonts/prefs
+X update with bold version of Source Code Pro
+X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro
+X instead of semibold, which wouldn't correctly connect to the other fonts
+X does editor line status work?
+X not sure what this one was, but added anti-aliasing to the status
+X Editor.applyPreferences() -> painter.setFont() removed
+X need to instead update defaults, then run from there
+X then call repaint() on the text area? or invalidate()? or the painter?
+X make sure font family change is working
+X make sure fonts can actually update size/etc in prefs
+X slightly gray background
+X bgcolor wasn't getting set (since fgcolor was set elsewhere)
+X spacing problem with large sizes (on retina?)
+X not just retina, was problem with non-mono text from Java
+X control text size in console
+o why aren't prefs from theme.txt showing up in preferences.txt? hrm
+o or rather, why can't they be overridden?
+X because theme.txt data is a different animal / that's part of the point
+X should fonts at least be in prefs.txt?
+X http://code.google.com/p/processing/issues/detail?id=226
+X https://github.com/processing/processing/issues/265
+X console font in EditorConsole
+X Font font = Preferences.getFont("console.font");
+o fix console font on Windows and Linux with 7u40
+X couldn't reproduce, but shouldn't be a problem with the rewrite
+X the message area text also looks ugly.. can we fix?
+X add pref to select PDE font (so that CJKV languages work better)
+X https://github.com/processing/processing/issues/2078
+X should we embed the PDE font into the JRE?
+X this would allow it to show up in the menus, etc
+X type in the status area is gross on retina displays and 7u40
+X no longer require restart of Processing when changing the font
+
+serial
+X closing several bugs because no longer relevant
+X need 64-bit version of RXTX library
+X http://code.google.com/p/processing/issues/detail?id=1237
+X https://github.com/processing/processing/issues/1275
+X serial still causing problems on OS X
+X http://code.google.com/p/processing/issues/detail?id=52
+X had already been closed
+X serial ports missing from list (OS X)
+X http://code.google.com/p/processing/issues/detail?id=52
+X also was marked fixed...
+X Serial.write problem with Bluetooth SPP virtual serial port
+X http://code.google.com/p/processing/issues/detail?id=318
+X was marked duplicate of #52
+X Serial silently fails when invalid port entered as string
+o https://github.com/processing/processing/issues/2114
+X Serial Issue for RPi (and others)
+o https://github.com/processing/processing/issues/2066
+X RXTX-2.1-7 doesn't list ports created in /dev with VirtualSerialPortApp
+o https://github.com/processing/processing/issues/1460
+X Bluetooth serial problems on Windows when connecting to Arduino device
+o https://github.com/processing/processing/issues/1374
+
+movie maker
+o moviemaker video sizes / usability
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Exhibition;action=display;num=1211318862
+X add gamma, better image options, etc to MovieMaker
+X TGA files cause Movie Maker to not work properly
+X https://github.com/processing/processing/issues/1933
+o move Movie Maker out to its own separate tool package (with separate build)
+X http://code.google.com/p/processing/issues/detail?id=837
+X https://github.com/processing/processing/issues/875
+X basically done in more recent releases
+X fix file selection dialog with MovieMaker
+X copied from PApplet, but not importing PApplet
+
+build
+X remove video library for other platforms in download
+X update apple.jar file with new version
+X https://developer.apple.com/legacy/library/samplecode/AppleJavaExtensions/Introduction/Intro.html
+X remove Mangler from tools/Mangler
+o update tools/howto.txt to just point at the correct online location
+X just remove the howto file
+X appbundler fixes/changes
+X the "Classes" folder is included
+X appears to be line 138 of main.m
+o maybe this is a holdover from OS X Java? don't know.
+X icon location uses path, even when embedded
+X add indents to the Info.plist output file
+X inside writeInfoPlist from AppBundlerTask.java
+o use Contents/Resources/Java instead of Contents/Java?
+o this is in main.m. why the change?
+X doesn't make any difference, just use Contents/Java
+X any missing args from our app (copyrights/versions?)
+X add MinimumSystemVersion for 10.7.3
+X https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-113253
+X copy GenericDocumentIcon.icns for placeholder icon
+X from /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/
+X the javadoc includes java.io.* and java.lang.* prefixes.. why?
+X re-run and and check in
+X upload javadoc updates
+X need to require JDK 7u40 to be installed on OS X
+X remove JAVA_HOME requirement from build.xml
+X what's needed on OS X? just the JDK 7u40?
+X remove Java FX from OS X build
+X remove Java FX during Linux builds
+X remove Java FX during Windows builds
+X remove javafx from the embed
+X more about optional files:
+X http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html
+
+build instructions and other doc
+X update the build instructions page
+X http://code.google.com/p/processing/wiki/BuildInstructions
+X update github instructions
+X https://github.com/processing/processing/issues/1629
+X https://github.com/processing/processing/wiki/Build-Instructions
+X only JRE needed at this point
+X switched over to Java 7
+o "unable to locate tools.jar" (Windows) can be ignored
+X JAVA_HOME warnings from Ant can also be ignored
+X updates for macosx instructions
+X JDK 7u45 is needed (or whatever version currently in the build)
+X to build appbundler, you'll need Xcode
+X and the command line tools Preferences > Downloads > Command Line Tools
+X appbundler will have an NPE if the osx binary isn't built
+X also need to have 10.8 version of the SDK (old Xcode won't work)
+o add notes to build instructions re: building core with eclipse
+X changing JRE might be a problem for fonts on Linux
+X where the JRE is often replaced
+X and where the font is needed most
+X make note of this on the platforms page
+X also make note re: only JRE needed (instead of JDK)
+X http://wiki.processing.org/index.php?title=Supported_Platforms&action=edit§ion=4
+X now Info.plist.tmpl instead of template.plist
+X can be embedded in a sketch
+X name change due to major modifications
+
+7u40 macosx
+X make OS X launch from its local JRE
+X also need to have a central menubar
+X add the offscreen window hack
+X otherwise mode change causes "do you want to quit?" on OS X
+X remove 32- and 64-bit preference from Preferences on OS X
+o try the bundle on Mac Mini running 10.6
+X we become full 64-bit on OS X
+X meaning that the macosx32 video library goes away
+X and the preference for launching in 32- or 64-bit mode
+X package Java 7u40 version of the app
+X docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html
+X http://www.intransitione.com/blog/take-java-to-app-store/
+X retina support http://bugs.sun.com/view_bug.do?bug_id=8009754
+X useful retina digging/findings for Oracle Java
+X http://bulenkov.com/2013/06/23/retina-support-in-oracle-jdk-1-7/
+X 7u40 target release is "late August"
+X http://openjdk.java.net/projects/jdk7u/releases/7u40.html
+X Contents/Java/Classes folder is added to java.class.path
+X so the folder must exist otherwise the ECJ compiler will crash
+X once fixed, remove notes from JavaBuild.java
+X "Are you sure you want to quit?" when switching modes on Oracle JVM
+X default menu bar is still broken
+X http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267
+X add appbundler.jar, otherwise folks have to include Xcode
+
+export
+X change app stub in OS X exported application
+X make note re: app export being slower, and resulting app much larger
+X change how export is handled
+X remove ability to export cross-platform apps
+X add ability to embed the current JRE
+X only going to embed always... consider option to disable it later
+o the case for the embedded JRE
+o https://github.com/processing/processing/issues/2104
+X major edits to http://wiki.processing.org/w/Export_Info_and_Tips
+
+
+0221 pde (2.0.3)
+X add double quotes to readlink call, fixes issue w/ paths and spaces
+X https://github.com/processing/processing/pull/2027
+X fix submitted by hamoid
+
+
+0220 pde (2.0.2)
+X fix "less less" typo
+X https://github.com/processing/processing/issues/1928
+X slash breaks syntax highlighting (with spaces)
+X https://github.com/processing/processing/issues/1681
+X Fix from Github user hamzaissa
+X selectInput() in exported OS X sketch treats .app package as a folder
+X https://github.com/processing/processing/issues/1959
+X waiting on retina support for JDK 7
+o b86 supposed to have some support (not available yet)
+o http://jdk8.java.net/download.html
+X code with a NUL character causes an error
+X https://github.com/processing/processing/issues/1973
+X also remove NUL characters when loading a file
+X Add "Processing Foundation" to the Help menu
+X https://github.com/processing/processing/issues/1908
+X Update JNA from 3.2.4 to 3.5.2
+X https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/3.5.2/jna-3.5.2.jar
+X https://maven.java.net/content/repositories/releases/net/java/dev/jna/platform/3.5.2/platform-3.5.2.jar
+X problem with associating .pde files
+X https://github.com/processing/processing/issues/286
+X http://code.google.com/p/processing/issues/detail?id=247
+o In regedit: Navigate to Computer\HKEY_CLASSES_ROOT\Applications and find your .exe name. Navigate under its name to shell>open>command. In the Default change its location to the actual location of the executable, hit okay and then try and reassociate the file type as you normally would.
+X UnsatisfiedLinkError causes huge message...
+X error report cleanups haven't been fixed yet
+X reported by Dan
+X this should be better now
+X add exception wrapper for startup
+X Add methods to move files to Trash/Recycle Bin where available
+X allow delete of files in unsaved sketches
+X https://github.com/processing/processing/issues/1942
+X https://github.com/processing/processing/pull/1945
+X proxy server requirement causes problems
+X contrib manager, update checks are broken
+X https://github.com/processing/processing/issues/1476
+X might be able to fix this with something in preferences.txt?
+X http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
+o Update Java version in the download to be the latest Java 6
+o https://github.com/processing/processing/issues/1841
+X try to use appbundler to create a version that includes a JRE (JDK)
+X http://java.net/downloads/appbundler/appbundler.html
+X docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html
+X http://www.intransitione.com/blog/take-java-to-app-store/
+X hobbling along, should be ready soon
+
+cleaning/earlier
+X common error messages
+X with a proper list, we can add links when throwing an error in the PDE
+X Dan started this on the Wiki
+o build is currently broken for fresh checkout due to changes to file layout
+o something that gets fixed by 'make clean'
+o also test on windows and linux
+o add a check to make sure that people aren't running from the dmg
+o doesn't actually cause any problems, so don't bother?
+o code to hide menubar.. just include JNA and call from there?
+NSMenu.setMenubarVisible(false);
+Then we used Cocoa via JNI:
+if([NSMenu menuBarVisible]){
+ [NSMenu setMenuBarVisible:NO];
+}
+You can't do that from the AWT event thread. You need to do a -performSelectorOnMainThread to do that on the AppKit event thread.
+Please see for more information, particularly the section about "Calling AppKit from AWT/Swing".
+
+manager
+X change location of the manager download
+X check to see if manager items from the download can be updated
+X oops, probably not, because they're part of the distribution
+X and folks won't be able to write to those directories
+X changed manager to go to download.processing.org/latest.txt
+X and uses a redirect from there (hopeully that's followed?)
+X libraries need to support multiple categories
+X https://github.com/processing/processing/issues/1970
+X restrict library categories to the ones in the document
+X if it's not correct, shows up as 'other'
+X catch Error (not just Exception) objects during load
+X handles UnsupportedClassVersionError and others
+X argh.. the 'old' folder is really poorly done
+X attempt to install multiple will cause havoc (fail because 'old' exists)
+o remove flagging for deletion
+o half-installed mode causes a lot of trouble
+o maybe it's reading from tmp folders?
+o https://github.com/processing/processing/issues/1875
+X can't fix, no response
+X remove "Compilations" category for libraries
+X modes shouldn't have categories?
+X was counting "Unknown" as a category
+X modes and tools require restart (per ContributionType class)
+X but no message is provided anywhere?
+X mode install requires restart *and* still doesn't show as installed
+X even though it gets added to the modes menu properly after the restart
+X https://github.com/processing/processing/issues/1782
+X Update example list when library is installed
+X https://github.com/processing/processing/issues/1909
+X https://github.com/processing/processing/pull/1925
+X Contributed modes should show up in mode menu after installation
+X waiting for fixed CoffeeScript mode to test this one
+X https://github.com/processing/processing/issues/1504
+X http://code.google.com/p/processing/issues/detail?id=1466
+X modes require restart, that's now properly shown as a message
+
+
+0219 pde (2.0.1)
+X modes, tools, libraries not copying/moving properly on Windows
+X https://github.com/processing/processing/issues/1781
+X undo seems to not be going to the right location (now with example)
+X https://github.com/processing/processing/issues/707
+X http://code.google.com/p/processing/issues/detail?id=668
+X fixes from Josh Giesbrecht
+X line ending problem with args.txt for Windows when exporting from others
+X (exporting from OS X to Windows)
+X https://github.com/processing/processing/issues/1890
+X add option to remove the background image at the top of the window
+
+
0218 pde (2.0)
X Example window has the Java application icon
X https://github.com/processing/processing/issues/1800
diff --git a/experimental/.classpath b/experimental/.classpath
deleted file mode 100644
index 5bb5a9eb3..000000000
--- a/experimental/.classpath
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/experimental/build.xml b/experimental/build.xml
deleted file mode 100644
index 2e0f18baa..000000000
--- a/experimental/build.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-