diff --git a/README.md b/README.md
index 55aaa792a..c01b621bd 100644
--- a/README.md
+++ b/README.md
@@ -19,8 +19,7 @@ The [processing-web](https://github.com/processing/processing-web/) repository
contains reference, examples, and the site.
(Please use that link to file issues regarding the web site, the examples, or the reference.)
-The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions),
-although they [need an update](https://github.com/processing/processing/issues/1629).
+The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions).
Someday we'll also write code style guidelines, fix all these bugs,
throw together hundreds of unit tests, and solve the Israeli-Palestinian conflict.
diff --git a/app/.classpath b/app/.classpath
index eb8980d92..25495070c 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -7,13 +7,8 @@
-
+
-
-
-
-
-
diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs
index da7176c57..60fcdf705 100644
--- a/app/.settings/org.eclipse.jdt.core.prefs
+++ b/app/.settings/org.eclipse.jdt.core.prefs
@@ -1,13 +1,14 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
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
@@ -47,6 +48,7 @@ org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignor
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=ignore
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
@@ -67,6 +69,7 @@ org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
@@ -90,9 +93,10 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
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/.settings/org.eclipse.ltk.core.refactoring.prefs b/app/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 000000000..b196c64a3
--- /dev/null
+++ b/app/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/app/build.xml b/app/build.xml
old mode 100644
new mode 100755
index c8d8ef937..1dc84edc3
--- a/app/build.xml
+++ b/app/build.xml
@@ -56,35 +56,7 @@
-
-
-
-
-
+
+ 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
index 098e6a5db..6b4f86bce 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -35,7 +35,7 @@ import javax.swing.tree.*;
import processing.app.contrib.*;
import processing.core.*;
-
+import processing.mode.java.JavaMode;
/**
* The base class for the main processing application.
@@ -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 = 221;
+ // updating the values, due to javac inlining the static final values.
+ static private final int REVISION = 228;
/** This might be replaced by main() if there's a lib/version.txt file. */
- static private String VERSION_NAME = "0221"; //$NON-NLS-1$
+ static private String VERSION_NAME = "0228"; //$NON-NLS-1$
/** Set true if this a proper release rather than a numbered revision. */
// static private boolean RELEASE = false;
@@ -127,7 +127,11 @@ public class Base {
private JMenu sketchbookMenu;
private Recent recent;
-// private JMenu recentMenu;
+
+ // Used by handleOpen(), this saves the chooser to remember the directory.
+ // Doesn't appear to be necessary with the AWT native file dialog.
+ // https://github.com/processing/processing/pull/2366
+ private JFileChooser openChooser;
static protected File sketchbookFolder;
// protected File toolsFolder;
@@ -205,13 +209,11 @@ public class Base {
// Prevent more than one copy of the PDE from running.
SingleInstance.startServer(base);
- } catch (Exception e) {
+ } catch (Throwable t) {
// 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);
+ showBadnessTrace("We're off on the wrong foot",
+ "An error occurred during startup.", t, true);
}
log("done creating base..."); //$NON-NLS-1$
}
@@ -366,13 +368,13 @@ public class Base {
} else {
for (Mode m : getModeList()) {
if (m.getIdentifier().equals(lastModeIdentifier)) {
- logf("Setting next mode to {0}.", lastModeIdentifier); //$NON-NLS-1$
+ logf("Setting next mode to %s.", lastModeIdentifier); //$NON-NLS-1$
nextMode = m;
}
}
if (nextMode == null) {
nextMode = coreModes[0];
- logf("Could not find mode {0}, using default.", lastModeIdentifier); //$NON-NLS-1$
+ logf("Could not find mode %s, using default.", lastModeIdentifier); //$NON-NLS-1$
}
}
@@ -609,38 +611,31 @@ public class Base {
Base.showWarning("Save",
"Please save the sketch before changing the mode.",
null);
- } else {
-// boolean untitled = activeEditor.untitled;
- String mainPath = sketch.getMainFilePath();
- boolean wasUntitled = sketch.isUntitled();
+ return;
+ }
+ nextMode = mode;
- // save a mode file into this sketch folder
- File sketchProps = new File(sketch.getFolder(), "sketch.properties"); //$NON-NLS-1$
- try {
- Settings props = new Settings(sketchProps);
- // Include the pretty name for error messages to show the user
- props.set("mode", mode.getTitle()); //$NON-NLS-1$
- // Actual identifier to be used to resurrect the mode
- props.set("mode.id", mode.getIdentifier()); //$NON-NLS-1$
- props.save();
- } catch (IOException e) {
- e.printStackTrace();
+ // If the current editor contains file extensions that the new mode can handle, then
+ // write a sketch.properties file with the new mode specified, and reopen.
+ boolean newModeCanHandleCurrentSource = true;
+ for (final SketchCode code: sketch.getCode()) {
+ if (!mode.validExtension(code.getExtension())) {
+ newModeCanHandleCurrentSource = false;
+ break;
}
-// PrintWriter writer = PApplet.createWriter(sketchProps);
-// writer.println("mode=" + mode.getTitle());
-// writer.flush();
-// writer.close();
-
-// // close this sketch
-//// int[] where = activeEditor.getPlacement();
-// Rectangle bounds = activeEditor.getBounds();
-// int divider = activeEditor.getDividerLocation();
- EditorState state = activeEditor.state;
+ }
+ if (newModeCanHandleCurrentSource) {
+ final File props = new File(sketch.getCodeFolder(), "sketch.properties");
+ saveModeSettings(props, nextMode);
handleClose(activeEditor, true);
-
- // re-open the sketch
-// /*Editor editor =*/ handleOpen(mainPath, untitled, state);
- /*Editor editor =*/ handleOpen(mainPath, wasUntitled, state);
+ handleOpen(sketch.getMainFilePath());
+ } else {
+ // If you're changing modes, and there's nothing in the current sketch, you probably
+ // don't intend to keep the old, wrong-mode editor around.
+ if (sketch.isUntitled()) {
+ handleClose(activeEditor, true);
+ }
+ handleNew();
}
}
}
@@ -753,6 +748,10 @@ public class Base {
if (!newbieFile.createNewFile()) {
throw new IOException(newbieFile + " already exists.");
}
+
+ // Create sketch properties.
+ saveModeSettings(new File(newbieDir, "sketch.properties"), nextMode);
+
String path = newbieFile.getAbsolutePath();
/*Editor editor =*/ handleOpen(path, true);
@@ -763,6 +762,18 @@ public class Base {
}
}
+ // Create or modify a sketch.proprties file to specify the given Mode.
+ private void saveModeSettings(final File sketchProps, final Mode mode) {
+ try {
+ final Settings settings = new Settings(sketchProps);
+ settings.set("mode", mode.getTitle());
+ settings.set("mode.id", mode.getIdentifier());
+ settings.save();
+ } catch (IOException e) {
+ System.err.println("While creating " + sketchProps + ": " + e.getMessage());
+ }
+ }
+
// /**
// * Replace the sketch in the current window with a new untitled document.
@@ -825,13 +836,17 @@ public class Base {
extensions.add(mode.getDefaultExtension());
}
+
final String prompt = Language.text("open");
- if (Preferences.getBoolean("chooser.files.native")) { // don't use native dialogs on Linux //$NON-NLS-1$
- // get the front-most window frame for placing file dialog
- FileDialog fd = new FileDialog(activeEditor, prompt, FileDialog.LOAD);
+
+ // don't use native dialogs on Linux (or anyone else w/ override)
+ if (Preferences.getBoolean("chooser.files.native")) { //$NON-NLS-1$
+ // use the front-most window frame for placing file dialog
+ FileDialog openDialog =
+ new FileDialog(activeEditor, prompt, FileDialog.LOAD);
// Only show .pde files as eligible bachelors
- fd.setFilenameFilter(new FilenameFilter() {
+ openDialog.setFilenameFilter(new FilenameFilter() {
public boolean accept(File dir, String name) {
// confirmed to be working properly [fry 110128]
for (String ext : extensions) {
@@ -843,20 +858,22 @@ public class Base {
}
});
- fd.setVisible(true);
+ openDialog.setVisible(true);
- String directory = fd.getDirectory();
- String filename = fd.getFile();
+ String directory = openDialog.getDirectory();
+ String filename = openDialog.getFile();
if (filename != null) {
File inputFile = new File(directory, filename);
handleOpen(inputFile.getAbsolutePath());
}
} else {
- JFileChooser fc = new JFileChooser();
- fc.setDialogTitle(prompt);
+ if (openChooser == null) {
+ openChooser = new JFileChooser();
+ }
+ openChooser.setDialogTitle(prompt);
- fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
+ openChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
public boolean accept(File file) {
// JFileChooser requires you to explicitly say yes to directories
// as well (unlike the AWT chooser). Useful, but... different.
@@ -876,8 +893,8 @@ public class Base {
return "Processing Sketch";
}
});
- if (fc.showOpenDialog(activeEditor) == JFileChooser.APPROVE_OPTION) {
- handleOpen(fc.getSelectedFile().getAbsolutePath());
+ if (openChooser.showOpenDialog(activeEditor) == JFileChooser.APPROVE_OPTION) {
+ handleOpen(openChooser.getSelectedFile().getAbsolutePath());
}
}
}
@@ -905,115 +922,171 @@ public class Base {
// protected Editor handleOpen(String path, int[] location) {
// protected Editor handleOpen(String path, Rectangle bounds, int divider) {
protected Editor handleOpen(String path, boolean untitled, EditorState state) {
-// System.err.println("entering handleOpen " + path);
-
- File file = new File(path);
- if (!file.exists()) return null;
-
- if (!Sketch.isSanitaryName(file.getName())) {
- Base.showWarning("You're tricky, but not tricky enough",
- file.getName() + " is not a valid name for a sketch.\n" +
- "Better to stick to ASCII, no spaces, and make sure\n" +
- "it doesn't start with a number.", null);
- return null;
- }
-
-// System.err.println(" editors: " + editors);
- // Cycle through open windows to make sure that it's not already open.
- for (Editor editor : editors) {
- if (editor.getSketch().getMainFilePath().equals(path)) {
- editor.toFront();
- // move back to the top of the recent list
- handleRecent(editor);
- return editor;
- }
- }
-
- // If the active editor window is an untitled, and un-modified document,
- // just replace it with the file that's being opened.
-// if (activeEditor != null) {
-// Sketch activeSketch = activeEditor.sketch;
-// if (activeSketch.isUntitled() && !activeSketch.isModified()) {
-// // if it's an untitled, unmodified document, it can be replaced.
-// // except in cases where a second blank window is being opened.
-// if (!path.startsWith(untitledFolder.getAbsolutePath())) {
-// activeEditor.handleOpenUnchecked(path, 0, 0, 0, 0);
-// return activeEditor;
-// }
-// }
-// }
-
-// Mode nextMode = nextEditorMode();
try {
- File sketchFolder = new File(path).getParentFile();
- File sketchProps = new File(sketchFolder, "sketch.properties"); //$NON-NLS-1$
- if (sketchProps.exists()) {
- Settings props = new Settings(sketchProps);
- String modeTitle = props.get("mode"); //$NON-NLS-1$
- String modeIdentifier = props.get("mode.id"); //$NON-NLS-1$
- if (modeTitle != null && modeIdentifier != null) {
-// nextMode = findMode(modeTitle);
- Mode mode = findMode(modeIdentifier);
- if (mode != null) {
- nextMode = mode;
+ // System.err.println("entering handleOpen " + path);
- } else {
- final String msg =
- "This sketch was last used in “" + modeTitle + "” mode,\n" +
- "which does not appear to be installed. The sketch will\n" +
- "be opened in “" + nextMode.getTitle() + "” mode instead.";
- Base.showWarning("Depeche Mode", msg, null);
- }
+ final File file = new File(path);
+ if (!file.exists()) {
+ return null;
+ }
+
+ // System.err.println(" editors: " + editors);
+ // Cycle through open windows to make sure that it's not already open.
+ for (Editor editor : editors) {
+ if (editor.getSketch().getMainFile().equals(file)) {
+ editor.toFront();
+ // move back to the top of the recent list
+ handleRecent(editor);
+ return editor;
}
}
- } catch (Exception e) {
- e.printStackTrace();
- }
-// Editor.State state = new Editor.State(editors);
- Editor editor = nextMode.createEditor(this, path, state);
- if (editor == null) {
- // if it's the last editor window
-// if (editors.size() == 0 && defaultFileMenu == null) {
- // if it's not mode[0] already, then don't go into an infinite loop
- // trying to recreate a window with the default mode.
- if (nextMode == coreModes[0]) {
- Base.showError("Editor Problems",
- "An error occurred while trying to change modes.\n" +
- "We'll have to quit for now because it's an\n" +
- "unfortunate bit of indigestion.",
- null);
- } else {
- editor = coreModes[0].createEditor(this, path, state);
- }
- }
- // Make sure that the sketch actually loaded
- if (editor.getSketch() == null) {
+ if (!Sketch.isSanitaryName(file.getName())) {
+ Base.showWarning("You're tricky, but not tricky enough",
+ file.getName() + " is not a valid name for a sketch.\n" +
+ "Better to stick to ASCII, no spaces, and make sure\n" +
+ "it doesn't start with a number.", null);
+ return null;
+ }
+
+ if (!nextMode.canEdit(file)) {
+ final Mode mode = selectMode(file);
+ if (mode == null) {
+ return null;
+ }
+ nextMode = mode;
+ }
+
+// Editor.State state = new Editor.State(editors);
+ Editor editor = nextMode.createEditor(this, path, state);
+ if (editor == null) {
+ // if it's the last editor window
+// if (editors.size() == 0 && defaultFileMenu == null) {
+ // if it's not mode[0] already, then don't go into an infinite loop
+ // trying to recreate a window with the default mode.
+ if (nextMode == coreModes[0]) {
+ Base.showError("Editor Problems",
+ "An error occurred while trying to change modes.\n" +
+ "We'll have to quit for now because it's an\n" +
+ "unfortunate bit of indigestion.",
+ null);
+ } else {
+ editor = coreModes[0].createEditor(this, path, state);
+ }
+ }
+
+ // Make sure that the sketch actually loaded
+ if (editor.getSketch() == null) {
// System.err.println("sketch was null, getting out of handleOpen");
- return null; // Just walk away quietly
- }
+ return null; // Just walk away quietly
+ }
// editor.untitled = untitled;
- editor.getSketch().setUntitled(untitled);
- editors.add(editor);
- handleRecent(editor);
+ editor.getSketch().setUntitled(untitled);
+ editors.add(editor);
+ handleRecent(editor);
- // now that we're ready, show the window
- // (don't do earlier, cuz we might move it based on a window being closed)
- editor.setVisible(true);
+ // now that we're ready, show the window
+ // (don't do earlier, cuz we might move it based on a window being closed)
+ editor.setVisible(true);
- return editor;
+ return editor;
+
+ } catch (Throwable t) {
+ showBadnessTrace("Terrible News",
+ "A serious error occurred while " +
+ "trying to create a new editor window.", t, false);
+ nextMode = coreModes[0];
+ return null;
+ }
}
-// protected Mode findMode(String title) {
-// for (Mode mode : getModeList()) {
-// if (mode.getTitle().equals(title)) {
-// return mode;
-// }
-// }
-// return null;
-// }
+ private static class ModeInfo {
+ public final String title;
+ public final String id;
+
+ public ModeInfo(String id, String title) {
+ this.id = id;
+ this.title = title;
+ }
+ }
+
+
+ private static ModeInfo modeInfoFor(final File sketch) {
+ final File sketchFolder = sketch.getParentFile();
+ final File sketchProps = new File(sketchFolder, "sketch.properties");
+ if (!sketchProps.exists()) {
+ return null;
+ }
+ try {
+ final Settings settings = new Settings(sketchProps);
+ final String title = settings.get("mode");
+ final String id = settings.get("mode.id");
+ if (title == null || id == null) {
+ return null;
+ }
+ return new ModeInfo(id, title);
+ } catch (IOException e) {
+ System.err.println("While trying to read " + sketchProps + ": "
+ + e.getMessage());
+ }
+ return null;
+ }
+
+
+ private Mode promptForMode(final File sketch, final ModeInfo preferredMode) {
+ final String extension =
+ sketch.getName().substring(sketch.getName().lastIndexOf('.') + 1);
+ final List possibleModes = new ArrayList();
+ for (final Mode mode : getModeList()) {
+ if (mode.canEdit(sketch)) {
+ possibleModes.add(mode);
+ }
+ }
+ if (possibleModes.size() == 1 &&
+ possibleModes.get(0).getIdentifier()
+ .equals(JavaMode.class.getCanonicalName())) {
+ // If default mode can open it, then do so without prompting.
+ return possibleModes.get(0);
+ }
+ if (possibleModes.size() == 0) {
+ if (preferredMode == null) {
+ Base.showWarning("Modeless Dialog",
+ "I don't know how to open a sketch with the \""
+ + extension
+ + "\"\nfile extension. You'll have to install a different"
+ + "\nProcessing mode for that.");
+ } else {
+ Base.showWarning("Modeless Dialog", "You'll have to install "
+ + preferredMode.title + " Mode " + "\nin order to open that sketch.");
+ }
+ return null;
+ }
+ final Mode[] modes = possibleModes.toArray(new Mode[possibleModes.size()]);
+ final String message = preferredMode == null ?
+ (nextMode.getTitle() + " Mode can't open ." + extension + " files, " +
+ "but you have one or more modes\ninstalled that can. " +
+ "Would you like to try one?") :
+ ("That's a " + preferredMode.title + " Mode sketch, " +
+ "but you don't have " + preferredMode.title + " installed.\n" +
+ "Would you like to try a different mode for opening a " +
+ "." + extension + " sketch?");
+ return (Mode) JOptionPane.showInputDialog(null, message, "Choose Wisely",
+ JOptionPane.QUESTION_MESSAGE,
+ null, modes, modes[0]);
+ }
+
+
+ private Mode selectMode(final File sketch) {
+ final ModeInfo modeInfo = modeInfoFor(sketch);
+ final Mode specifiedMode = modeInfo == null ? null : findMode(modeInfo.id);
+ if (specifiedMode != null) {
+ return specifiedMode;
+ }
+ return promptForMode(sketch, modeInfo);
+ }
+
protected Mode findMode(String id) {
for (Mode mode : getModeList()) {
@@ -1028,6 +1101,8 @@ public class Base {
/**
* Close a sketch as specified by its editor window.
* @param editor Editor object of the sketch to be closed.
+ * @param modeSwitch Whether this close is being done in the context of a
+ * mode switch.
* @return true if succeeded in closing, false if canceled.
*/
public boolean handleClose(Editor editor, boolean modeSwitch) {
@@ -1040,6 +1115,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.
@@ -1079,6 +1155,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
@@ -1592,18 +1669,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");
@@ -2079,10 +2167,17 @@ public class Base {
}
+ /**
+ * Non-fatal error message.
+ */
+ static public void showWarning(String title, String message) {
+ showWarning(title, message, null);
+ }
+
/**
* 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) {
@@ -2101,7 +2196,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;
@@ -2175,6 +2270,35 @@ public class Base {
}
+ /**
+ * Testing a new warning window that includes the stack trace.
+ */
+ static private void showBadnessTrace(String title, String message,
+ Throwable t, boolean fatal) {
+ if (title == null) title = fatal ? "Error" : "Warning";
+
+ if (commandLine) {
+ System.err.println(title + ": " + message);
+ if (t != null) {
+ t.printStackTrace();
+ }
+
+ } else {
+ StringWriter sw = new StringWriter();
+ t.printStackTrace(new PrintWriter(sw));
+ // Necessary to replace \n with (even if pre) otherwise Java
+ // treats it as a closed tag and reverts to plain formatting.
+ message = "" + message + "
" +
+ sw.toString().replaceAll("\n", " ");
+
+ JOptionPane.showMessageDialog(new Frame(), message, title,
+ fatal ?
+ JOptionPane.ERROR_MESSAGE :
+ JOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+
// ...................................................................
@@ -2349,22 +2473,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 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.
- processingRoot = jarFolder;
- }
- if (processingRoot == null || !processingRoot.exists()) {
- // Try working directory instead (user.dir, different from user.home)
- Base.log("Could not find lib folder via " +
- jarFolder.getAbsolutePath() +
- ", switching to user.dir");
- processingRoot = new File(System.getProperty("user.dir"));
+
+ 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 {
+ // 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"));
+ }
}
}
/*
@@ -2385,6 +2524,58 @@ 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 dir.isDirectory() &&
+ name.endsWith(".jdk") && !name.startsWith(".");
+ }
+ });
+ 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
@@ -2522,6 +2713,7 @@ public class Base {
to = null;
targetFile.setLastModified(sourceFile.lastModified());
+ targetFile.setExecutable(sourceFile.canExecute());
}
@@ -2594,6 +2786,28 @@ 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
@@ -2986,7 +3200,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/ColorChooser.java b/app/src/processing/app/ColorChooser.java
new file mode 100644
index 000000000..b4a6ccac8
--- /dev/null
+++ b/app/src/processing/app/ColorChooser.java
@@ -0,0 +1,701 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2006-14 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;
+
+import processing.core.*;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+
+/**
+ * Generic color selector frame, pulled from the Tool object. API not really
+ * worked out here (what should the constructor be? how flexible?) So use with
+ * caution and be ready for it to break in future releases.
+ */
+public class ColorChooser { //extends JFrame implements DocumentListener {
+
+ int hue, saturation, brightness; // range 360, 100, 100
+ int red, green, blue; // range 256, 256, 256
+
+ ColorRange range;
+ ColorSlider slider;
+
+ JTextField hueField, saturationField, brightnessField;
+ JTextField redField, greenField, blueField;
+
+ JTextField hexField;
+
+ JPanel colorPanel;
+ DocumentListener colorListener;
+
+ JDialog window;
+
+
+// public String getMenuTitle() {
+// return "Color Selector";
+// }
+
+
+ public ColorChooser(Frame owner, boolean modal, Color initialColor,
+ String buttonName, ActionListener buttonListener) {
+ //super("Color Selector");
+ window = new JDialog(owner, "Color Selector", modal);
+ window.getContentPane().setLayout(new BorderLayout());
+
+ Box box = Box.createHorizontalBox();
+ box.setBorder(new EmptyBorder(12, 12, 12, 12));
+
+ range = new ColorRange();
+ range.init();
+ Box rangeBox = new Box(BoxLayout.Y_AXIS);
+ rangeBox.setAlignmentY(0);
+ rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ rangeBox.add(range);
+ box.add(rangeBox);
+ box.add(Box.createHorizontalStrut(10));
+
+ slider = new ColorSlider();
+ slider.init();
+ Box sliderBox = new Box(BoxLayout.Y_AXIS);
+ sliderBox.setAlignmentY(0);
+ sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ sliderBox.add(slider);
+ box.add(sliderBox);
+ box.add(Box.createHorizontalStrut(10));
+
+ box.add(createColorFields(buttonName, buttonListener));
+// System.out.println("1: " + hexField.getInsets());
+
+ box.add(Box.createHorizontalStrut(10));
+
+// System.out.println("2: " + hexField.getInsets());
+
+ window.getContentPane().add(box, BorderLayout.CENTER);
+// System.out.println(hexField);
+// System.out.println("3: " + hexField.getInsets());
+// colorPanel.setInsets(hexField.getInsets());
+
+ window.pack();
+ window.setResizable(false);
+
+// Dimension size = getSize();
+// Dimension screen = Toolkit.getScreenSize();
+// setLocation((screen.width - size.width) / 2,
+// (screen.height - size.height) / 2);
+ window.setLocationRelativeTo(null);
+
+ window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ window.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ hide();
+ }
+ });
+ Toolkit.registerWindowCloseKeys(window.getRootPane(), new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ hide();
+ }
+ });
+
+ Toolkit.setIcon(window);
+
+ colorListener = new ColorListener();
+ hueField.getDocument().addDocumentListener(colorListener);
+ saturationField.getDocument().addDocumentListener(colorListener);
+ brightnessField.getDocument().addDocumentListener(colorListener);
+ redField.getDocument().addDocumentListener(colorListener);
+ greenField.getDocument().addDocumentListener(colorListener);
+ blueField.getDocument().addDocumentListener(colorListener);
+ hexField.getDocument().addDocumentListener(colorListener);
+
+ setColor(initialColor);
+// System.out.println("4: " + hexField.getInsets());
+ }
+
+
+ //hexField.setText("#FFFFFF");
+
+
+ public void show() {
+ window.setVisible(true);
+ window.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+
+
+ public void hide() {
+ window.setVisible(false);
+ }
+
+
+ public Color getColor() {
+ return new Color(red, green, blue);
+ }
+
+
+ public void setColor(Color color) {
+ updateRGB(color.getRGB());
+ }
+
+
+ public String getHexColor() {
+ return "#" + PApplet.hex(red, 2) + PApplet.hex(green, 2) + PApplet.hex(blue, 2);
+ }
+
+
+ public class ColorListener implements DocumentListener {
+
+ public void changedUpdate(DocumentEvent e) {
+ //System.out.println("changed");
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ //System.out.println("remove");
+ }
+
+
+ boolean updating;
+
+ public void insertUpdate(DocumentEvent e) {
+ if (updating) return; // don't update forever recursively
+ updating = true;
+
+ Document doc = e.getDocument();
+ if (doc == hueField.getDocument()) {
+ hue = bounded(hue, hueField, 359);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == saturationField.getDocument()) {
+ saturation = bounded(saturation, saturationField, 99);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == brightnessField.getDocument()) {
+ brightness = bounded(brightness, brightnessField, 99);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == redField.getDocument()) {
+ red = bounded(red, redField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == greenField.getDocument()) {
+ green = bounded(green, greenField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == blueField.getDocument()) {
+ blue = bounded(blue, blueField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == hexField.getDocument()) {
+ String str = hexField.getText();
+ if (str.startsWith("#")) {
+ str = str.substring(1);
+ }
+ while (str.length() < 6) {
+ str += "0";
+ }
+ if (str.length() > 6) {
+ str = str.substring(0, 6);
+ }
+ updateRGB(Integer.parseInt(str, 16));
+ updateHSB();
+ }
+ range.redraw();
+ slider.redraw();
+ //colorPanel.setBackground(new Color(red, green, blue));
+ colorPanel.repaint();
+ updating = false;
+ }
+}
+
+
+ /**
+ * Set the RGB values based on the current HSB values.
+ */
+ protected void updateRGB() {
+ updateRGB(Color.HSBtoRGB(hue / 359f,
+ saturation / 99f,
+ brightness / 99f));
+ }
+
+
+ /**
+ * Set the RGB values based on a calculated ARGB int.
+ * Used by both updateRGB() to set the color from the HSB values,
+ * and by updateHex(), to unpack the hex colors and assign them.
+ */
+ protected void updateRGB(int rgb) {
+ red = (rgb >> 16) & 0xff;
+ green = (rgb >> 8) & 0xff;
+ blue = rgb & 0xff;
+
+ redField.setText(String.valueOf(red));
+ greenField.setText(String.valueOf(green));
+ blueField.setText(String.valueOf(blue));
+ }
+
+
+ /**
+ * Set the HSB values based on the current RGB values.
+ */
+ protected void updateHSB() {
+ float hsb[] = new float[3];
+ Color.RGBtoHSB(red, green, blue, hsb);
+
+ hue = (int) (hsb[0] * 359.0f);
+ saturation = (int) (hsb[1] * 99.0f);
+ brightness = (int) (hsb[2] * 99.0f);
+
+ hueField.setText(String.valueOf(hue));
+ saturationField.setText(String.valueOf(saturation));
+ brightnessField.setText(String.valueOf(brightness));
+ }
+
+
+ protected void updateHex() {
+ hexField.setText(getHexColor());
+ }
+
+
+ /**
+ * Get the bounded value for a specific range. If the value is outside
+ * the max, you can't edit right away, so just act as if it's already
+ * been bounded and return the bounded value, then fire an event to set
+ * it to the value that was just returned.
+ */
+ protected int bounded(int current, final JTextField field, final int max) {
+ String text = field.getText();
+ if (text.length() == 0) {
+ return 0;
+ }
+ try {
+ int value = Integer.parseInt(text);
+ if (value > max) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ field.setText(String.valueOf(max));
+ }
+ });
+ return max;
+ }
+ return value;
+
+ } catch (NumberFormatException e) {
+ return current; // should not be reachable
+ }
+ }
+
+
+ protected Container createColorFields(String buttonName, ActionListener buttonListener) {
+ Box box = Box.createVerticalBox();
+ box.setAlignmentY(0);
+
+ final int GAP = Base.isWindows() ? 5 : 0;
+ final int BETWEEN = Base.isWindows() ? 8 : 6; //10;
+
+ Box row;
+
+ row = Box.createHorizontalBox();
+ if (Base.isMacOS()) {
+ row.add(Box.createHorizontalStrut(17));
+ } else {
+ row.add(createFixedLabel(""));
+ }
+ // Can't just set the bg color of the panel because it also tints the bevel
+ // (on OS X), which looks odd. So instead we override paintComponent().
+ colorPanel = new JPanel() {
+ public void paintComponent(Graphics g) {
+ g.setColor(new Color(red, green, blue));
+ Dimension size = getSize();
+ g.fillRect(0, 0, size.width, size.height);
+ }
+ };
+ colorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ Dimension dim = new Dimension(70, 25);
+ colorPanel.setMinimumSize(dim);
+ colorPanel.setMaximumSize(dim);
+ colorPanel.setPreferredSize(dim);
+ row.add(colorPanel);
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(BETWEEN));
+// if (Base.isMacOS()) { // need a little extra
+// box.add(Box.createVerticalStrut(BETWEEN));
+// }
+
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("H"));
+ row.add(hueField = new NumberField(4, false));
+ row.add(new JLabel(" \u00B0")); // degree symbol
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(GAP));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("S"));
+ row.add(saturationField = new NumberField(4, false));
+ row.add(new JLabel(" %"));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(GAP));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("B"));
+ row.add(brightnessField = new NumberField(4, false));
+ row.add(new JLabel(" %"));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(BETWEEN));
+
+ //
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("R"));
+ row.add(redField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(GAP));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("G"));
+ row.add(greenField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(GAP));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("B"));
+ row.add(blueField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(BETWEEN));
+
+ //
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel(""));
+ // Windows needs extra space, OS X and Linux do not
+ // Mac OS X needs 6 because #CCCCCC is quite wide
+ final int hexCount = Base.isWindows() ? 7 : 6;
+ row.add(hexField = new NumberField(hexCount, true));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(GAP));
+
+ //
+
+// // Not great, because the insets make things weird anyway
+// //Dimension dim = new Dimension(hexField.getPreferredSize());
+// Dimension dim = new Dimension(70, 20);
+// colorPanel.setMinimumSize(dim);
+// colorPanel.setMaximumSize(dim);
+// colorPanel.setPreferredSize(dim);
+//// colorPanel.setBorder(new EmptyBorder(hexField.getInsets()));
+
+ //
+
+ row = Box.createHorizontalBox();
+ if (Base.isMacOS()) {
+ row.add(Box.createHorizontalStrut(11));
+ } else {
+ row.add(createFixedLabel(""));
+ }
+ JButton button = new JButton(buttonName);
+ button.addActionListener(buttonListener);
+ //System.out.println("button: " + button.getInsets());
+ row.add(button);
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+
+ //
+
+ box.add(Box.createVerticalGlue());
+ return box;
+ }
+
+
+ int labelH;
+
+ /**
+ * return a label of a fixed width
+ */
+ protected JLabel createFixedLabel(String title) {
+ JLabel label = new JLabel(title);
+ if (labelH == 0) {
+ labelH = label.getPreferredSize().height;
+ }
+ Dimension dim = new Dimension(15, labelH);
+ label.setPreferredSize(dim);
+ label.setMinimumSize(dim);
+ label.setMaximumSize(dim);
+ return label;
+ }
+
+
+ public class ColorRange extends PApplet {
+
+ static final int WIDE = 256;
+ static final int HIGH = 256;
+
+ int lastX, lastY;
+
+
+ public void setup() {
+ size(WIDE, HIGH); //, P3D);
+ noLoop();
+
+ colorMode(HSB, 360, 256, 256);
+ noFill();
+ rectMode(CENTER);
+
+ loadPixels();
+ }
+
+ public void draw() {
+// if ((g == null) || (g.pixels == null)) return;
+ if ((width != WIDE) || (height < HIGH)) {
+ //System.out.println("bad size " + width + " " + height);
+ return;
+ }
+
+ int index = 0;
+ for (int j = 0; j < 256; j++) {
+ for (int i = 0; i < 256; i++) {
+ pixels[index++] = color(hue, i, 255 - j);
+ }
+ }
+
+ updatePixels();
+ stroke((brightness > 50) ? 0 : 255);
+ rect(lastX, lastY, 9, 9);
+ }
+
+ public void mousePressed() {
+ updateMouse();
+ }
+
+ public void mouseDragged() {
+ updateMouse();
+ }
+
+ public void updateMouse() {
+ if ((mouseX >= 0) && (mouseX < 256) &&
+ (mouseY >= 0) && (mouseY < 256)) {
+ int nsaturation = (int) (100 * (mouseX / 255.0f));
+ int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f)));
+ saturationField.setText(String.valueOf(nsaturation));
+ brightnessField.setText(String.valueOf(nbrightness));
+
+ lastX = mouseX;
+ lastY = mouseY;
+ }
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMinimumSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public void keyPressed() {
+ if (key == ESC) {
+ ColorChooser.this.hide();
+ // don't quit out of processing
+ // http://dev.processing.org/bugs/show_bug.cgi?id=1006
+ key = 0;
+ }
+ }
+ }
+
+
+ public class ColorSlider extends PApplet {
+
+ static final int WIDE = 20;
+ static final int HIGH = 256;
+
+ public void setup() {
+ size(WIDE, HIGH); //, P3D);
+ colorMode(HSB, 255, 100, 100);
+ noLoop();
+ loadPixels();
+ }
+
+ public void draw() {
+// if ((g == null) || (g.pixels == null)) return;
+ if ((width != WIDE) || (height < HIGH)) {
+ //System.out.println("bad size " + width + " " + height);
+ return;
+ }
+
+ int index = 0;
+ int sel = 255 - (int) (255 * (hue / 359f));
+ for (int j = 0; j < 256; j++) {
+ int c = color(255 - j, 100, 100);
+ if (j == sel) c = 0xFF000000;
+ for (int i = 0; i < WIDE; i++) {
+ g.pixels[index++] = c;
+ }
+ }
+ updatePixels();
+ }
+
+ public void mousePressed() {
+ updateMouse();
+ }
+
+ public void mouseDragged() {
+ updateMouse();
+ }
+
+ public void updateMouse() {
+ if ((mouseX >= 0) && (mouseX < 256) &&
+ (mouseY >= 0) && (mouseY < 256)) {
+ int nhue = 359 - (int) (359 * (mouseY / 255.0f));
+ hueField.setText(String.valueOf(nhue));
+ }
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMinimumSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public void keyPressed() {
+ if (key == ESC) {
+ ColorChooser.this.hide();
+ // don't quit out of processing
+ // http://dev.processing.org/bugs/show_bug.cgi?id=1006
+ key = 0;
+ }
+ }
+ }
+
+
+ /**
+ * Extension of JTextField that only allows numbers
+ */
+ class NumberField extends JTextField {
+
+ public boolean allowHex;
+
+ public NumberField(int cols, boolean allowHex) {
+ super(cols);
+ this.allowHex = allowHex;
+ }
+
+ protected Document createDefaultModel() {
+ return new NumberDocument(this);
+ }
+
+ public Dimension getPreferredSize() {
+ if (!allowHex) {
+ return new Dimension(45, super.getPreferredSize().height);
+ }
+ return super.getPreferredSize();
+ }
+
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+
+ public Dimension getMaximumSize() {
+ return getPreferredSize();
+ }
+ }
+
+
+ /**
+ * Document model to go with JTextField that only allows numbers.
+ */
+ class NumberDocument extends PlainDocument {
+
+ NumberField parentField;
+
+ public NumberDocument(NumberField parentField) {
+ this.parentField = parentField;
+ //System.out.println("setting parent to " + parentSelector);
+ }
+
+ public void insertString(int offs, String str, AttributeSet a)
+ throws BadLocationException {
+
+ if (str == null) return;
+
+ char chars[] = str.toCharArray();
+ int charCount = 0;
+ // remove any non-digit chars
+ for (int i = 0; i < chars.length; i++) {
+ boolean ok = Character.isDigit(chars[i]);
+ if (parentField.allowHex) {
+ if ((chars[i] >= 'A') && (chars[i] <= 'F')) ok = true;
+ if ((chars[i] >= 'a') && (chars[i] <= 'f')) ok = true;
+ if ((offs == 0) && (i == 0) && (chars[i] == '#')) ok = true;
+ }
+ if (ok) {
+ if (charCount != i) { // shift if necessary
+ chars[charCount] = chars[i];
+ }
+ charCount++;
+ }
+ }
+ super.insertString(offs, new String(chars, 0, charCount), a);
+ // can't call any sort of methods on the enclosing class here
+ // seems to have something to do with how Document objects are set up
+ }
+ }
+
+
+// static public void main(String[] args) {
+// ColorSelector cs = new ColorSelector();
+// cs.init(null);
+// EventQueue.invokeLater(cs);
+// }
+}
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index bd824d294..7f4b1a8be 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,102 @@ 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("The " + nsme.getMessage() + " method no longer exists.");
+ 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 (NoClassDefFoundError ncdfe) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
+ System.err.println("The " + ncdfe.getMessage() + " class is no longer available.");
+ Base.log("Incompatible Tool found during tool.init()", ncdfe);
+
+ } catch (Error err) {
+ System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+ err.printStackTrace();
+
+ } catch (Exception ex) {
+ System.err.println("An exception occurred inside \"" + tool.getMenuTitle() + "\"");
+ ex.printStackTrace();
+ }
}
ArrayList toolList = new ArrayList(toolItems.keySet());
@@ -984,7 +1070,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 +1095,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");
}
@@ -1419,7 +1502,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
public int getScrollPosition() {
- return textarea.getScrollPosition();
+ return textarea.getVerticalScrollPosition();
}
@@ -1688,7 +1771,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
} else {
// replace with new bootiful text
// selectionEnd hopefully at least in the neighborhood
- int scrollPos = textarea.getScrollPosition();
+ int scrollPos = textarea.getVerticalScrollPosition();
setText(formattedText);
setSelection(selectionEnd, selectionEnd);
@@ -1696,14 +1779,14 @@ public abstract class Editor extends JFrame implements RunnerListener {
// Since we're not doing a good job of maintaining position anyway,
// a more complicated workaround here is fairly pointless.
// http://code.google.com/p/processing/issues/detail?id=1533
- if (scrollPos != textarea.getScrollPosition()) {
+ if (scrollPos != textarea.getVerticalScrollPosition()) {
// boolean wouldBeVisible =
// scrollPos >= textarea.getFirstLine() &&
// scrollPos < textarea.getLastLine();
//
// // if it was visible, and now it's not, then allow the scroll
// if (!(wasVisible && !wouldBeVisible)) {
- textarea.setScrollPosition(scrollPos);
+ textarea.setVerticalScrollPosition(scrollPos);
// }
}
getSketch().setModified(true);
@@ -2010,6 +2093,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()) {
@@ -2108,31 +2194,30 @@ public abstract class Editor extends JFrame implements RunnerListener {
protected boolean handleOpenInternal(String path) {
// check to make sure that this .pde file is
// in a folder of the same name
- File file = new File(path);
- File parentFile = new File(file.getParent());
- String parentName = parentFile.getName();
- String pdeName = parentName + ".pde";
- File altFile = new File(file.getParent(), pdeName);
+ final File file = new File(path);
+ final File parentFile = new File(file.getParent());
+ final String parentName = parentFile.getName();
+ final String defaultName = parentName + "." + mode.getDefaultExtension();
+ final File altFile = new File(file.getParent(), defaultName);
- if (pdeName.equals(file.getName())) {
+ if (defaultName.equals(file.getName())) {
// no beef with this guy
-
} else if (altFile.exists()) {
- // user selected a .java from the same sketch,
- // but open the .pde instead
+ // The user selected a source file from the same sketch,
+ // but open the file with the default extension instead.
path = altFile.getAbsolutePath();
- //System.out.println("found alt file in same folder");
-
- } else if (!path.endsWith(".pde")) {
- Base.showWarning("Bad file selected",
- "Processing can only open its own sketches\n" +
- "and other files ending in .pde", null);
+ } else if (!mode.canEdit(file)) {
+ final String modeName = (mode.getTitle().equals("Java")) ? "Processing"
+ : mode.getTitle();
+ Base
+ .showWarning("Bad file selected", modeName
+ + " can only open its own sketches\nand other files ending in "
+ + mode.getDefaultExtension(), null);
return false;
-
} else {
- String properParent =
- file.getName().substring(0, file.getName().length() - 4);
-
+ final String properParent =
+ file.getName().substring(0, file.getName().lastIndexOf('.'));
+
Object[] options = { "OK", "Cancel" };
String prompt =
"The file \"" + file.getName() + "\" needs to be inside\n" +
@@ -2328,9 +2413,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());
@@ -2474,6 +2559,22 @@ public abstract class Editor extends JFrame implements RunnerListener {
}
}
+
+ /**
+ * Returns the current notice message in the editor status bar.
+ */
+ public String getStatusMessage(){
+ return status.message;
+ }
+
+
+ /**
+ * Returns the current mode of the editor status bar: NOTICE, ERR or EDIT.
+ */
+ public int getStatusMode(){
+ return status.mode;
+ }
+
/**
* Clear the status area.
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/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..c99d45f31 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.*;
@@ -35,11 +36,9 @@ public class EditorStatus extends JPanel {
Color[] bgcolor;
Color[] fgcolor;
- static final int NOTICE = 0;
- static final int ERR = 1;
- //static final int PROMPT = 2;
- //static final int EDIT = 3;
- static final int EDIT = 2;
+ static public final int NOTICE = 0;
+ static public final int ERR = 1;
+ static public final int EDIT = 2;
static final int YES = 1;
static final int NO = 2;
@@ -196,6 +195,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/FindReplace.java b/app/src/processing/app/FindReplace.java
index 736319916..de6e1b34a 100644
--- a/app/src/processing/app/FindReplace.java
+++ b/app/src/processing/app/FindReplace.java
@@ -454,9 +454,22 @@ public class FindReplace extends JFrame {
editor.setSelection(0, 0);
boolean foundAtLeastOne = false;
- while (true) {
+ int startTab = -1, startIndex = -1, c = 50000;
+ // you couldn't seriously be replacing 50K times o_O
+ while (--c > 0) {
if (find(false, false)) {
- foundAtLeastOne = true;
+ if(editor.getSketch().getCurrentCodeIndex() == startTab
+ && editor.getSelectionStart() == startIndex){
+ // we've reached where we started, so stop the replace
+ Toolkit.beep();
+ editor.statusNotice("Reached beginning of search!");
+ break;
+ }
+ if(!foundAtLeastOne){
+ foundAtLeastOne = true;
+ startTab = editor.getSketch().getCurrentCodeIndex();
+ startIndex = editor.getSelectionStart();
+ }
replace();
} else {
break;
diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java
index 237f9f650..ea19fde35 100644
--- a/app/src/processing/app/Mode.java
+++ b/app/src/processing/app/Mode.java
@@ -43,7 +43,7 @@ public abstract class Mode {
protected File folder;
- protected PdeKeywords tokenMarker = new PdeKeywords();
+ protected TokenMarker tokenMarker;
protected HashMap keywordToReference =
new HashMap();
@@ -94,6 +94,7 @@ public abstract class Mode {
public Mode(Base base, File folder) {
this.base = base;
this.folder = folder;
+ tokenMarker = createTokenMarker();
// Get paths for the libraries and examples in the mode folder
examplesFolder = new File(folder, "examples");
@@ -125,27 +126,38 @@ public abstract class Mode {
protected void loadKeywords(File keywordFile) throws IOException {
+ // overridden for Python, where # is an actual keyword
+ loadKeywords(keywordFile, "#");
+ }
+
+
+ protected void loadKeywords(File keywordFile,
+ String commentPrefix) throws IOException {
BufferedReader reader = PApplet.createReader(keywordFile);
String line = null;
while ((line = reader.readLine()) != null) {
-// String[] pieces = PApplet.trim(PApplet.split(line, '\t'));
- String[] pieces = PApplet.splitTokens(line);
- if (pieces.length >= 2) {
- String keyword = pieces[0];
- String coloring = pieces[1];
+ if (!line.trim().startsWith(commentPrefix)) {
+ // Was difficult to make sure that mode authors were properly doing
+ // tab-separated values. By definition, there can't be additional
+ // spaces inside a keyword (or filename), so just splitting on tokens.
+ String[] pieces = PApplet.splitTokens(line);
+ if (pieces.length >= 2) {
+ String keyword = pieces[0];
+ String coloring = pieces[1];
- if (coloring.length() > 0) {
- tokenMarker.addColoring(keyword, coloring);
- }
- if (pieces.length == 3) {
- String htmlFilename = pieces[2];
- if (htmlFilename.length() > 0) {
- // if the file is for the version with parens,
- // add a paren to the keyword
- if (htmlFilename.endsWith("_")) {
- keyword += "_";
+ if (coloring.length() > 0) {
+ tokenMarker.addColoring(keyword, coloring);
+ }
+ if (pieces.length == 3) {
+ String htmlFilename = pieces[2];
+ if (htmlFilename.length() > 0) {
+ // if the file is for the version with parens,
+ // add a paren to the keyword
+ if (htmlFilename.endsWith("_")) {
+ keyword += "_";
+ }
+ keywordToReference.put(keyword, htmlFilename);
}
- keywordToReference.put(keyword, htmlFilename);
}
}
}
@@ -901,6 +913,10 @@ public abstract class Mode {
public TokenMarker getTokenMarker() {
return tokenMarker;
}
+
+ protected TokenMarker createTokenMarker() {
+ return new PdeKeywords();
+ }
// abstract public Formatter createFormatter();
@@ -959,9 +975,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);
}
@@ -998,6 +1015,18 @@ public abstract class Mode {
}
+ /**
+ * @param f File to be checked against this mode's accepted extensions.
+ * @return Whether or not the given file name features an extension supported by this mode.
+ */
+ public boolean canEdit(final File f) {
+ final int dot = f.getName().lastIndexOf('.');
+ if (dot < 0) {
+ return false;
+ }
+ return validExtension(f.getName().substring(dot + 1));
+ }
+
/**
* Check this extension (no dots, please) against the list of valid
* extensions.
@@ -1017,6 +1046,18 @@ public abstract class Mode {
abstract public String getDefaultExtension();
+ /**
+ * Returns the appropriate file extension to use for auxilliary source files in a sketch.
+ * For example, in a Java-mode sketch, auxilliary files should be name "Foo.java"; in
+ * Python mode, they should be named "foo.py".
+ *
+ *
Modes that do not override this function will get the default behavior of returning the
+ * default extension.
+ */
+ public String getModuleExtension() {
+ return getDefaultExtension();
+ }
+
/**
* Returns a String[] array of proper extensions.
@@ -1058,4 +1099,9 @@ public abstract class Mode {
// public void handleNewReplace() {
// base.handleNewReplace();
// }
+
+ @Override
+ public String toString() {
+ return getTitle();
+ }
}
\ No newline at end of file
diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java
index 7115d8908..525ae5f03 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.*;
@@ -61,6 +60,7 @@ import processing.core.*;
*/
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$
@@ -113,19 +113,25 @@ public class Preferences {
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;
JComboBox languageSelectionBox;
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;
@@ -141,7 +147,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);
@@ -239,6 +247,11 @@ public class Preferences {
dialog = new JFrame(Language.text("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);
@@ -321,22 +334,7 @@ public class Preferences {
top += d.height + GUI_BETWEEN;
- // Editor font size [ ]
-
- Container box = Box.createHorizontalBox();
- label = new JLabel(Language.text("preferences.editor_font_size")+": ");
- box.add(label);
- fontSizeField = new JTextField(4);
- box.add(fontSizeField);
- label = new JLabel(" ("+Language.text("preferences.requires_restart")+")");
- 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
@@ -345,20 +343,70 @@ 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(Language.text("preferences.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(Language.text("preferences.editor_font_size")+": ");
+ box.add(label);
+ //fontSizeField = new JTextField(4);
+ fontSizeField = new JComboBox(FONT_SIZES);
+// fontSizeField = new JComboBox(FONT_SIZES);
+ fontSizeField.setEditable(true);
+ box.add(fontSizeField);
+// label = new JLabel(" ("+Language.text("preferences.requires_restart")+")");
+// label = new JLabel(" (requires restart of Processing)");
+// box.add(label);
+ box.add(Box.createHorizontalStrut(GUI_BETWEEN));
+
+ label = new JLabel(Language.text("preferences.console_font_size")+": ");
+
+ box.add(label);
+// consoleSizeField = new JComboBox(FONT_SIZES);
+ 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(Language.text("preferences.use_smooth_text")+
- " ("+Language.text("preferences.requires_restart")+")");
+ editorAntialiasBox = new JCheckBox(Language.text("preferences.use_smooth_text"));
+// 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
@@ -407,17 +455,17 @@ public class Preferences {
// top += d.height + GUI_BETWEEN;
- // [ ] Delete previous folder on export
+ // [ ] Delete previous application folder on export
deletePreviousBox =
- new JCheckBox(Language.text("preferences.delete_previous_folder_on_export"));
+ new JCheckBox(Language.text("preferences.delete_previous_folder_on_export"));
pain.add(deletePreviousBox);
d = deletePreviousBox.getPreferredSize();
deletePreviousBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
-
-
+
+
// // [ ] Use external editor
//
// externalEditorBox = new JCheckBox("Use external editor");
@@ -480,6 +528,7 @@ public class Preferences {
// Launch programs as [ ] 32-bit [ ] 64-bit (Mac OS X only)
+ /*
if (Base.isMacOS()) {
box = Box.createHorizontalBox();
label = new JLabel(Language.text("preferences.launch_programs_in")+" ");
@@ -498,6 +547,7 @@ public class Preferences {
box.setBounds(left, top, d.width, d.height);
top += d.height + GUI_BETWEEN;
}
+ */
// More preferences are in the ...
@@ -644,7 +694,8 @@ 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.delete_target_folder", //$NON-NLS-1$
deletePreviousBox.isSelected());
@@ -717,6 +768,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()) {
@@ -729,16 +781,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$
@@ -755,7 +842,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
@@ -788,12 +875,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$
@@ -807,6 +905,7 @@ public class Preferences {
bitsThirtyTwoButton.setEnabled(false);
}
}
+ */
if (autoAssociateBox != null) {
autoAssociateBox.
@@ -817,6 +916,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;
@@ -1059,6 +1215,7 @@ public class Preferences {
}
+ /*
static public SyntaxStyle getStyle(String what) {
String str = get("editor." + what + ".style"); //, dflt); //$NON-NLS-1$ //$NON-NLS-2$
@@ -1073,9 +1230,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/Recent.java b/app/src/processing/app/Recent.java
index 4af3a566c..8dc1069b1 100644
--- a/app/src/processing/app/Recent.java
+++ b/app/src/processing/app/Recent.java
@@ -118,7 +118,14 @@ public class Recent {
menu.removeAll();
String sketchbookPath = Base.getSketchbookFolder().getAbsolutePath();
// String homePath = System.getProperty("user.home");
- for (final Record rec : records) {
+ for (Record rec : records) {
+ updateMenuRecord(menu, rec, sketchbookPath);
+ }
+ }
+
+
+ private void updateMenuRecord(JMenu menu, final Record rec, String sketchbookPath) {
+ try {
String recPath = new File(rec.getPath()).getParent();
String purtyPath = null;
@@ -197,6 +204,11 @@ public class Recent {
});
//menu.add(item);
menu.insert(item, 0);
+
+ } catch (Exception e) {
+ // Strange things can happen... report them for the geeky and move on:
+ // https://github.com/processing/processing/issues/2463
+ e.printStackTrace();
}
}
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
index 194438a52..41cb57482 100644
--- a/app/src/processing/app/Sketch.java
+++ b/app/src/processing/app/Sketch.java
@@ -179,7 +179,7 @@ public class Sketch {
// Don't allow people to use files with invalid names, since on load,
// it would be otherwise possible to sneak in nasty filenames. [0116]
- if (Sketch.isSanitaryName(base)) {
+ if (isSanitaryName(base)) {
code[codeCount++] =
new SketchCode(new File(folder, filename), extension);
}
@@ -324,7 +324,7 @@ public class Sketch {
renamingCode = true;
String prompt = (currentIndex == 0) ?
"New name for sketch:" : "New name for file:";
- String oldName = (current.isExtension("pde")) ?
+ String oldName = (current.isExtension(mode.getDefaultExtension())) ?
current.getPrettyName() : current.getFileName();
editor.status.edit(prompt, oldName);
}
@@ -333,17 +333,19 @@ public class Sketch {
/**
* This is called upon return from entering a new file name.
* (that is, from either newCode or renameCode after the prompt)
- * This code is almost identical for both the newCode and renameCode
- * cases, so they're kept merged except for right in the middle
- * where they diverge.
*/
protected void nameCode(String newName) {
+ newName = newName.trim();
+ if (newName.length() == 0) {
+ return;
+ }
+
// make sure the user didn't hide the sketch folder
ensureExistence();
// Add the extension here, this simplifies some of the logic below.
if (newName.indexOf('.') == -1) {
- newName += "." + mode.getDefaultExtension();
+ newName += "." + (renamingCode ? mode.getDefaultExtension() : mode.getModuleExtension());
}
// if renaming to the same thing as before, just ignore.
@@ -359,21 +361,18 @@ public class Sketch {
}
}
- newName = newName.trim();
- if (newName.equals("")) return;
-
- int dot = newName.indexOf('.');
- if (dot == 0) {
+ if (newName.startsWith(".")) {
Base.showWarning("Problem with rename",
- "The name cannot start with a period.", null);
+ "The name cannot start with a period.");
return;
}
+ int dot = newName.lastIndexOf('.');
String newExtension = newName.substring(dot+1).toLowerCase();
if (!mode.validExtension(newExtension)) {
Base.showWarning("Problem with rename",
"\"." + newExtension + "\"" +
- "is not a valid extension.", null);
+ "is not a valid extension.");
return;
}
@@ -384,7 +383,7 @@ public class Sketch {
Base.showWarning("Problem with rename",
"The first tab cannot be a ." + newExtension + " file.\n" +
"(It may be time for your to graduate to a\n" +
- "\"real\" programming environment, hotshot.)", null);
+ "\"real\" programming environment, hotshot.)");
return;
}
}
@@ -425,14 +424,14 @@ public class Sketch {
if (newFolder.exists()) {
Base.showWarning("Cannot Rename",
"Sorry, a sketch (or folder) named " +
- "\"" + newName + "\" already exists.", null);
+ "\"" + newName + "\" already exists.");
return;
}
// renaming the containing sketch folder
boolean success = folder.renameTo(newFolder);
if (!success) {
- Base.showWarning("Error", "Could not rename the sketch folder.", null);
+ Base.showWarning("Error", "Could not rename the sketch folder.");
return;
}
// let this guy know where he's living (at least for a split second)
@@ -454,7 +453,7 @@ public class Sketch {
if (!current.renameTo(newFile, newExtension)) {
Base.showWarning("Error",
"Could not rename \"" + current.getFileName() +
- "\" to \"" + newFile.getName() + "\"", null);
+ "\" to \"" + newFile.getName() + "\"");
return;
}
@@ -486,7 +485,7 @@ public class Sketch {
if (!current.renameTo(newFile, newExtension)) {
Base.showWarning("Error",
"Could not rename \"" + current.getFileName() +
- "\" to \"" + newFile.getName() + "\"", null);
+ "\" to \"" + newFile.getName() + "\"");
return;
}
}
@@ -870,7 +869,7 @@ public class Sketch {
}
// save the main tab with its new name
- File newFile = new File(newFolder, newName + ".pde");
+ File newFile = new File(newFolder, newName + "." + mode.getDefaultExtension());
code[0].saveAs(newFile);
updateInternal(newName, newFolder);
@@ -1434,11 +1433,13 @@ public class Sketch {
/**
- * Return true if the name is valid for a Processing sketch.
+ * Return true if the name is valid for a Processing sketch. Extensions of the form .foo are
+ * ignored.
*/
- static public boolean isSanitaryName(String name) {
- if (name.toLowerCase().endsWith(".pde")) {
- name = name.substring(0, name.length() - 4);
+ public static boolean isSanitaryName(String name) {
+ final int dot = name.lastIndexOf('.');
+ if (dot >= 0) {
+ name = name.substring(0, dot);
}
return sanitizeName(name).equals(name);
}
diff --git a/app/src/processing/app/SketchCode.java b/app/src/processing/app/SketchCode.java
index 8deaedbe7..4b1a45814 100644
--- a/app/src/processing/app/SketchCode.java
+++ b/app/src/processing/app/SketchCode.java
@@ -94,7 +94,7 @@ public class SketchCode {
protected void makePrettyName() {
prettyName = file.getName();
- int dot = prettyName.indexOf('.');
+ int dot = prettyName.lastIndexOf('.');
prettyName = prettyName.substring(0, dot);
}
diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java
index a22ca11b9..34aa23834 100644
--- a/app/src/processing/app/Toolkit.java
+++ b/app/src/processing/app/Toolkit.java
@@ -30,18 +30,22 @@ import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
+import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionEvent;
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;
@@ -148,17 +152,22 @@ public class Toolkit {
static ArrayList iconImages;
+
+ // Deprecated version of the function, but can't get rid of it without
+ // breaking tools and modes (they'd only require a recompile, but they would
+ // no longer be backwards compatible.
+ static public void setIcon(Frame frame) {
+ setIcon((Window) frame);
+ }
+
+
/**
* Give this Frame the Processing icon set. Ignored on OS X, because they
* thought different and made this function set the minified image of the
* window, not the window icon for the dock or cmd-tab.
*/
- static public void setIcon(Frame frame) {
+ static public void setIcon(Window window) {
if (!Base.isMacOS()) {
-// // too low-res, prepping for nicer icons in 2.0 timeframe
-// Image image = awtToolkit.createImage(PApplet.ICON_IMAGE);
-// frame.setIconImage(image);
-
if (iconImages == null) {
iconImages = new ArrayList();
final int[] sizes = { 16, 32, 48, 64, 128, 256, 512 };
@@ -166,7 +175,7 @@ public class Toolkit {
iconImages.add(Toolkit.getLibImage("icons/pde-" + sz + ".png"));
}
}
- frame.setIconImages(iconImages);
+ window.setIconImages(iconImages);
}
}
@@ -320,17 +329,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);
@@ -341,20 +414,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);
}
@@ -365,26 +433,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/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java
index 86693e6a3..fe98fab2b 100644
--- a/app/src/processing/app/UpdateCheck.java
+++ b/app/src/processing/app/UpdateCheck.java
@@ -112,8 +112,9 @@ public class UpdateCheck {
boolean offerToUpdateContributions = true;
if (latest > Base.getRevision()) {
- System.out.println("You are running Processing revision " +
- Base.getRevision() + ", the latest is " + latest + ".");
+ System.out.println("You are running Processing revision 0" +
+ Base.getRevision() + ", the latest build is 0" +
+ latest + ".");
// Assume the person is busy downloading the latest version
offerToUpdateContributions = !promptToVisitDownloadPage();
}
diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java
index b4cb57cd4..a815ab6da 100644
--- a/app/src/processing/app/contrib/AvailableContribution.java
+++ b/app/src/processing/app/contrib/AvailableContribution.java
@@ -48,7 +48,10 @@ class AvailableContribution extends Contribution {
url = params.get("url");
sentence = params.get("sentence");
paragraph = params.get("paragraph");
- version = PApplet.parseInt(params.get("version"), 0);
+ String versionStr = params.get("version");
+ if (versionStr != null) {
+ version = PApplet.parseInt(versionStr, 0);
+ }
prettyVersion = params.get("prettyVersion");
}
diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java
index 0bc88268b..8367b98d3 100644
--- a/app/src/processing/app/contrib/Contribution.java
+++ b/app/src/processing/app/contrib/Contribution.java
@@ -152,12 +152,22 @@ abstract public class Contribution {
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 public List parseCategories(String categoryStr) {
+ static List parseCategories(String categoryStr) {
List outgoing = new ArrayList();
if (categoryStr != null) {
@@ -169,7 +179,7 @@ abstract public class Contribution {
}
}
if (outgoing.size() == 0) {
- outgoing.add("Unknown");
+ return defaultCategory();
}
return outgoing;
}
diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java
index 149cb3fdc..05531f63d 100644
--- a/app/src/processing/app/contrib/ContributionListing.java
+++ b/app/src/processing/app/contrib/ContributionListing.java
@@ -87,9 +87,10 @@ public class ContributionListing {
*/
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);
}
diff --git a/app/src/processing/app/contrib/ContributionManager.java b/app/src/processing/app/contrib/ContributionManager.java
index 5bb246259..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();
diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java
index 1d05ad609..6583acff9 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();
}
}
});
diff --git a/app/src/processing/app/contrib/ContributionPanel.java b/app/src/processing/app/contrib/ContributionPanel.java
index 09ba24faf..ca6f2da4e 100644
--- a/app/src/processing/app/contrib/ContributionPanel.java
+++ b/app/src/processing/app/contrib/ContributionPanel.java
@@ -122,6 +122,7 @@ class ContributionPanel extends JPanel {
updateButton.setEnabled(false);
installRemoveButton.setEnabled(false);
installProgressBar.setVisible(true);
+ installProgressBar.setIndeterminate(true);
((LocalContribution) contrib).removeContribution(listPanel.contribManager.editor,
new JProgressMonitor(installProgressBar) {
@@ -484,7 +485,7 @@ class ContributionPanel extends JPanel {
protected void resetInstallProgressBarState() {
installProgressBar.setString("Starting");
- installProgressBar.setIndeterminate(true);
+ installProgressBar.setIndeterminate(false);
installProgressBar.setValue(0);
installProgressBar.setVisible(false);
}
diff --git a/app/src/processing/app/contrib/LocalContribution.java b/app/src/processing/app/contrib/LocalContribution.java
index cc494b613..03a6e0f31 100644
--- a/app/src/processing/app/contrib/LocalContribution.java
+++ b/app/src/processing/app/contrib/LocalContribution.java
@@ -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();
}
}
diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java
index 4a927c895..052628e7b 100644
--- a/app/src/processing/app/contrib/ModeContribution.java
+++ b/app/src/processing/app/contrib/ModeContribution.java
@@ -24,7 +24,6 @@ package processing.app.contrib;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.*;
-import java.util.HashMap;
import processing.app.Base;
import processing.app.Mode;
@@ -43,19 +42,19 @@ public class ModeContribution extends LocalContribution {
String searchName) {
try {
return new ModeContribution(base, folder, searchName);
+
} catch (IgnorableException ig) {
Base.log(ig.getMessage());
- } catch (Error err) {
- // Handles UnsupportedClassVersionError and others
- err.printStackTrace();
- } 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,
// 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;
@@ -95,17 +94,32 @@ public class ModeContribution extends LocalContribution {
existing.put(contrib.getFolder(), contrib);
}
File[] potential = ContributionType.MODE.listCandidates(modesFolder);
- 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) {
- e.printStackTrace();
+ // 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 (Throwable e) {
+ e.printStackTrace();
+ }
}
}
}
+
+ // This allows you to build and test your Mode code from Eclipse.
+ // -Dusemode=com.foo.FrobMode:/path/to/FrobMode/resources
+ final String usemode = System.getProperty("usemode");
+ if (usemode != null) {
+ final String[] modeinfo = usemode.split(":", 2);
+ final String modeClass = modeinfo[0];
+ final String modeResourcePath = modeinfo[1];
+ System.err.println("Attempting to load " + modeClass + " with resources at " + modeResourcePath);
+ contribModes.add(ModeContribution.load(base, new File(modeResourcePath), modeClass));
+ }
}
diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java
index 978e95f49..bccbda1bb 100644
--- a/app/src/processing/app/contrib/ToolContribution.java
+++ b/app/src/processing/app/contrib/ToolContribution.java
@@ -74,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/exec/ProcessHelper.java b/app/src/processing/app/exec/ProcessHelper.java
index 66e9d331f..0bbd2aa97 100644
--- a/app/src/processing/app/exec/ProcessHelper.java
+++ b/app/src/processing/app/exec/ProcessHelper.java
@@ -128,37 +128,19 @@ public class ProcessHelper {
}
-// static public ProcessResult execute(String exe, String[] args, File dir)
-// throws InterruptedException, IOException {
-// final StringWriter outWriter = new StringWriter();
-// final StringWriter errWriter = new StringWriter();
-// final long startTime = System.currentTimeMillis();
-//
-// final String prettyCommand = exe + " " + PApplet.join(args, " ");
-// System.out.println("pretty cmd is " + prettyCommand);
-// final Process process = dir == null ?
-// Runtime.getRuntime().exec(exe, args) :
-// Runtime.getRuntime().exec(exe, args, dir);
-// ProcessRegistry.watch(process);
-// try {
-// String title = prettyCommand;
-// new StreamPump(process.getInputStream(), "out: " + title).addTarget(outWriter).start();
-// new StreamPump(process.getErrorStream(), "err: " + title).addTarget(errWriter).start();
-// try {
-// final int result = process.waitFor();
-// final long time = System.currentTimeMillis() - startTime;
-// // System.err.println("ProcessHelper: <<<<< "
-// // + Thread.currentThread().getId() + " " + cmd[0] + " (" + time
-// // + "ms)");
-// return new ProcessResult(prettyCommand, result, outWriter.toString(),
-// errWriter.toString(), time);
-// } catch (final InterruptedException e) {
-// System.err.println("Interrupted: " + prettyCommand);
-// throw e;
-// }
-// } finally {
-// process.destroy();
-// ProcessRegistry.unwatch(process);
-// }
-// }
+ static public boolean ffs(final String... cmd) {
+ try {
+ ProcessHelper helper = new ProcessHelper(cmd);
+ ProcessResult result = helper.execute();
+ if (result.succeeded()) {
+ return true;
+ }
+ System.out.println(result.getStdout());
+ System.err.println(result.getStderr());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/app/src/processing/app/languages/PDE.properties b/app/src/processing/app/languages/PDE.properties
index d1982b8aa..9903f65a8 100644
--- a/app/src/processing/app/languages/PDE.properties
+++ b/app/src/processing/app/languages/PDE.properties
@@ -1,7 +1,7 @@
# ---------------------------------------
-# Language: English (en) (Default)
+# Language: English (en) (default)
# ---------------------------------------
@@ -118,7 +118,9 @@ preferences.button.width = 80
preferences.requires_restart = requires restart of Processing
preferences.sketchbook_location = Sketchook location
preferences.language = Language
+preferences.editor_and_console_font = Editor and Console font
preferences.editor_font_size = Editor font size
+preferences.console_font_size = Console font size
preferences.use_smooth_text = Use smooth text in editor window
preferences.enable_complex_text_input = Enable complex text input
preferences.enable_complex_text_input_example = i.e. Japanese
diff --git a/app/src/processing/app/languages/PDE_de.properties b/app/src/processing/app/languages/PDE_de.properties
index b7c357b94..f0630fef4 100644
--- a/app/src/processing/app/languages/PDE_de.properties
+++ b/app/src/processing/app/languages/PDE_de.properties
@@ -1,7 +1,7 @@
# ---------------------------------------
-# Language: Deutsch (de)
+# Language: German (Deutsch) (de)
# ---------------------------------------
@@ -113,7 +113,9 @@ preferences.button.width = 110
preferences.requires_restart = nach Neustart von Processing aktiv
preferences.sketchbook_location = Sketchbook Pfad
preferences.language = Sprache
+preferences.editor_and_console_font = Editor und Console Schriftart
preferences.editor_font_size = Editor Schriftgre
+preferences.console_font_size = Console Schriftgre
preferences.use_smooth_text = Editor Textglttung
preferences.enable_complex_text_input = Komplexe Sprachen erlauben
preferences.enable_complex_text_input_example = z.B. Japanisch
diff --git a/app/src/processing/app/platform/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java
index 79caaa338..aba1ed4ba 100644
--- a/app/src/processing/app/platform/ThinkDifferent.java
+++ b/app/src/processing/app/platform/ThinkDifferent.java
@@ -22,13 +22,10 @@
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;
@@ -77,38 +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
-// if (System.getProperty("java.vendor").contains("Apple") ||
-// Base.isUsableOracleJava()) {
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.err.println("Skipping default menu bar due to Oracle Java 7 bug:");
- System.err.println("http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267");
+ // 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/syntax/Brackets.java b/app/src/processing/app/syntax/Brackets.java
index c35e9c359..1fd46ec27 100644
--- a/app/src/processing/app/syntax/Brackets.java
+++ b/app/src/processing/app/syntax/Brackets.java
@@ -90,7 +90,7 @@ public class Brackets {
readComment(text);
} else if (d == '*') {
readMLComment(text);
- }
+ } else pos--; // Go back because there isn't a comment.
} else if (c == '"' || c == '\'') {
readString(text, c);
} else if (c == '{' || c == '[' || c == '(' || c == '}' || c == ']'
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 89b77502f..de7eb16ce 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;
@@ -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;
@@ -190,26 +192,65 @@ public class JEditTextArea extends JComponent
/**
* Get current position of the vertical scroll bar. [fry]
+ * @deprecated Use {@link #getVerticalScrollPosition()}.
*/
public int getScrollPosition() {
- return vertical.getValue();
+ return getVerticalScrollPosition();
}
/**
* Set position of the vertical scroll bar. [fry]
+ * @deprecated Use {@link #setVerticalScrollPosition(int)}.
*/
public void setScrollPosition(int what) {
- vertical.setValue(what);
+ setVerticalScrollPosition(what);
+ }
+
+
+ /**
+ * Get current position of the vertical scroll bar.
+ */
+ public int getVerticalScrollPosition() {
+ return vertical.getValue();
}
+ /**
+ * Set position of the vertical scroll bar.
+ */
+ public void setVerticalScrollPosition(int what) {
+ vertical.setValue(what);
+ }
+
+
+ /**
+ * Get current position of the horizontal scroll bar.
+ */
+ public int getHorizontalScrollPosition() {
+ return horizontal.getValue();
+ }
+
+
+ /**
+ * Set position of the horizontal scroll bar.
+ */
+ public void setHorizontalScrollPosition(int what) {
+ horizontal.setValue(what);
+ }
+
+
/**
* Returns the object responsible for painting this text area.
*/
public final TextAreaPainter getPainter() {
return painter;
}
+
+
+ public final Printable getPrintable() {
+ return painter.getPrintable();
+ }
/**
@@ -587,7 +628,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 +640,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 +716,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;
@@ -766,8 +810,8 @@ public class JEditTextArea extends JComponent
* Set document with a twist, includes the old caret
* and scroll positions, added for p5. [fry]
*/
- public void setDocument(SyntaxDocument document,
- int start, int stop, int scroll) {
+ public void setDocument(SyntaxDocument document,
+ int start, int stop, int scroll) {
if (this.document == document)
return;
if (this.document != null)
@@ -778,7 +822,7 @@ public class JEditTextArea extends JComponent
select(start, stop);
updateScrollBars();
- setScrollPosition(scroll);
+ setVerticalScrollPosition(scroll);
painter.repaint();
}
@@ -787,65 +831,60 @@ public class JEditTextArea extends JComponent
* Returns the document's token marker. Equivalent to calling
* getDocument().getTokenMarker().
*/
- public final TokenMarker getTokenMarker()
- {
+ public final TokenMarker getTokenMarker() {
return document.getTokenMarker();
}
+
/**
* Sets the document's token marker. Equivalent to caling
* getDocument().setTokenMarker().
* @param tokenMarker The token marker
*/
- public final void setTokenMarker(TokenMarker tokenMarker)
- {
+ public final void setTokenMarker(TokenMarker tokenMarker) {
document.setTokenMarker(tokenMarker);
}
+
/**
* Returns the length of the document. Equivalent to calling
* getDocument().getLength().
*/
- public final int getDocumentLength()
- {
+ public final int getDocumentLength() {
return document.getLength();
}
+
/**
* Returns the number of lines in the document.
*/
- public final int getLineCount()
- {
+ public final int getLineCount() {
return document.getDefaultRootElement().getElementCount();
}
+
/**
* Returns the line containing the specified offset.
* @param offset The offset
*/
- public final int getLineOfOffset(int offset)
- {
+ public final int getLineOfOffset(int offset) {
return document.getDefaultRootElement().getElementIndex(offset);
}
+
/**
* Returns the start offset of the specified line.
* @param line The line
* @return The start offset of the specified line, or -1 if the line is
* invalid
*/
- public int getLineStartOffset(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getStartOffset();
+ public int getLineStartOffset(int line) {
+ Element lineElement = document.getDefaultRootElement().getElement(line);
+ return (lineElement == null) ? -1 : lineElement.getStartOffset();
}
- public int getLineStartNonWhiteSpaceOffset(int line)
- {
+
+ public int getLineStartNonWhiteSpaceOffset(int line) {
int offset = getLineStartOffset(line);
int length = getLineLength(line);
String str = getText(offset, length);
@@ -858,37 +897,33 @@ public class JEditTextArea extends JComponent
return offset + length;
}
+
/**
* Returns the end offset of the specified line.
* @param line The line
* @return The end offset of the specified line, or -1 if the line is
* invalid.
*/
- public int getLineStopOffset(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getEndOffset();
+ public int getLineStopOffset(int line) {
+ Element lineElement = document.getDefaultRootElement().getElement(line);
+ return (lineElement == null) ? -1 : lineElement.getEndOffset();
}
- public int getLineStopNonWhiteSpaceOffset(int line)
- {
+
+ public int getLineStopNonWhiteSpaceOffset(int line) {
int offset = getLineStopOffset(line);
int length = getLineLength(line);
String str = getText(offset - length - 1, length);
- for(int i = 0; i < length; i++) {
+ for (int i = 0; i < length; i++) {
if(!Character.isWhitespace(str.charAt(length - i - 1))) {
return offset - i;
}
}
-
return offset - length;
}
+
/**
* Returns the start offset of the line after this line, or the end of
* this line if there is no next line.
@@ -896,42 +931,32 @@ public class JEditTextArea extends JComponent
* @return The end offset of the specified line, or -1 if the line is
* invalid.
*/
- public int getLineSelectionStopOffset(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return Math.min(lineElement.getEndOffset(),getDocumentLength());
+ public int getLineSelectionStopOffset(int line) {
+ Element lineElement = document.getDefaultRootElement().getElement(line);
+ return (lineElement == null) ? -1 :
+ Math.min(lineElement.getEndOffset(), getDocumentLength());
}
+
/**
* Returns the length of the specified line.
* @param line The line
*/
- public int getLineLength(int line)
- {
- Element lineElement = document.getDefaultRootElement()
- .getElement(line);
- if(lineElement == null)
- return -1;
- else
- return lineElement.getEndOffset()
- - lineElement.getStartOffset() - 1;
+ public int getLineLength(int line) {
+ Element lineElement = document.getDefaultRootElement().getElement(line);
+ return (lineElement == null) ? -1 :
+ lineElement.getEndOffset() - lineElement.getStartOffset() - 1;
}
+
/**
* Returns the entire text of this text area.
*/
- public String getText()
- {
- try
- {
+ public String getText() {
+ try {
return document.getText(0,document.getLength());
- }
- catch(BadLocationException bl)
- {
+
+ } catch(BadLocationException bl) {
bl.printStackTrace();
return null;
}
@@ -941,8 +966,7 @@ public class JEditTextArea extends JComponent
/**
* Sets the entire text of this text area.
*/
- public void setText(String text)
- {
+ public void setText(String text) {
try {
document.beginCompoundEdit();
document.remove(0,document.getLength());
@@ -963,18 +987,16 @@ public class JEditTextArea extends JComponent
* @param len The length of the substring
* @return The substring, or null if the offsets are invalid
*/
- public final String getText(int start, int len)
- {
- try
- {
+ public final String getText(int start, int len) {
+ try {
return document.getText(start,len);
- }
- catch(BadLocationException bl)
- {
+
+ } catch(BadLocationException bl) {
bl.printStackTrace();
return null;
}
}
+
/**
* Copies the specified substring of the document into a segment.
@@ -983,49 +1005,47 @@ public class JEditTextArea extends JComponent
* @param len The length of the substring
* @param segment The segment
*/
- public final void getText(int start, int len, Segment segment)
- {
- try
- {
+ public final void getText(int start, int len, Segment segment) {
+ try {
document.getText(start,len,segment);
- }
- catch(BadLocationException bl)
- {
+
+ } catch(BadLocationException bl) {
bl.printStackTrace();
segment.offset = segment.count = 0;
}
}
+
/**
* Returns the text on the specified line.
* @param lineIndex The line
* @return The text, or null if the line is invalid
*/
- public final String getLineText(int lineIndex)
- {
+ public final String getLineText(int lineIndex) {
int start = getLineStartOffset(lineIndex);
return getText(start,getLineStopOffset(lineIndex) - start - 1);
}
+
/**
* Copies the text on the specified line into a segment. If the line
* is invalid, the segment will contain a null string.
* @param lineIndex The line
*/
- public final void getLineText(int lineIndex, Segment segment)
- {
+ public final void getLineText(int lineIndex, Segment segment) {
int start = getLineStartOffset(lineIndex);
getText(start,getLineStopOffset(lineIndex) - start - 1,segment);
}
+
/**
* Returns the selection start offset.
*/
- public final int getSelectionStart()
- {
+ public final int getSelectionStart() {
return selectionStart;
}
+
/**
* Returns the offset where the selection starts on the specified
* line.
@@ -1395,30 +1415,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 +1440,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.
@@ -1983,7 +1975,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;
@@ -2369,28 +2361,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?
@@ -2403,48 +2388,54 @@ 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());
+ // isPopupTrigger() is handled differently across platforms,
+ // so it may fire during release, or during the press.
+ // http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html#isPopupTrigger()
+ // However, we have to exit out of this method if it's a right-click
+ // anyway, because otherwise it'll de-select the current word.
+ // As a result, better to just check for BUTTON3 now, indicating that
+ // isPopupTrigger() is going to fire on the release anyway.
+ boolean windowsRightClick =
+ Base.isWindows() && (event.getButton() == MouseEvent.BUTTON3);
+ if ((event.isPopupTrigger() || windowsRightClick) && (popup != null)) {
+// // Windows fires the popup trigger on release (see mouseReleased() below)(
+// if (!Base.isWindows()) {
+// 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) {
@@ -2455,8 +2446,19 @@ 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);
@@ -2466,35 +2468,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);
@@ -2505,11 +2504,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;
@@ -2517,61 +2516,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 977d6f4b7..8d8b60b23 100644
--- a/app/src/processing/app/syntax/PdeKeywords.java
+++ b/app/src/processing/app/syntax/PdeKeywords.java
@@ -29,10 +29,6 @@ import javax.swing.text.Segment;
import processing.app.Editor;
-/**
- * This class reads a keywords.txt file to get coloring put links to reference
- * locations for the set of keywords.
- */
public class PdeKeywords extends TokenMarker {
private KeywordMap keywordColoring;
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..8c971605c 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,47 @@ 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;
}
+// };
+
+
+ // do we go here? do will kill tabs?
+// public float nextTabStop(float x, int tabOffset) {
+// return x;
+// }
+
- /**
- * 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 +597,7 @@ implements TabExpander, Printable {
public int getCurrentLineIndex() {
return currentLineIndex;
}
+
/**
* Accessor used by tools that want to hook in and grab the formatting.
@@ -528,6 +605,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 +614,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 +631,177 @@ 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 = currentLine.array[currentLine.offset + i] == '\t' ? (int)nextTabStop(x, i) :
+ x + fm.charWidth(currentLine.array[currentLine.offset+i]);
+ }
- 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 = line.array[line.offset + i] == '\t' ? (int)nextTabStop(x, i) :
+ x + fm.charWidth(line.array[line.offset+i]);
+ }
+ //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 +814,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 +863,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 +882,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 +890,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
@@ -761,4 +910,4 @@ implements TabExpander, Printable {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/processing/app/syntax/TokenMarker.java b/app/src/processing/app/syntax/TokenMarker.java
index 363bb61e3..0e414e901 100644
--- a/app/src/processing/app/syntax/TokenMarker.java
+++ b/app/src/processing/app/syntax/TokenMarker.java
@@ -25,6 +25,8 @@ import javax.swing.text.Segment;
*/
public abstract class TokenMarker
{
+ abstract public void addColoring(String keyword, String coloring);
+
/**
* A wrapper for the lower-level markTokensImpl method
* that is called to split a line up into tokens.
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
index e81ad47ee..a10643649 100644
--- a/app/src/processing/app/tools/Archiver.java
+++ b/app/src/processing/app/tools/Archiver.java
@@ -102,6 +102,11 @@ public class Archiver implements Tool {
public void fileSelected(File newbie) {
if (newbie != null) {
try {
+ // Force a .zip extension
+ // https://github.com/processing/processing/issues/2526
+ if (!newbie.getName().toLowerCase().endsWith(".zip")) {
+ newbie = new File(newbie.getAbsolutePath() + ".zip");
+ }
//System.out.println(newbie);
FileOutputStream zipOutputFile = new FileOutputStream(newbie);
ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
diff --git a/app/src/processing/app/tools/ColorSelector.java b/app/src/processing/app/tools/ColorSelector.java
index f600128d6..59cce7760 100644
--- a/app/src/processing/app/tools/ColorSelector.java
+++ b/app/src/processing/app/tools/ColorSelector.java
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2006-12 Ben Fry and Casey Reas
+ Copyright (c) 2006-14 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
@@ -22,19 +22,11 @@
package processing.app.tools;
import processing.app.*;
-import processing.core.*;
-import java.awt.BorderLayout;
import java.awt.Color;
-import java.awt.Container;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Graphics;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.border.*;
-import javax.swing.event.*;
-import javax.swing.text.*;
/**
@@ -45,597 +37,39 @@ import javax.swing.text.*;
* auto-insert of colorMode() or fill() or stroke() code cuz we couldn't
* decide on a good way to do this.. your contributions welcome).
*/
-public class ColorSelector implements Tool, DocumentListener {
-
-// Editor editor;
+public class ColorSelector implements Tool {
/**
* Only create one instance, otherwise we'll have dozens of animation
* threads going if you open/close a lot of editor windows.
*/
- static JFrame frame;
-
- int hue, saturation, brightness; // range 360, 100, 100
- int red, green, blue; // range 256, 256, 256
-
- ColorRange range;
- ColorSlider slider;
-
- JTextField hueField, saturationField, brightnessField;
- JTextField redField, greenField, blueField;
-
- JTextField hexField;
-
- JPanel colorPanel;
-
+ static ColorChooser selector;
+
public String getMenuTitle() {
return Language.text("menu.tools.color_selector");
}
public void init(Editor editor) {
-// this.editor = editor;
- if (frame == null) {
- createFrame();
+
+ // Language.text("color_selector")
+
+ if (selector == null) {
+ selector = new ColorChooser(editor, false, Color.WHITE,
+ "Copy", new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Clipboard clipboard = Toolkit.getSystemClipboard();
+ clipboard.setContents(new StringSelection(selector.getHexColor()), null);
+ }
+ });
}
}
- void createFrame() {
- frame = new JFrame(Language.text("color_selector"));
- frame.getContentPane().setLayout(new BorderLayout());
-
- Box box = Box.createHorizontalBox();
- box.setBorder(new EmptyBorder(12, 12, 12, 12));
-
- range = new ColorRange();
- range.init();
- Box rangeBox = new Box(BoxLayout.Y_AXIS);
- rangeBox.setAlignmentY(0);
- rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
- rangeBox.add(range);
- box.add(rangeBox);
- box.add(Box.createHorizontalStrut(10));
-
- slider = new ColorSlider();
- slider.init();
- Box sliderBox = new Box(BoxLayout.Y_AXIS);
- sliderBox.setAlignmentY(0);
- sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
- sliderBox.add(slider);
- box.add(sliderBox);
- box.add(Box.createHorizontalStrut(10));
-
- box.add(createColorFields());
- box.add(Box.createHorizontalStrut(10));
-
- frame.getContentPane().add(box, BorderLayout.CENTER);
- frame.pack();
- frame.setResizable(false);
-
- // these don't help either.. they fix the component size but
- // leave a gap where the component is located
- //range.setSize(256, 256);
- //slider.setSize(256, 20);
-
- Dimension size = frame.getSize();
- Dimension screen = Toolkit.getScreenSize();
- frame.setLocation((screen.width - size.width) / 2,
- (screen.height - size.height) / 2);
-
- frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
- frame.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- frame.setVisible(false);
- }
- });
- Toolkit.registerWindowCloseKeys(frame.getRootPane(), new ActionListener() {
- public void actionPerformed(ActionEvent actionEvent) {
- frame.setVisible(false);
- }
- });
-
- Toolkit.setIcon(frame);
-
- hueField.getDocument().addDocumentListener(this);
- saturationField.getDocument().addDocumentListener(this);
- brightnessField.getDocument().addDocumentListener(this);
- redField.getDocument().addDocumentListener(this);
- greenField.getDocument().addDocumentListener(this);
- blueField.getDocument().addDocumentListener(this);
- hexField.getDocument().addDocumentListener(this);
-
- hexField.setText("#FFFFFF");
- }
-
-
public void run() {
- frame.setVisible(true);
- // You've got to be f--ing kidding me.. why did the following line
- // get deprecated for the pile of s-- that follows it?
- //frame.setCursor(Cursor.CROSSHAIR_CURSOR);
- frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ selector.show();
}
-
-
- public void changedUpdate(DocumentEvent e) {
- //System.out.println("changed");
- }
-
- public void removeUpdate(DocumentEvent e) {
- //System.out.println("remove");
- }
-
-
- boolean updating;
-
- public void insertUpdate(DocumentEvent e) {
- if (updating) return; // don't update forever recursively
- updating = true;
-
- Document doc = e.getDocument();
- if (doc == hueField.getDocument()) {
- hue = bounded(hue, hueField, 359);
- updateRGB();
- updateHex();
-
- } else if (doc == saturationField.getDocument()) {
- saturation = bounded(saturation, saturationField, 99);
- updateRGB();
- updateHex();
-
- } else if (doc == brightnessField.getDocument()) {
- brightness = bounded(brightness, brightnessField, 99);
- updateRGB();
- updateHex();
-
- } else if (doc == redField.getDocument()) {
- red = bounded(red, redField, 255);
- updateHSB();
- updateHex();
-
- } else if (doc == greenField.getDocument()) {
- green = bounded(green, greenField, 255);
- updateHSB();
- updateHex();
-
- } else if (doc == blueField.getDocument()) {
- blue = bounded(blue, blueField, 255);
- updateHSB();
- updateHex();
-
- } else if (doc == hexField.getDocument()) {
- String str = hexField.getText();
- if (str.startsWith("#")) {
- str = str.substring(1);
- }
- while (str.length() < 6) {
- str += "0";
- }
- if (str.length() > 6) {
- str = str.substring(0, 6);
- }
- updateRGB2(Integer.parseInt(str, 16));
- updateHSB();
- }
- range.redraw();
- slider.redraw();
- colorPanel.repaint();
- updating = false;
- }
-
-
- /**
- * Set the RGB values based on the current HSB values.
- */
- protected void updateRGB() {
- int rgb = Color.HSBtoRGB(hue / 359f,
- saturation / 99f,
- brightness / 99f);
- updateRGB2(rgb);
- }
-
-
- /**
- * Set the RGB values based on a calculated ARGB int.
- * Used by both updateRGB() to set the color from the HSB values,
- * and by updateHex(), to unpack the hex colors and assign them.
- */
- protected void updateRGB2(int rgb) {
- red = (rgb >> 16) & 0xff;
- green = (rgb >> 8) & 0xff;
- blue = rgb & 0xff;
-
- redField.setText(String.valueOf(red));
- greenField.setText(String.valueOf(green));
- blueField.setText(String.valueOf(blue));
- }
-
-
- /**
- * Set the HSB values based on the current RGB values.
- */
- protected void updateHSB() {
- float hsb[] = new float[3];
- Color.RGBtoHSB(red, green, blue, hsb);
-
- hue = (int) (hsb[0] * 359.0f);
- saturation = (int) (hsb[1] * 99.0f);
- brightness = (int) (hsb[2] * 99.0f);
-
- hueField.setText(String.valueOf(hue));
- saturationField.setText(String.valueOf(saturation));
- brightnessField.setText(String.valueOf(brightness));
- }
-
-
- protected void updateHex() {
- hexField.setText("#" +
- PApplet.hex(red, 2) +
- PApplet.hex(green, 2) +
- PApplet.hex(blue, 2));
- }
-
-
- /**
- * Get the bounded value for a specific range. If the value is outside
- * the max, you can't edit right away, so just act as if it's already
- * been bounded and return the bounded value, then fire an event to set
- * it to the value that was just returned.
- */
- protected int bounded(int current, final JTextField field, final int max) {
- String text = field.getText();
- if (text.length() == 0) {
- return 0;
- }
- try {
- int value = Integer.parseInt(text);
- if (value > max) {
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- field.setText(String.valueOf(max));
- }
- });
- return max;
- }
- return value;
-
- } catch (NumberFormatException e) {
- return current; // should not be reachable
- }
- }
-
-
- protected Container createColorFields() {
- Box box = Box.createVerticalBox();
- box.setAlignmentY(0);
-
- colorPanel = new JPanel() {
- public void paintComponent(Graphics g) {
- g.setColor(new Color(red, green, blue));
- Dimension size = getSize();
- g.fillRect(0, 0, size.width, size.height);
- }
- };
- colorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
- Dimension dim = new Dimension(60, 40);
- colorPanel.setMinimumSize(dim);
- //colorPanel.setMaximumSize(dim);
- //colorPanel.setPreferredSize(dim);
- box.add(colorPanel);
- box.add(Box.createVerticalStrut(10));
-
- Box row;
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("H"));
- row.add(hueField = new NumberField(4, false));
- row.add(new JLabel(" \u00B0")); // degree symbol
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(5));
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("S"));
- row.add(saturationField = new NumberField(4, false));
- row.add(new JLabel(" %"));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(5));
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("B"));
- row.add(brightnessField = new NumberField(4, false));
- row.add(new JLabel(" %"));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(10));
-
- //
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("R"));
- row.add(redField = new NumberField(4, false));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(5));
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("G"));
- row.add(greenField = new NumberField(4, false));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(5));
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel("B"));
- row.add(blueField = new NumberField(4, false));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(10));
-
- //
-
- row = Box.createHorizontalBox();
- row.add(createFixedLabel(""));
- row.add(hexField = new NumberField(5, true));
- row.add(Box.createHorizontalGlue());
- box.add(row);
- box.add(Box.createVerticalStrut(10));
-
- box.add(Box.createVerticalGlue());
- return box;
- }
-
-
- int labelH;
-
- /**
- * return a label of a fixed width
- */
- protected JLabel createFixedLabel(String title) {
- JLabel label = new JLabel(title);
- if (labelH == 0) {
- labelH = label.getPreferredSize().height;
- }
- Dimension dim = new Dimension(20, labelH);
- label.setPreferredSize(dim);
- label.setMinimumSize(dim);
- label.setMaximumSize(dim);
- return label;
- }
-
-
- public class ColorRange extends PApplet {
-
- static final int WIDE = 256;
- static final int HIGH = 256;
-
- int lastX, lastY;
-
-
- public void setup() {
- size(WIDE, HIGH); //, P3D);
- noLoop();
-
- colorMode(HSB, 360, 256, 256);
- noFill();
- rectMode(CENTER);
-
- loadPixels();
- }
-
- public void draw() {
-// if ((g == null) || (g.pixels == null)) return;
- if ((width != WIDE) || (height < HIGH)) {
- //System.out.println("bad size " + width + " " + height);
- return;
- }
-
- int index = 0;
- for (int j = 0; j < 256; j++) {
- for (int i = 0; i < 256; i++) {
- pixels[index++] = color(hue, i, 255 - j);
- }
- }
-
- updatePixels();
- stroke((brightness > 50) ? 0 : 255);
- rect(lastX, lastY, 9, 9);
- }
-
- public void mousePressed() {
- updateMouse();
- }
-
- public void mouseDragged() {
- updateMouse();
- }
-
- public void updateMouse() {
- if ((mouseX >= 0) && (mouseX < 256) &&
- (mouseY >= 0) && (mouseY < 256)) {
- int nsaturation = (int) (100 * (mouseX / 255.0f));
- int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f)));
- saturationField.setText(String.valueOf(nsaturation));
- brightnessField.setText(String.valueOf(nbrightness));
-
- lastX = mouseX;
- lastY = mouseY;
- }
- }
-
- public Dimension getPreferredSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public Dimension getMinimumSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public Dimension getMaximumSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public void keyPressed() {
- if (key == ESC) {
- ColorSelector.frame.setVisible(false);
- // don't quit out of processing
- // http://dev.processing.org/bugs/show_bug.cgi?id=1006
- key = 0;
- }
- }
- }
-
-
- public class ColorSlider extends PApplet {
-
- static final int WIDE = 20;
- static final int HIGH = 256;
-
- public void setup() {
- size(WIDE, HIGH); //, P3D);
- colorMode(HSB, 255, 100, 100);
- noLoop();
- loadPixels();
- }
-
- public void draw() {
-// if ((g == null) || (g.pixels == null)) return;
- if ((width != WIDE) || (height < HIGH)) {
- //System.out.println("bad size " + width + " " + height);
- return;
- }
-
- int index = 0;
- int sel = 255 - (int) (255 * (hue / 359f));
- for (int j = 0; j < 256; j++) {
- int c = color(255 - j, 100, 100);
- if (j == sel) c = 0xFF000000;
- for (int i = 0; i < WIDE; i++) {
- g.pixels[index++] = c;
- }
- }
- updatePixels();
- }
-
- public void mousePressed() {
- updateMouse();
- }
-
- public void mouseDragged() {
- updateMouse();
- }
-
- public void updateMouse() {
- if ((mouseX >= 0) && (mouseX < 256) &&
- (mouseY >= 0) && (mouseY < 256)) {
- int nhue = 359 - (int) (359 * (mouseY / 255.0f));
- hueField.setText(String.valueOf(nhue));
- }
- }
-
- public Dimension getPreferredSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public Dimension getMinimumSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public Dimension getMaximumSize() {
- return new Dimension(WIDE, HIGH);
- }
-
- public void keyPressed() {
- if (key == ESC) {
- ColorSelector.frame.setVisible(false);
- // don't quit out of processing
- // http://dev.processing.org/bugs/show_bug.cgi?id=1006
- key = 0;
- }
- }
- }
-
-
- /**
- * Extension of JTextField that only allows numbers
- */
- class NumberField extends JTextField {
-
- public boolean allowHex;
-
- public NumberField(int cols, boolean allowHex) {
- super(cols);
- this.allowHex = allowHex;
- }
-
- protected Document createDefaultModel() {
- return new NumberDocument(this);
- }
-
- public Dimension getPreferredSize() {
- if (!allowHex) {
- return new Dimension(45, super.getPreferredSize().height);
- }
- return super.getPreferredSize();
- }
-
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
-
- public Dimension getMaximumSize() {
- return getPreferredSize();
- }
- }
-
-
- /**
- * Document model to go with JTextField that only allows numbers.
- */
- class NumberDocument extends PlainDocument {
-
- NumberField parentField;
-
- public NumberDocument(NumberField parentField) {
- this.parentField = parentField;
- //System.out.println("setting parent to " + parentSelector);
- }
-
- public void insertString(int offs, String str, AttributeSet a)
- throws BadLocationException {
-
- if (str == null) return;
-
- char chars[] = str.toCharArray();
- int charCount = 0;
- // remove any non-digit chars
- for (int i = 0; i < chars.length; i++) {
- boolean ok = Character.isDigit(chars[i]);
- if (parentField.allowHex) {
- if ((chars[i] >= 'A') && (chars[i] <= 'F')) ok = true;
- if ((chars[i] >= 'a') && (chars[i] <= 'f')) ok = true;
- if ((offs == 0) && (i == 0) && (chars[i] == '#')) ok = true;
- }
- if (ok) {
- if (charCount != i) { // shift if necessary
- chars[charCount] = chars[i];
- }
- charCount++;
- }
- }
- super.insertString(offs, new String(chars, 0, charCount), a);
- // can't call any sort of methods on the enclosing class here
- // seems to have something to do with how Document objects are set up
- }
- }
-
-
-// static public void main(String[] args) {
-// ColorSelector cs = new ColorSelector();
-// cs.init(null);
-// EventQueue.invokeLater(cs);
-// }
}
diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java
index d3de7bd2c..d119e76d3 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 d3eb69e4e..1967c4e30 100644
--- a/app/src/processing/app/tools/InstallCommander.java
+++ b/app/src/processing/app/tools/InstallCommander.java
@@ -81,30 +81,29 @@ 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() +
+ " -Djna.nosys=true" +
+ " -cp \"" + classPath + "\"" +
" processing.mode.java.Commander \"$@\"");
writer.flush();
writer.close();
diff --git a/app/src/processing/mode/java/AutoFormat.java b/app/src/processing/mode/java/AutoFormat.java
index f7a86a0bf..91d8a7cec 100644
--- a/app/src/processing/mode/java/AutoFormat.java
+++ b/app/src/processing/mode/java/AutoFormat.java
@@ -38,56 +38,62 @@ import processing.core.PApplet;
*
* After some further digging, this code in fact appears to be a modified
* version of Jason Pell's GPLed "Java Beautifier" class found
- * here.
- * Which is itself based on code from Van Di-Han Ho from
- * here.
+ * here,
+ * which is itself based on code from Van Di-Han Ho from
+ * here.
* [Ben Fry, August 2009]
*/
public class AutoFormat implements Formatter {
private char[] chars;
private final StringBuilder buf = new StringBuilder();
-
private final StringBuilder result = new StringBuilder();
private int indentValue;
private boolean EOF;
- private boolean a_flg, e_flg, if_flg, s_flag, q_flg;
- private boolean s_if_flg[];
+ private boolean a_flg, if_flg, s_flag, elseFlag;
+
+ /** Number of ? entered without exiting at : of a?b:c structures. */
+ private int conditionalLevel;
+
private int pos;
-// private int lineNumber;
- private int s_level[];
private int c_level;
- private int sp_flg[][];
- private int s_ind[][];
- private int s_if_lev[];
- private int if_lev, level;
- private int ind[];
- private int paren;
- private int p_flg[];
+ private int[][] sp_flg;
+ private int[][] s_ind;
+ private int if_lev;
+
+ /** Number of curly brackets entered and not exited. */
+ private int level;
+
+ /** Number of parentheses entered and not exited. */
+ private int parenLevel;
+
+ private int[] ind;
+ private int[] p_flg;
private char l_char;
- private int ct;
- private int s_tabs[][];
+ private int[][] s_tabs;
private boolean jdoc_flag;
private char cc;
private int tabs;
private char c;
+ private char lastNonWhitespace = 0;
private final Stack castFlags = new Stack();
- private void comment() {
- final boolean save_s_flg = s_flag;
+ private void handleMultiLineComment() {
+ final boolean saved_s_flag = s_flag;
- buf.append(c = next()); // extra char
+ char ch;
+ buf.append(ch = nextChar()); // extra char
while (true) {
- buf.append(c = next());
- while ((c != '/')) {
- if (c == '\n') {
-// lineNumber++;
+ buf.append(ch = nextChar());
+ while (ch != '/') {
+ if (ch == '\n') {
+// lineNumber++;
writeIndentedComment();
s_flag = true;
}
- buf.append(c = next());
+ buf.append(ch = nextChar());
}
if (buf.length() >= 2 && buf.charAt(buf.length() - 2) == '*') {
jdoc_flag = false;
@@ -96,50 +102,65 @@ public class AutoFormat implements Formatter {
}
writeIndentedComment();
- s_flag = save_s_flg;
+ s_flag = saved_s_flag;
jdoc_flag = false;
return;
}
-
- private char get_string() {
- char ch;
- while (true) {
- buf.append(ch = next());
- if (ch == '\\') {
- buf.append(next());
- continue;
- }
- if (ch == '\'' || ch == '"') {
- buf.append(cc = next());
- while (!EOF && cc != ch) {
- if (cc == '\\') {
- buf.append(next());
- }
- buf.append(cc = next());
- }
- continue;
- }
- if (ch == '\n') {
- writeIndentedLine();
- a_flg = true;
- continue;
- }
- return ch;
+
+ private void handleSingleLineComment() {
+ char ch = nextChar();
+ while (ch != '\n') {
+ buf.append(ch);
+ ch = nextChar();
}
+// lineNumber++;
+ writeIndentedLine();
+ s_flag = true;
}
+
+// /**
+// * Transfers buf to result until a character is reached that
+// * is neither \, \n, or in a string. \n is not written, but
+// * writeIndentedLine is called on finding it.
+// * @return The first character not listed above.
+// */
+// private char get_string() {
+// char ch1, ch2;
+// while (true) {
+// buf.append(ch1 = nextChar());
+// if (ch1 == '\\') {
+// buf.append(nextChar());
+// } else if (ch1 == '\'' || ch1 == '\"') {
+// buf.append(ch2 = nextChar());
+// while (!EOF && ch2 != ch1) {
+// if (ch2 == '\\') {
+// // Next char is escaped, ignore.
+// buf.append(nextChar());
+// }
+// buf.append(ch2 = nextChar());
+// }
+// } else if (ch1 == '\n') {
+// writeIndentedLine();
+// a_flg = true;
+// } else {
+// return ch1;
+// }
+// }
+// }
+
private void writeIndentedLine() {
if (buf.length() == 0) {
if (s_flag) {
- s_flag = a_flg = false;
+ s_flag = a_flg = elseFlag = false;
}
return;
}
if (s_flag) {
- final boolean shouldIndent = (tabs > 0) && (buf.charAt(0) != '{')
- && a_flg;
+ final boolean shouldIndent =
+ (tabs > 0) && (buf.charAt(0) != '{') && a_flg;
if (shouldIndent) {
tabs++;
}
@@ -150,9 +171,25 @@ public class AutoFormat implements Formatter {
}
a_flg = false;
}
+ if (elseFlag) {
+ if (lastNonSpaceChar() == '}') {
+ trimRight(result);
+ result.append(' ');
+ }
+ elseFlag = false;
+ }
result.append(buf);
buf.setLength(0);
}
+
+
+ private char lastNonSpaceChar() {
+ for (int i = result.length() - 1; i >= 0; i--) {
+ char c_i = result.charAt(i);
+ if (c_i != ' ' && c_i != '\n') return c_i;
+ }
+ return 0;
+ }
private void writeIndentedComment() {
@@ -170,7 +207,7 @@ public class AutoFormat implements Formatter {
jdoc_flag = true;
}
if (buf.charAt(i) == '/' && buf.charAt(i + 1) == '*') {
- if (saved_s_flag && prev() != ';') {
+ if (saved_s_flag && getLastNonWhitespace() != ';') {
result.append(buf.substring(i));
} else {
result.append(buf);
@@ -187,18 +224,6 @@ public class AutoFormat implements Formatter {
}
- private void handleSingleLineComment() {
- c = next();
- while (c != '\n') {
- buf.append(c);
- c = next();
- }
-// lineNumber++;
- writeIndentedLine();
- s_flag = true;
- }
-
-
private void printIndentation() {
if (tabs < 0) {
tabs = 0;
@@ -208,7 +233,7 @@ public class AutoFormat implements Formatter {
}
final int spaces = tabs * indentValue;
for (int k = 0; k < spaces; k++) {
- result.append(" ");
+ result.append(' ');
}
}
@@ -221,10 +246,7 @@ public class AutoFormat implements Formatter {
}
- private char lastNonWhitespace = 0;
-
-
- private int prev() {
+ private int getLastNonWhitespace() {
return lastNonWhitespace;
}
@@ -239,33 +261,32 @@ public class AutoFormat implements Formatter {
if (pos == chars.length - 1) {
EOF = true;
} else {
- pos--; // reset for next()
+ pos--; // reset for nextChar()
}
}
- private char next() {
+ private char nextChar() {
if (EOF) {
- return 0;
+ return '\0';
}
pos++;
- final char c;
+ char retVal;
if (pos < chars.length) {
- c = chars[pos];
- if (!Character.isWhitespace(c))
- lastNonWhitespace = c;
+ retVal = chars[pos];
+ if (!Character.isWhitespace(retVal))
+ lastNonWhitespace = retVal;
} else {
- c = 0;
+ retVal = '\0';
}
- if (pos == chars.length - 1) {
+ if (pos == chars.length-1) {
EOF = true;
}
- return c;
+ return retVal;
}
- /* else processing */
- private void gotelse() {
+ private void gotElse() {
tabs = s_tabs[c_level][if_lev];
p_flg[level] = sp_flg[c_level][if_lev];
ind[level] = s_ind[c_level][if_lev];
@@ -273,23 +294,22 @@ public class AutoFormat implements Formatter {
}
- /* read to new_line */
- private boolean getnl() {
+ private boolean readUntilNewLine() {
final int savedTabs = tabs;
char c = peek();
while (!EOF && (c == '\t' || c == ' ')) {
- buf.append(next());
+ buf.append(nextChar());
c = peek();
}
if (c == '/') {
- buf.append(next());
+ buf.append(nextChar());
c = peek();
if (c == '*') {
- buf.append(next());
- comment();
+ buf.append(nextChar());
+ handleMultiLineComment();
} else if (c == '/') {
- buf.append(next());
+ buf.append(nextChar());
handleSingleLineComment();
return true;
}
@@ -298,7 +318,7 @@ public class AutoFormat implements Formatter {
c = peek();
if (c == '\n') {
// eat it
- next();
+ nextChar();
// lineNumber++;
tabs = savedTabs;
return true;
@@ -327,24 +347,25 @@ public class AutoFormat implements Formatter {
public String format(final String source) {
final String normalizedText = source.replaceAll("\r", "");
- final String cleanText = normalizedText
- + (normalizedText.endsWith("\n") ? "" : "\n");
+ final String cleanText =
+ normalizedText + (normalizedText.endsWith("\n") ? "" : "\n");
result.setLength(0);
indentValue = Preferences.getInteger("editor.tabs.size");
-// lineNumber = 0;
- q_flg = e_flg = a_flg = if_flg = false;
+// lineNumber = 0;
+ boolean forFlag = a_flg = if_flg = false;
s_flag = true;
- c_level = if_lev = level = paren = 0;
+ int forParenthLevel = 0;
+ conditionalLevel = parenLevel = c_level = if_lev = level = 0;
tabs = 0;
jdoc_flag = false;
- s_level = new int[10];
+ int[] s_level = new int[10];
sp_flg = new int[20][10];
s_ind = new int[20][10];
- s_if_lev = new int[10];
- s_if_flg = new boolean[10];
+ int[] s_if_lev = new int[10];
+ boolean[] s_if_flg = new boolean[10];
ind = new int[10];
p_flg = new int[10];
s_tabs = new int[20][10];
@@ -352,10 +373,10 @@ public class AutoFormat implements Formatter {
chars = cleanText.toCharArray();
// lineNumber = 1;
- EOF = false; // set in next() when EOF
+ EOF = false; // set in nextChar() when EOF
while (!EOF) {
- c = next();
+ c = nextChar();
switch (c) {
default:
buf.append(c);
@@ -371,15 +392,12 @@ public class AutoFormat implements Formatter {
case ' ':
case '\t':
- if (lookup("else")) {
- gotelse();
+ elseFlag = lookup("else");
+ if (elseFlag) {
+ gotElse();
if ((!s_flag) || buf.length() > 0) {
buf.append(c);
}
-// // issue https://github.com/processing/processing/issues/364
-// s_flag = false;
-// trimRight(result);
-// result.append(" ");
writeIndentedLine();
s_flag = false;
@@ -395,9 +413,9 @@ public class AutoFormat implements Formatter {
if (EOF) {
break;
}
- e_flg = lookup("else");
- if (e_flg) {
- gotelse();
+ elseFlag = lookup("else");
+ if (elseFlag) {
+ gotElse();
}
if (lookup_com("//")) {
final char lastChar = buf.charAt(buf.length() - 1);
@@ -409,18 +427,18 @@ public class AutoFormat implements Formatter {
writeIndentedLine();
result.append("\n");
s_flag = true;
- if (e_flg) {
+ if (elseFlag) {
p_flg[level]++;
tabs++;
- } else if (prev() == l_char) {
+ } else if (getLastNonWhitespace() == l_char) {
a_flg = true;
}
break;
case '{':
- if (lookup("else")) {
- gotelse();
- }
+ elseFlag = lookup("else");
+ if (elseFlag) gotElse();
+
if (s_if_lev.length == c_level) {
s_if_lev = PApplet.expand(s_if_lev);
s_if_flg = PApplet.expand(s_if_flg);
@@ -440,9 +458,9 @@ public class AutoFormat implements Formatter {
buf.append(" ");
buf.append(c);
writeIndentedLine();
- getnl();
+ readUntilNewLine();
writeIndentedLine();
- //fprintf(outfil,"\n");
+
result.append("\n");
tabs++;
s_flag = true;
@@ -475,11 +493,12 @@ public class AutoFormat implements Formatter {
printIndentation();
result.append(c);
if (peek() == ';') {
- result.append(next());
+ result.append(nextChar());
}
- getnl();
+
+ readUntilNewLine();
writeIndentedLine();
- result.append("\n");
+ result.append('\n');
s_flag = true;
if (c_level < s_level[level]) {
if (level > 0) {
@@ -497,21 +516,21 @@ public class AutoFormat implements Formatter {
case '"':
case '\'':
buf.append(c);
- cc = next();
+ cc = nextChar();
while (!EOF && cc != c) {
buf.append(cc);
if (cc == '\\') {
- buf.append(cc = next());
+ buf.append(cc = nextChar());
}
if (cc == '\n') {
// lineNumber++;
writeIndentedLine();
s_flag = true;
}
- cc = next();
+ cc = nextChar();
}
buf.append(cc);
- if (getnl()) {
+ if (readUntilNewLine()) {
l_char = cc;
// push a newline into the stream
chars[pos--] = '\n';
@@ -519,13 +538,21 @@ public class AutoFormat implements Formatter {
break;
case ';':
+ if (forFlag) {
+ // This is like a comma.
+ trimRight(buf);
+ buf.append("; ");
+ // Not non-whitespace: allow \n.
+ advanceToNonSpace();
+ break;
+ }
buf.append(c);
writeIndentedLine();
if (p_flg[level] > 0 && ind[level] == 0) {
tabs -= p_flg[level];
p_flg[level] = 0;
}
- getnl();
+ readUntilNewLine();
writeIndentedLine();
result.append("\n");
s_flag = true;
@@ -541,26 +568,39 @@ public class AutoFormat implements Formatter {
case '\\':
buf.append(c);
- buf.append(next());
+ buf.append(nextChar());
break;
case '?':
- q_flg = true;
+ conditionalLevel++;
buf.append(c);
break;
case ':':
- buf.append(c);
+ // Java 8 :: operator.
if (peek() == ':') {
writeIndentedLine();
- result.append(next());
+ result.append(c).append(nextChar());
break;
}
- if (q_flg) {
- q_flg = false;
+ // End a?b:c structures.
+ else if (conditionalLevel>0) {
+ conditionalLevel--;
+ buf.append(c);
break;
}
+
+ else if (forFlag) {
+ trimRight(buf);
+ buf.append(" : ");
+ // Not to non-whitespace: allow \n.
+ advanceToNonSpace();
+ break;
+ }
+
+ buf.append(c);
+
if (!lookup("default") && !lookup("case")) {
s_flag = false;
writeIndentedLine();
@@ -570,26 +610,27 @@ public class AutoFormat implements Formatter {
tabs++;
}
if (peek() == ';') {
- result.append(next());
+ result.append(nextChar());
}
- getnl();
+ readUntilNewLine();
writeIndentedLine();
- result.append("\n");
+ result.append('\n');
s_flag = true;
break;
case '/':
- final char la = peek();
- if (la == '/') {
- buf.append(c).append(next());
+ final char next = peek();
+ if (next == '/') {
+ // call nextChar to move on.
+ buf.append(c).append(nextChar());
handleSingleLineComment();
result.append("\n");
- } else if (la == '*') {
+ } else if (next == '*') {
if (buf.length() > 0) {
writeIndentedLine();
}
- buf.append(c).append(next());
- comment();
+ buf.append(c).append(nextChar());
+ handleMultiLineComment();
} else {
buf.append(c);
}
@@ -599,15 +640,23 @@ public class AutoFormat implements Formatter {
final boolean isCast = castFlags.isEmpty() ? false : castFlags.pop();
- paren--;
- if (paren < 0) {
- paren = 0;
+ parenLevel--;
+
+ // If we're further back than the start of a for loop, we've
+ // left it.
+ if (forFlag && forParenthLevel > parenLevel) {
+ forFlag = false;
}
+
+ if (parenLevel < 0) {
+ parenLevel = 0;
+ }
+
buf.append(c);
writeIndentedLine();
- if (getnl()) {
+ if (readUntilNewLine()) {
chars[pos--] = '\n';
- if (paren != 0) {
+ if (parenLevel != 0) {
a_flg = true;
} else if (tabs > 0 && !isCast) {
p_flg[level]++;
@@ -630,42 +679,16 @@ public class AutoFormat implements Formatter {
}
buf.append(c);
- paren++;
+ parenLevel++;
+ // isFor says "is it the start of a for?". If it is, we set forFlag and
+ // forParenthLevel. If it is not parenth_lvl was incremented above and
+ // that's it.
if (isFor) {
- // TODO(feinberg): handle new-style for loops
- c = get_string();
- while (c != ';' && c != ':') {
- c = get_string();
+ if (!forFlag) {
+ forParenthLevel = parenLevel;
+ forFlag = true;
}
- ct = 0;
- int for_done = 0;
- while (for_done == 0) {
- c = get_string();
- while (c != ')') {
- if (c == '(') {
- ct++;
- }
- c = get_string();
- }
- if (ct != 0) {
- ct--;
- } else {
- for_done = 1;
- }
- } // endwhile for_done
- paren--;
- if (paren < 0) {
- paren = 0;
- }
- writeIndentedLine();
- if (getnl()) {
- chars[pos--] = '\n';
- p_flg[level]++;
- tabs++;
- ind[level] = 0;
- }
- break;
} else if (isIf) {
writeIndentedLine();
s_tabs[c_level][if_lev] = tabs;
diff --git a/app/src/processing/mode/java/Commander.java b/app/src/processing/mode/java/Commander.java
index fdf55848a..43a327632 100644
--- a/app/src/processing/mode/java/Commander.java
+++ b/app/src/processing/mode/java/Commander.java
@@ -48,6 +48,7 @@ public class Commander implements RunnerListener {
static final String forceArg = "--force";
static final String outputArg = "--output=";
static final String exportApplicationArg = "--export";
+ static final String noJavaArg = "--no-java";
static final String platformArg = "--platform=";
static final String bitsArg = "--bits=";
// static final String preferencesArg = "--preferences=";
@@ -61,38 +62,19 @@ public class Commander implements RunnerListener {
static final int EXPORT = 4;
Sketch sketch;
-
+
PrintStream systemOut;
PrintStream systemErr;
static public void main(String[] args) {
- /*
- if (args == null || args.length == 0) {
-// System.out.println(System.getProperty("user.dir"));
- args = new String[] {
- "--export",
-// "--build",
-// "--run",
-// "--present",
- "--force",
-// "--platform=windows",
- "--platform=macosx",
- "--bits=64",
- "--sketch=/Users/fry/coconut/processing/java/examples/Basics/Lights/Directional",
-// "--sketch=/Users/fry/coconut/sketchbook/sketchbook_libraries_test",
- "--output=/Users/fry/Desktop/test-build"
- };
- }
- */
-
// Do this early so that error messages go to the console
Base.setCommandLine();
// init the platform so that prefs and other native code is ready to go
Base.initPlatform();
// make sure a full JDK is installed
Base.initRequirements();
-
+
// launch command line handler
new Commander(args);
}
@@ -107,20 +89,25 @@ public class Commander implements RunnerListener {
boolean force = false; // replace that no good output folder
// String preferencesPath = null;
int platform = PApplet.platform; // default to this platform
- int platformBits = 0;
+// int platformBits = 0;
+ int platformBits = Base.getNativeBits();
int task = HELP;
+ boolean embedJava = true;
// Turns out the output goes as MacRoman or something else useless.
// http://code.google.com/p/processing/issues/detail?id=1418
try {
systemOut = new PrintStream(System.out, true, "UTF-8");
systemErr = new PrintStream(System.err, true, "UTF-8");
-
+
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.exit(1);
}
-
+
+// File preferencesFile = Base.getSettingsFile("preferences.txt");
+// System.out.println("Preferences file at " + preferencesFile.getAbsolutePath());
+
for (String arg : args) {
if (arg.length() == 0) {
// ignore it, just the crappy shell script
@@ -146,23 +133,28 @@ public class Commander implements RunnerListener {
} else if (arg.equals(exportApplicationArg)) {
task = EXPORT;
+ } else if (arg.equals(noJavaArg)) {
+ embedJava = false;
+
} else if (arg.startsWith(platformArg)) {
- String platformStr = arg.substring(platformArg.length());
- platform = Base.getPlatformIndex(platformStr);
- if (platform == -1) {
- complainAndQuit(platformStr + " should instead be " +
- "'windows', 'macosx', or 'linux'.", true);
- }
+ complainAndQuit("The --platform option has been removed from Processing 2.1.", false);
+// String platformStr = arg.substring(platformArg.length());
+// platform = Base.getPlatformIndex(platformStr);
+// if (platform == -1) {
+// complainAndQuit(platformStr + " should instead be " +
+// "'windows', 'macosx', or 'linux'.", true);
+// }
} else if (arg.startsWith(bitsArg)) {
- String bitsStr = arg.substring(bitsArg.length());
- if (bitsStr.equals("32")) {
- platformBits = 32;
- } else if (bitsStr.equals("64")) {
- platformBits = 64;
- } else {
- complainAndQuit("Bits should be either 32 or 64, not " + bitsStr, true);
- }
+ complainAndQuit("The --bits option has been removed from Processing 2.1.", false);
+// String bitsStr = arg.substring(bitsArg.length());
+// if (bitsStr.equals("32")) {
+// platformBits = 32;
+// } else if (bitsStr.equals("64")) {
+// platformBits = 64;
+// } else {
+// complainAndQuit("Bits should be either 32 or 64, not " + bitsStr, true);
+// }
} else if (arg.startsWith(sketchArg)) {
sketchPath = arg.substring(sketchArg.length());
@@ -212,7 +204,7 @@ public class Commander implements RunnerListener {
Base.removeDir(outputFolder);
} else {
complainAndQuit("The output folder already exists. " +
- "Use --force to remove it.", false);
+ "Use --force to remove it.", false);
}
}
@@ -273,11 +265,11 @@ public class Commander implements RunnerListener {
// if (platformBits == 0) {
// platformBits = Base.getNativeBits();
// }
- if (platformBits == 0 &&
- Library.hasMultipleArch(platform, build.getImportedLibraries())) {
- complainAndQuit("This sketch can be exported for 32- or 64-bit, please specify one.", true);
- }
- success = build.exportApplication(outputFolder, platform, platformBits);
+// if (platformBits == 0 &&
+// Library.hasMultipleArch(platform, build.getImportedLibraries())) {
+// complainAndQuit("This sketch can be exported for 32- or 64-bit, please specify one.", true);
+// }
+ success = build.exportApplication(outputFolder, platform, platformBits, embedJava);
}
}
}
@@ -289,6 +281,7 @@ public class Commander implements RunnerListener {
} catch (SketchException re) {
statusError(re);
+ System.exit(1);
} catch (IOException e) {
e.printStackTrace();
@@ -316,15 +309,18 @@ public class Commander implements RunnerListener {
if (codeIndex != -1) {
// format the runner exception like emacs
//blah.java:2:10:2:13: Syntax Error: This is a big error message
+ // Emacs doesn't like the double line thing coming from Java
+ // https://github.com/processing/processing/issues/2158
String filename = sketch.getCode(codeIndex).getFileName();
int line = re.getCodeLine() + 1;
int column = re.getCodeColumn() + 1;
//if (column == -1) column = 0;
// TODO if column not specified, should just select the whole line.
+ // But what's the correct syntax for that?
systemErr.println(filename + ":" +
line + ":" + column + ":" +
line + ":" + column + ":" + " " + re.getMessage());
-
+
} else { // no line number, pass the trace along to the user
exception.printStackTrace();
}
@@ -363,11 +359,12 @@ public class Commander implements RunnerListener {
out.println("--present Preprocess, compile, and run a sketch full screen.");
out.println();
out.println("--export Export an application.");
- out.println("--platform Specify the platform (export to application only).");
- out.println(" Should be one of 'windows', 'macosx', or 'linux'.");
- out.println("--bits Must be specified if libraries are used that are");
- out.println(" 32- or 64-bit specific such as the OpenGL library.");
- out.println(" Otherwise specify 0 or leave it out.");
+ out.println("--no-java Do not embed Java. Use at your own risk!");
+// out.println("--platform Specify the platform (export to application only).");
+// out.println(" Should be one of 'windows', 'macosx', or 'linux'.");
+// out.println("--bits Must be specified if libraries are used that are");
+// out.println(" 32- or 64-bit specific such as the OpenGL library.");
+// out.println(" Otherwise specify 0 or leave it out.");
out.println();
}
@@ -391,4 +388,4 @@ public class Commander implements RunnerListener {
public boolean isHalted() {
return false;
}
-}
\ No newline at end of file
+}
diff --git a/app/src/processing/mode/java/JavaBuild.java b/app/src/processing/mode/java/JavaBuild.java
index 43112e227..46c18816d 100644
--- a/app/src/processing/mode/java/JavaBuild.java
+++ b/app/src/processing/mode/java/JavaBuild.java
@@ -26,8 +26,15 @@ import java.io.*;
import java.util.*;
import java.util.zip.*;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+
import processing.app.*;
+import processing.app.exec.ProcessHelper;
import processing.core.*;
+import processing.data.XML;
import processing.mode.java.preproc.*;
// Would you believe there's a java.lang.Compiler class? I wouldn't.
@@ -397,7 +404,7 @@ public class JavaBuild {
throw new SketchException(ex.toString());
}
- // grab the imports from the code just preproc'd
+ // grab the imports from the code just preprocessed
importedLibraries = new ArrayList();
Library core = mode.getCoreLibrary();
@@ -408,10 +415,21 @@ public class JavaBuild {
// System.out.println("extra imports: " + result.extraImports);
for (String item : result.extraImports) {
+// System.out.println("item = '" + item + "'");
// remove things up to the last dot
int dot = item.lastIndexOf('.');
// http://dev.processing.org/bugs/show_bug.cgi?id=1145
String entry = (dot == -1) ? item : item.substring(0, dot);
+// System.out.print(entry + " => ");
+
+ if (item.startsWith("static ")) {
+ // import static - https://github.com/processing/processing/issues/8
+ // Remove more stuff.
+ int dot2 = item.lastIndexOf('.');
+ entry = entry.substring(7, (dot2 == -1) ? entry.length() : dot2);
+// System.out.println(entry);
+ }
+
// System.out.println("library searching for " + entry);
Library library = mode.getLibrary(entry);
// System.out.println(" found " + library);
@@ -427,7 +445,7 @@ public class JavaBuild {
// If someone insists on unnecessarily repeating the code folder
// import, don't show an error for it.
if (codeFolderPackages != null) {
- String itemPkg = item.substring(0, item.lastIndexOf('.'));
+ String itemPkg = entry;
for (String pkg : codeFolderPackages) {
if (pkg.equals(itemPkg)) {
found = true;
@@ -435,7 +453,7 @@ public class JavaBuild {
}
}
}
- if (ignorableImport(item)) {
+ if (ignorableImport(entry + '.')) {
found = true;
}
if (!found) {
@@ -531,6 +549,8 @@ public class JavaBuild {
if (pkg.startsWith("processing.data.")) return true;
if (pkg.startsWith("processing.event.")) return true;
if (pkg.startsWith("processing.opengl.")) return true;
+
+// if (pkg.startsWith("com.jogamp.")) return true;
// // ignore core, data, and opengl packages
// String[] coreImports = preprocessor.getCoreImports();
@@ -1093,43 +1113,68 @@ public class JavaBuild {
File folder = null;
for (String platformName : PConstants.platformNames) {
int platform = Base.getPlatformIndex(platformName);
+
+ // Can only embed Java on the native platform
+ boolean embedJava = (platform == PApplet.platform) &&
+ Preferences.getBoolean("export.application.embed_java");
+
if (Preferences.getBoolean("export.application.platform." + platformName)) {
if (Library.hasMultipleArch(platform, importedLibraries)) {
// export the 32-bit version
folder = new File(sketch.getFolder(), "application." + platformName + "32");
- if (!exportApplication(folder, platform, 32)) {
+ if (!exportApplication(folder, platform, 32, embedJava && Base.getNativeBits() == 32)) {
return false;
}
// export the 64-bit version
folder = new File(sketch.getFolder(), "application." + platformName + "64");
- if (!exportApplication(folder, platform, 64)) {
+ if (!exportApplication(folder, platform, 64, embedJava && Base.getNativeBits() == 64)) {
return false;
}
} else { // just make a single one for this platform
folder = new File(sketch.getFolder(), "application." + platformName);
- if (!exportApplication(folder, platform, 0)) {
+ if (!exportApplication(folder, platform, 0, embedJava)) {
return false;
}
}
}
}
+
+ /*
+ File folder = null;
+ String platformName = Base.getPlatformName();
+ boolean embedJava = Preferences.getBoolean("export.application.embed_java");
+ if (Library.hasMultipleArch(PApplet.platform, importedLibraries)) {
+ if (Base.getNativeBits() == 32) {
+ // export the 32-bit version
+ folder = new File(sketch.getFolder(), "application." + platformName + "32");
+ if (!exportApplication(folder, PApplet.platform, 32, embedJava)) {
+ return false;
+ }
+ } else if (Base.getNativeBits() == 64) {
+ // export the 64-bit version
+ folder = new File(sketch.getFolder(), "application." + platformName + "64");
+ if (!exportApplication(folder, PApplet.platform, 64, embedJava)) {
+ return false;
+ }
+ }
+ } else { // just make a single one for this platform
+ folder = new File(sketch.getFolder(), "application." + platformName);
+ if (!exportApplication(folder, PApplet.platform, 0, embedJava)) {
+ return false;
+ }
+ }
+ */
return true; // all good
}
-// public boolean exportApplication(String destPath,
-// String platformName,
-// int exportBits) throws IOException, RunnerException {
-// return exportApplication(destPath, Base.getPlatformIndex(platformName), exportBits);
-// }
-
-
/**
* Export to application without GUI. Also called by the Commander.
*/
protected boolean exportApplication(File destFolder,
int exportPlatform,
- int exportBits) throws IOException, SketchException {
+ int exportBits,
+ boolean embedJava) throws IOException, SketchException {
// TODO this should probably be a dialog box instead of a warning
// on the terminal. And the message should be written better than this.
// http://code.google.com/p/processing/issues/detail?id=884
@@ -1160,13 +1205,53 @@ public class JavaBuild {
/// on macosx, need to copy .app skeleton since that's
/// also where the jar files will be placed
File dotAppFolder = null;
+ String jvmRuntime = "";
+ String jdkPath = null;
if (exportPlatform == PConstants.MACOSX) {
dotAppFolder = new File(destFolder, sketch.getName() + ".app");
-// String APP_SKELETON = "skeleton.app";
- //File dotAppSkeleton = new File(folder, APP_SKELETON);
- File dotAppSkeleton = mode.getContentFile("application/template.app");
- Base.copyDir(dotAppSkeleton, dotAppFolder);
+ File contentsOrig = new File(Base.getJavaHome(), "../../../../..");
+
+ if (embedJava) {
+ File jdkFolder = new File(Base.getJavaHome(), "../../..");
+ String jdkFolderName = jdkFolder.getCanonicalFile().getName();
+ jvmRuntime = "JVMRuntime\n " + jdkFolderName + "";
+ jdkPath = new File(dotAppFolder, "Contents/PlugIns/" + jdkFolderName + ".jdk").getAbsolutePath();
+ }
+
+ File contentsFolder = new File(dotAppFolder, "Contents");
+ contentsFolder.mkdirs();
+
+ // Info.plist will be written later
+
+ // set the jar folder to a different location than windows/linux
+ //jarFolder = new File(dotAppFolder, "Contents/Resources/Java");
+ jarFolder = new File(contentsFolder, "Java");
+
+ File macosFolder = new File(contentsFolder, "MacOS");
+ macosFolder.mkdirs();
+ Base.copyFile(new File(contentsOrig, "MacOS/Processing"),
+ new File(contentsFolder, "MacOS/" + sketch.getName()));
+
+ File pkgInfo = new File(contentsFolder, "PkgInfo");
+ PrintWriter writer = PApplet.createWriter(pkgInfo);
+ writer.println("APPL????");
+ writer.flush();
+ writer.close();
+
+ // Use faster(?) native copy here (also to do sym links)
+ if (embedJava) {
+ Base.copyDirNative(new File(contentsOrig, "PlugIns"),
+ new File(contentsFolder, "PlugIns"));
+ }
+
+ File resourcesFolder = new File(contentsFolder, "Resources");
+ Base.copyDir(new File(contentsOrig, "Resources/en.lproj"),
+ new File(resourcesFolder, "en.lproj"));
+ Base.copyFile(mode.getContentFile("application/sketch.icns"),
+ new File(resourcesFolder, "sketch.icns"));
+
+ /*
String stubName = "Contents/MacOS/JavaApplicationStub";
// need to set the stub to executable
// will work on osx or *nix, but just dies on windows, oh well..
@@ -1189,17 +1274,25 @@ public class JavaBuild {
String stubPath = stubFile.getAbsolutePath();
Runtime.getRuntime().exec(new String[] { "chmod", "+x", stubPath });
}
-
- // set the jar folder to a different location than windows/linux
- jarFolder = new File(dotAppFolder, "Contents/Resources/Java");
+ */
+ } else if (exportPlatform == PConstants.LINUX) {
+ if (embedJava) {
+ Base.copyDirNative(Base.getJavaHome(), new File(destFolder, "java"));
+ }
+
+ } else if (exportPlatform == PConstants.WINDOWS) {
+ if (embedJava) {
+ Base.copyDir(Base.getJavaHome(), new File(destFolder, "java"));
+ }
}
- /// make the jar folder (windows and linux)
+ /// make the jar folder (all platforms)
if (!jarFolder.exists()) jarFolder.mkdirs();
+ /*
/// on windows, copy the exe file
if (exportPlatform == PConstants.WINDOWS) {
@@ -1208,7 +1301,8 @@ public class JavaBuild {
File batFile = new File(destFolder, sketch.getName() + ".bat");
PrintWriter writer = PApplet.createWriter(batFile);
writer.println("@echo off");
- writer.println("java -Djava.ext.dirs=lib -Djava.library.path=lib " + sketch.getName());
+ String javaPath = embedJava ? ".\\java\\bin\\java.exe" : "java";
+ writer.println(javaPath + " -Djna.nosys=true -Djava.ext.dirs=lib -Djava.library.path=lib " + sketch.getName());
writer.flush();
writer.close();
} else {
@@ -1216,8 +1310,9 @@ public class JavaBuild {
new File(destFolder, sketch.getName() + ".exe"));
}
}
+ */
-
+
/// start copying all jar files
Vector jarListVector = new Vector();
@@ -1271,7 +1366,6 @@ public class JavaBuild {
String includes = Base.contentsToClassPath(sketch.getCodeFolder());
// Use tokens to get rid of extra blanks, which causes huge exports
String[] codeList = PApplet.splitTokens(includes, File.pathSeparator);
-// String cp = "";
for (int i = 0; i < codeList.length; i++) {
if (codeList[i].toLowerCase().endsWith(".jar") ||
codeList[i].toLowerCase().endsWith(".zip")) {
@@ -1283,7 +1377,6 @@ public class JavaBuild {
// cp += codeList[i] + File.pathSeparator;
}
}
-// packClassPathIntoZipFile(cp, zos, zipFileContents); // this was double adding the code folder prior to 2.0a2
}
zos.flush();
@@ -1292,15 +1385,6 @@ public class JavaBuild {
jarListVector.add(sketch.getName() + ".jar");
-// /// add core.jar to the jar destination folder
-//
-// File bagelJar = Base.isMacOS() ?
-// Base.getContentFile("core.jar") :
-// Base.getContentFile("lib/core.jar");
-// Base.copyFile(bagelJar, new File(jarFolder, "core.jar"));
-// jarListVector.add("core.jar");
-
-
/// add contents of 'library' folders to the export
for (Library library : importedLibraries) {
// add each item from the library folder / export list to the output
@@ -1313,38 +1397,13 @@ public class JavaBuild {
"a big fat lie and does not exist.");
} else if (exportFile.isDirectory()) {
- //System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
-// if (exportPlatform == PConstants.MACOSX) {
-// // For OS X, copy subfolders to Contents/Resources/Java
Base.copyDir(exportFile, new File(jarFolder, exportName));
-// } else {
-// // For other platforms, just copy the folder to the same directory
-// // as the application.
-// Base.copyDir(exportFile, new File(destFolder, exportName));
-// }
} else if (exportName.toLowerCase().endsWith(".zip") ||
exportName.toLowerCase().endsWith(".jar")) {
Base.copyFile(exportFile, new File(jarFolder, exportName));
jarListVector.add(exportName);
- // old style, prior to 2.0a2
-// } else if ((exportPlatform == PConstants.MACOSX) &&
-// (exportFile.getName().toLowerCase().endsWith(".jnilib"))) {
-// // jnilib files can be placed in Contents/Resources/Java
-// Base.copyFile(exportFile, new File(jarFolder, exportName));
-//
-// } else {
-// // copy the file to the main directory.. prolly a .dll or something
-// Base.copyFile(exportFile, new File(destFolder, exportName));
-// }
-
- // first 2.0a2 attempt, until below...
-// } else if (exportPlatform == PConstants.MACOSX) {
-// Base.copyFile(exportFile, new File(jarFolder, exportName));
-//
-// } else {
-// Base.copyFile(exportFile, new File(destFolder, exportName));
} else {
// Starting with 2.0a2 put extra export files (DLLs, plugins folder,
// anything else for libraries) inside lib or Contents/Resources/Java
@@ -1380,31 +1439,30 @@ public class JavaBuild {
/// figure out run options for the VM
- String runOptions = Preferences.get("run.options");
+ List runOptions = new ArrayList();
if (Preferences.getBoolean("run.options.memory")) {
- runOptions += " -Xms" +
- Preferences.get("run.options.memory.initial") + "m";
- runOptions += " -Xmx" +
- Preferences.get("run.options.memory.maximum") + "m";
+ runOptions.add("-Xms" + Preferences.get("run.options.memory.initial") + "m");
+ runOptions.add("-Xmx" + Preferences.get("run.options.memory.maximum") + "m");
}
-// if (exportPlatform == PConstants.MACOSX) {
-// // If no bits specified (libs are all universal, or no native libs)
-// // then exportBits will be 0, and can be controlled via "Get Info".
-// // Otherwise, need to specify the bits as a VM option.
-// if (exportBits == 32) {
-// runOptions += " -d32";
-// } else if (exportBits == 64) {
-// runOptions += " -d64";
-// }
-// }
+ // https://github.com/processing/processing/issues/2239
+ runOptions.add("-Djna.nosys=true");
+
/// macosx: write out Info.plist (template for classpath, etc)
if (exportPlatform == PConstants.MACOSX) {
- String PLIST_TEMPLATE = "template.plist";
+ StringBuilder runOptionsXML = new StringBuilder();
+ for (String opt : runOptions) {
+ runOptionsXML.append(" ");
+ runOptionsXML.append(opt);
+ runOptionsXML.append("");
+ runOptionsXML.append('\n');
+ }
+
+ String PLIST_TEMPLATE = "Info.plist.tmpl";
File plistTemplate = new File(sketch.getFolder(), PLIST_TEMPLATE);
if (!plistTemplate.exists()) {
- plistTemplate = mode.getContentFile("application/template.plist");
+ plistTemplate = mode.getContentFile("application/" + PLIST_TEMPLATE);
}
File plistFile = new File(dotAppFolder, "Contents/Info.plist");
PrintWriter pw = PApplet.createWriter(plistFile);
@@ -1414,33 +1472,22 @@ public class JavaBuild {
if (lines[i].indexOf("@@") != -1) {
StringBuffer sb = new StringBuffer(lines[i]);
int index = 0;
- while ((index = sb.indexOf("@@vmoptions@@")) != -1) {
- sb.replace(index, index + "@@vmoptions@@".length(),
- runOptions);
+ while ((index = sb.indexOf("@@jvm_runtime@@")) != -1) {
+ sb.replace(index, index + "@@jvm_runtime@@".length(),
+ jvmRuntime);
+ }
+ while ((index = sb.indexOf("@@jvm_options_list@@")) != -1) {
+ sb.replace(index, index + "@@jvm_options_list@@".length(),
+ runOptionsXML.toString());
}
while ((index = sb.indexOf("@@sketch@@")) != -1) {
sb.replace(index, index + "@@sketch@@".length(),
sketch.getName());
}
- while ((index = sb.indexOf("@@classpath@@")) != -1) {
- sb.replace(index, index + "@@classpath@@".length(),
- exportClassPath.toString());
- }
while ((index = sb.indexOf("@@lsuipresentationmode@@")) != -1) {
sb.replace(index, index + "@@lsuipresentationmode@@".length(),
Preferences.getBoolean("export.application.fullscreen") ? "4" : "0");
}
- while ((index = sb.indexOf("@@lsarchitecturepriority@@")) != -1) {
- // More about this mess: http://support.apple.com/kb/TS2827
- // First default to exportBits == 0 case
- String arch = "x86_64\n i386";
- if (exportBits == 32) {
- arch = "i386";
- } else if (exportBits == 64) {
- arch = "x86_64";
- }
- sb.replace(index, index + "@@lsarchitecturepriority@@".length(), arch);
- }
lines[i] = sb.toString();
}
@@ -1450,17 +1497,93 @@ public class JavaBuild {
pw.flush();
pw.close();
+ // attempt to code sign if the Xcode tools appear to be installed
+ if (Base.isMacOS() && new File("/usr/bin/codesign_allocate").exists()) {
+ if (embedJava) {
+ ProcessHelper.ffs("codesign", "--force", "--sign", "-", jdkPath);
+ }
+ String appPath = dotAppFolder.getAbsolutePath();
+ ProcessHelper.ffs("codesign", "--force", "--sign", "-", appPath);
+ }
+
} else if (exportPlatform == PConstants.WINDOWS) {
- File argsFile = new File(destFolder + "/lib/args.txt");
- PrintWriter pw = PApplet.createWriter(argsFile);
+ File buildFile = new File(destFolder, "launch4j-build.xml");
+ File configFile = new File(destFolder, "launch4j-config.xml");
- // Since this is only on Windows, make sure we use Windows CRLF
- pw.print(runOptions + "\r\n");
- pw.print(sketch.getName() + "\r\n");
- pw.print(exportClassPath);
+ XML project = new XML("project");
+ XML target = project.addChild("target");
+ target.setString("name", "windows");
+
+ XML taskdef = target.addChild("taskdef");
+ taskdef.setString("name", "launch4j");
+ taskdef.setString("classname", "net.sf.launch4j.ant.Launch4jTask");
+ String launchPath = mode.getContentFile("application/launch4j").getAbsolutePath();
+ taskdef.setString("classpath", launchPath + "/launch4j.jar:" + launchPath + "/lib/xstream.jar");
+
+ XML launch4j = target.addChild("launch4j");
+ // not all launch4j options are available when embedded inside the ant
+ // build file (i.e. the icon param doesn't work), so use a config file
+ //
+ launch4j.setString("configFile", configFile.getAbsolutePath());
+
+ XML config = new XML("launch4jConfig");
+ config.addChild("headerType").setContent("gui");
+ config.addChild("dontWrapJar").setContent("true");
+ config.addChild("downloadUrl").setContent("http://java.com/download");
+
+ File exeFile = new File(destFolder, sketch.getName() + ".exe");
+ config.addChild("outfile").setContent(exeFile.getAbsolutePath());
+
+ File iconFile = mode.getContentFile("application/sketch.ico");
+ config.addChild("icon").setContent(iconFile.getAbsolutePath());
- pw.flush();
- pw.close();
+ XML clazzPath = config.addChild("classPath");
+ clazzPath.addChild("mainClass").setContent(sketch.getName());
+ for (String jarName : jarList) {
+ clazzPath.addChild("cp").setContent("lib/" + jarName);
+ }
+ XML jre = config.addChild("jre");
+ if (embedJava) {
+ jre.addChild("path").setContent("java");
+ }
+ jre.addChild("minVersion").setContent("1.7.0_40");
+ for (String opt : runOptions) {
+ jre.addChild("opt").setContent(opt);
+ }
+
+ /*
+ XML config = launch4j.addChild("config");
+ config.setString("headerType", "gui");
+ File exeFile = new File(destFolder, sketch.getName() + ".exe");
+ config.setString("outfile", exeFile.getAbsolutePath());
+ config.setString("dontWrapJar", "true");
+ config.setString("jarPath", "lib\\" + jarList[0]);
+
+ File iconFile = mode.getContentFile("application/sketch.ico");
+ config.addChild("icon").setContent(iconFile.getAbsolutePath());
+
+ XML clazzPath = config.addChild("classPath");
+ clazzPath.setString("mainClass", sketch.getName());
+ for (int i = 1; i < jarList.length; i++) {
+ String jarName = jarList[i];
+ clazzPath.addChild("cp").setContent("lib\\" + jarName);
+ }
+ XML jre = config.addChild("jre");
+ jre.setString("minVersion", "1.7.0_40");
+ //PApplet.join(runOptions.toArray(new String[0]), " ")
+ for (String opt : runOptions) {
+ jre.addChild("opt").setContent(opt);
+ }
+ */
+
+ config.save(configFile);
+ project.save(buildFile);
+ if (!buildWindowsLauncher(buildFile, "windows")) {
+ // don't delete the build file, might be useful for debugging
+ return false;
+ }
+ configFile.delete();
+ buildFile.delete();
} else {
File shellScript = new File(destFolder, sketch.getName());
@@ -1473,7 +1596,13 @@ public class JavaBuild {
pw.print("APPDIR=$(dirname \"$0\")\n"); // more posix compliant
// another fix for bug #234, LD_LIBRARY_PATH ignored on some platforms
//ps.print("LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR\n");
- pw.print("java " + Preferences.get("run.options") +
+ if (embedJava) {
+ // https://github.com/processing/processing/issues/2349
+ pw.print("$APPDIR/java/bin/");
+ }
+ String runOptionsStr =
+ PApplet.join(runOptions.toArray(new String[0]), " ");
+ pw.print("java " + runOptionsStr +
" -Djava.library.path=\"$APPDIR:$APPDIR/lib\"" +
" -cp \"" + exportClassPath + "\"" +
" " + sketch.getName() + " \"$@\"\n");
@@ -1512,23 +1641,66 @@ public class JavaBuild {
}
- /// remove the .class files from the export folder.
-// for (File file : classFiles) {
-// if (!file.delete()) {
-// Base.showWarning("Could not delete",
-// file.getName() + " could not \n" +
-// "be deleted from the applet folder. \n" +
-// "You'll need to remove it by hand.", null);
-// }
-// }
- // these will now be removed automatically via the temp folder deleteOnExit()
-
-
/// goodbye
return true;
}
+ /**
+ * Run the launch4j build.xml file through ant to create the exe.
+ * Most of this code was lifted from Android mode.
+ */
+ protected boolean buildWindowsLauncher(File buildFile, String target) {
+ Project p = new Project();
+ String path = buildFile.getAbsolutePath().replace('\\', '/');
+ p.setUserProperty("ant.file", path);
+
+ // deals with a problem where javac error messages weren't coming through
+ p.setUserProperty("build.compiler", "extJavac");
+
+ // too chatty
+ /*
+ // try to spew something useful to the console
+ final DefaultLogger consoleLogger = new DefaultLogger();
+ consoleLogger.setErrorPrintStream(System.err);
+ consoleLogger.setOutputPrintStream(System.out);
+ // WARN, INFO, VERBOSE, DEBUG
+ consoleLogger.setMessageOutputLevel(Project.MSG_ERR);
+ p.addBuildListener(consoleLogger);
+ */
+
+ DefaultLogger errorLogger = new DefaultLogger();
+ ByteArrayOutputStream errb = new ByteArrayOutputStream();
+ PrintStream errp = new PrintStream(errb);
+ errorLogger.setErrorPrintStream(errp);
+ ByteArrayOutputStream outb = new ByteArrayOutputStream();
+ PrintStream outp = new PrintStream(outb);
+ errorLogger.setOutputPrintStream(outp);
+ errorLogger.setMessageOutputLevel(Project.MSG_INFO);
+ p.addBuildListener(errorLogger);
+
+ try {
+ p.fireBuildStarted();
+ p.init();
+ final ProjectHelper helper = ProjectHelper.getProjectHelper();
+ p.addReference("ant.projectHelper", helper);
+ helper.parse(p, buildFile);
+ p.executeTarget(target);
+ return true;
+
+ } catch (final BuildException e) {
+ // Send a "build finished" event to the build listeners for this project.
+ p.fireBuildFinished(e);
+
+ String out = new String(outb.toByteArray());
+ String err = new String(errb.toByteArray());
+ System.out.println(out);
+ System.err.println(err);
+ }
+ return false;
+ }
+
+
protected void addManifest(ZipOutputStream zos) throws IOException {
ZipEntry entry = new ZipEntry("META-INF/MANIFEST.MF");
zos.putNextEntry(entry);
diff --git a/app/src/processing/mode/java/JavaEditor.java b/app/src/processing/mode/java/JavaEditor.java
index 3bb214a59..155ef546c 100644
--- a/app/src/processing/mode/java/JavaEditor.java
+++ b/app/src/processing/mode/java/JavaEditor.java
@@ -251,31 +251,33 @@ public class JavaEditor extends Editor {
toolbar.deactivate(JavaToolbar.EXPORT);
}
-
+
+// JPanel presentColorPanel;
+// JTextField presentColorPanel;
+
protected boolean exportApplicationPrompt() throws IOException, SketchException {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(Box.createVerticalStrut(6));
- //Box panel = Box.createVerticalBox();
-
- //Box labelBox = Box.createHorizontalBox();
+// Box panel = Box.createVerticalBox();
+// Box labelBox = Box.createHorizontalBox();
// String msg = "Click Export to Application to create a standalone, " +
// "double-clickable application for the selected plaforms.";
-
// String msg = "Export to Application creates a standalone, \n" +
// "double-clickable application for the selected plaforms.";
String line1 = Language.text("export.description.line1");
String line2 = Language.text("export.description.line2");
+ //String line2 = "standalone application for the current plaform.";
JLabel label1 = new JLabel(line1, SwingConstants.CENTER);
JLabel label2 = new JLabel(line2, SwingConstants.CENTER);
label1.setAlignmentX(Component.LEFT_ALIGNMENT);
label2.setAlignmentX(Component.LEFT_ALIGNMENT);
-// label1.setAlignmentX();
-// label2.setAlignmentX(0);
panel.add(label1);
panel.add(label2);
- int wide = label2.getPreferredSize().width;
+ // The longer line is different between Windows and OS X.
+// int wide = Math.max(label1.getPreferredSize().width,
+// label2.getPreferredSize().width);
panel.add(Box.createVerticalStrut(12));
final JCheckBox windowsButton = new JCheckBox("Windows");
@@ -288,7 +290,6 @@ public class JavaEditor extends Editor {
});
final JCheckBox macosxButton = new JCheckBox("Mac OS X");
- //macosxButton.setMnemonic(KeyEvent.VK_M);
macosxButton.setSelected(Preferences.getBoolean("export.application.platform.macosx"));
macosxButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
@@ -315,14 +316,15 @@ public class JavaEditor extends Editor {
platformPanel.setBorder(new TitledBorder(Language.text("export.platforms")));
//Dimension goodIdea = new Dimension(wide, platformPanel.getPreferredSize().height);
//platformPanel.setMaximumSize(goodIdea);
- wide = Math.max(wide, platformPanel.getPreferredSize().width);
+// wide = Math.max(wide, platformPanel.getPreferredSize().width);
platformPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(platformPanel);
-
-// Box indentPanel = Box.createHorizontalBox();
-// indentPanel.add(Box.createHorizontalStrut(new JCheckBox().getPreferredSize().width));
+ int divWidth = platformPanel.getPreferredSize().width;
+
+ //int indent = new JCheckBox().getPreferredSize().width;
+ int indent = 0;
+
final JCheckBox showStopButton = new JCheckBox(Language.text("export.options.show_stop_button"));
- //showStopButton.setMnemonic(KeyEvent.VK_S);
showStopButton.setSelected(Preferences.getBoolean("export.application.stop"));
showStopButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
@@ -330,9 +332,7 @@ public class JavaEditor extends Editor {
}
});
showStopButton.setEnabled(Preferences.getBoolean("export.application.fullscreen"));
- showStopButton.setBorder(new EmptyBorder(3, 13, 6, 13));
-// indentPanel.add(showStopButton);
-// indentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ showStopButton.setBorder(new EmptyBorder(3, 13 + indent, 6, 13));
final JCheckBox fullScreenButton = new JCheckBox(Language.text("export.options.fullscreen"));
//fullscreenButton.setMnemonic(KeyEvent.VK_F);
@@ -346,63 +346,200 @@ public class JavaEditor extends Editor {
});
fullScreenButton.setBorder(new EmptyBorder(3, 13, 3, 13));
- JPanel optionPanel = new JPanel();
- optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.Y_AXIS));
- optionPanel.add(fullScreenButton);
- optionPanel.add(showStopButton);
-// optionPanel.add(indentPanel);
- optionPanel.setBorder(new TitledBorder(Language.text("export.options")));
- wide = Math.max(wide, platformPanel.getPreferredSize().width);
- //goodIdea = new Dimension(wide, optionPanel.getPreferredSize().height);
- optionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
- //optionPanel.setMaximumSize(goodIdea);
- panel.add(optionPanel);
+ JPanel presentPanel = new JPanel();
+ presentPanel.setLayout(new BoxLayout(presentPanel, BoxLayout.Y_AXIS));
+ Box fullScreenBox = Box.createHorizontalBox();
+ fullScreenBox.add(fullScreenButton);
+
+ /*
+ //run.present.stop.color
+// presentColorPanel = new JTextField();
+// presentColorPanel.setFocusable(false);
+// presentColorPanel.setEnabled(false);
+ presentColorPanel = new JPanel() {
+ public void paintComponent(Graphics g) {
+ g.setColor(Preferences.getColor("run.present.bgcolor"));
+ Dimension size = getSize();
+ g.fillRect(0, 0, size.width, size.height);
+ }
+ };
+ presentColorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+// presentColorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
+ presentColorPanel.setMaximumSize(new Dimension(30, 20));
+ fullScreenBox.add(presentColorPanel);
+ */
+ fullScreenBox.add(new ColorPreference("run.present.bgcolor"));
+ //presentPanel.add(fullScreenButton);
+ fullScreenBox.add(Box.createHorizontalStrut(10));
+ fullScreenBox.add(Box.createHorizontalGlue());
- Dimension good;
- //label1, label2, platformPanel, optionPanel
- good = new Dimension(wide, label1.getPreferredSize().height);
- label1.setMaximumSize(good);
- good = new Dimension(wide, label2.getPreferredSize().height);
- label2.setMaximumSize(good);
- good = new Dimension(wide, platformPanel.getPreferredSize().height);
- platformPanel.setMaximumSize(good);
- good = new Dimension(wide, optionPanel.getPreferredSize().height);
- optionPanel.setMaximumSize(good);
-
-// JPanel actionPanel = new JPanel();
-// optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
-// optionPanel.add(Box.createHorizontalGlue());
-
-// final JDialog frame = new JDialog(editor, "Export to Application");
-
-// JButton cancelButton = new JButton("Cancel");
-// cancelButton.addActionListener(new ActionListener() {
-// public void actionPerformed(ActionEvent e) {
-// frame.dispose();
-// return false;
+ presentPanel.add(fullScreenBox);
+
+// presentColorPanel.addMouseListener(new MouseAdapter() {
+// public void mousePressed(MouseEvent e) {
+// new ColorListener("run.present.bgcolor");
// }
// });
- // Add the buttons in platform-specific order
-// if (PApplet.platform == PConstants.MACOSX) {
-// optionPanel.add(cancelButton);
-// optionPanel.add(exportButton);
-// } else {
-// optionPanel.add(exportButton);
-// optionPanel.add(cancelButton);
-// }
+ Box showStopBox = Box.createHorizontalBox();
+ showStopBox.add(showStopButton);
+ showStopBox.add(new ColorPreference("run.present.stop.color"));
+ showStopBox.add(Box.createHorizontalStrut(10));
+ showStopBox.add(Box.createHorizontalGlue());
+ presentPanel.add(showStopBox);
+
+ //presentPanel.add(showStopButton);
+// presentPanel.add(Box.createHorizontalStrut(10));
+// presentPanel.add(Box.createHorizontalGlue());
+ presentPanel.setBorder(new TitledBorder("Full Screen"));
+// wide = Math.max(wide, platformPanel.getPreferredSize().width);
+ presentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ panel.add(presentPanel);
+
+// Dimension good;
+// good = new Dimension(wide, label1.getPreferredSize().height);
+// label1.setMaximumSize(good);
+// good = new Dimension(wide, label2.getPreferredSize().height);
+// label2.setMaximumSize(good);
+// good = new Dimension(wide, presentPanel.getPreferredSize().height);
+
+ //
+
+ JPanel embedPanel = new JPanel();
+ embedPanel.setLayout(new BoxLayout(embedPanel, BoxLayout.Y_AXIS));
+
+ String platformName = null;
+ if (Base.isMacOS()) {
+ platformName = "Mac OS X";
+ } else if (Base.isWindows()) {
+ platformName = "Windows (" + Base.getNativeBits() + "-bit)";
+ } else if (Base.isLinux()) {
+ platformName = "Linux (" + Base.getNativeBits() + "-bit)";
+ }
+
+ boolean embed = Preferences.getBoolean("export.application.embed_java");
+ final String embedWarning =
+ "
" +
+// "" +
+ "Embedding Java will make the " + platformName + " application " +
+ "larger, but it will be far more likely to work. " +
+ "Users on other platforms will need to install Java 7.";
+ final String nopeWarning =
+ "
" +
+// "" +
+ "Users on all platforms will have to install the latest " +
+ "version of Java 7 from http://java.com/download. " +
+ " ";
+ //"from java.com/download.";
+ final JLabel warningLabel = new JLabel(embed ? embedWarning : nopeWarning);
+ warningLabel.addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent event) {
+ Base.openURL("http://java.com/download");
+ }
+ });
+ warningLabel.setBorder(new EmptyBorder(3, 13 + indent, 3, 13));
+
+ final JCheckBox embedJavaButton =
+ new JCheckBox("Embed Java for " + platformName);
+ embedJavaButton.setSelected(embed);
+ embedJavaButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ boolean selected = embedJavaButton.isSelected();
+ Preferences.setBoolean("export.application.embed_java", selected);
+ if (selected) {
+ warningLabel.setText(embedWarning);
+ } else {
+ warningLabel.setText(nopeWarning);
+ }
+ }
+ });
+ embedJavaButton.setBorder(new EmptyBorder(3, 13, 3, 13));
+
+ embedPanel.add(embedJavaButton);
+ embedPanel.add(warningLabel);
+ embedPanel.setBorder(new TitledBorder("Embed Java"));
+ panel.add(embedPanel);
+
+ //
+
+ if (Base.isMacOS()) {
+ JPanel signPanel = new JPanel();
+ signPanel.setLayout(new BoxLayout(signPanel, BoxLayout.Y_AXIS));
+ signPanel.setBorder(new TitledBorder("Code Signing"));
+
+ // gatekeeper: http://support.apple.com/kb/ht5290
+ // for developers: https://developer.apple.com/developer-id/
+ String thePain =
+ //"" +
+ "In recent versions of OS X, Apple has introduced the \u201CGatekeeper\u201D system, " +
+ "which makes it more difficult to run applications like those exported from Processing. ";
+
+ if (new File("/usr/bin/codesign_allocate").exists()) {
+ thePain +=
+ "This application will be \u201Cself-signed\u201D which means that Finder may report that the " +
+ "application is from an \u201Cunidentified developer\u201D. If the application will not " +
+ "run, try right-clicking the app and selecting Open from the pop-up menu. Or you can visit " +
+ "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ";
+ } else {
+ thePain +=
+ "Gatekeeper requires applications to be \u201Csigned\u201D, or they will be reported as damaged. " +
+ "To prevent this message, install Xcode (and the Command Line Tools) from the App Store, or visit " +
+ "System Preferences \u2192 Security & Privacy and select Allow apps downloaded from: anywhere. ";
+ }
+ thePain +=
+ "To avoid the messages entirely, manually code sign your app. " +
+ "For more information: https://developer.apple.com/developer-id/";
+
+ // xattr -d com.apple.quarantine thesketch.app
+
+ //signPanel.add(new JLabel(thePain));
+ //JEditorPane area = new JEditorPane("text/html", thePain);
+ //JTextPane area = new JEditorPane("text/html", thePain);
+
+// JTextArea area = new JTextArea(thePain);
+// area.setBackground(null);
+// area.setFont(new Font("Dialog", Font.PLAIN, 10));
+// area.setLineWrap(true);
+// area.setWrapStyleWord(true);
+ // Are you f-king serious, Java API developers?
+ JLabel area = new JLabel("
+ * 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.
+ *
@@ -784,8 +835,6 @@ public class PApplet extends Applet
* location, or could be used by other classes to launch at a
* specific position on-screen.
*/
- static public final String ARGS_EXTERNAL = "--external";
-
static public final String ARGS_LOCATION = "--location";
static public final String ARGS_DISPLAY = "--display";
@@ -865,6 +914,12 @@ public class PApplet extends Applet
useActive = false;
}
+ if (javaVersion >= 1.7f) {
+ try {
+ revalidateMethod = getClass().getMethod("revalidate", new Class[] {});
+ } catch (Exception e) { }
+ }
+
// send tab keys through to the PApplet
setFocusTraversalKeysEnabled(false);
@@ -895,11 +950,18 @@ public class PApplet extends Applet
online = false;
}
- try {
- if (sketchPath == null) {
- sketchPath = System.getProperty("user.dir");
- }
- } catch (Exception e) { } // may be a security problem
+ // Removed in 2.1.2, brought back for 2.1.3. Usually sketchPath is set
+ // inside runSketch(), but if this sketch takes care of calls to init()
+ // and setup() itself (i.e. it's in a larger Java application), it'll
+ // still need to be set here so that fonts, etc can be retrieved.
+ if (sketchPath == null) {
+ sketchPath = calcSketchPath();
+ }
+
+ // Figure out the available display width and height.
+ // No major problem if this fails, we have to try again anyway in
+ // handleDraw() on the first (== 0) frame.
+ checkDisplaySize();
Dimension size = getSize();
if ((size.width != 0) && (size.height != 0)) {
@@ -954,6 +1016,21 @@ public class PApplet extends Applet
}
+ private void checkDisplaySize() {
+ if (getGraphicsConfiguration() != null) {
+ GraphicsDevice displayDevice = getGraphicsConfiguration().getDevice();
+
+ if (displayDevice != null) {
+ Rectangle screenRect =
+ displayDevice.getDefaultConfiguration().getBounds();
+
+ displayWidth = screenRect.width;
+ displayHeight = screenRect.height;
+ }
+ }
+ }
+
+
private boolean checkRetina() {
if (platform == MACOSX) {
// This should probably be reset each time there's a display change.
@@ -1558,6 +1635,7 @@ public class PApplet extends Applet
* @see PApplet#noLoop()
* @see PApplet#redraw()
* @see PApplet#frameRate(float)
+ * @see PGraphics#background(float, float, float, float)
*/
public void draw() {
// if no draw method, then shut things down
@@ -1650,6 +1728,8 @@ public class PApplet extends Applet
* @webref environment
* @param w width of the display window in units of pixels
* @param h height of the display window in units of pixels
+ * @see PApplet#width
+ * @see PApplet#height
*/
public void size(int w, int h) {
size(w, h, JAVA2D, null);
@@ -2263,17 +2343,18 @@ public class PApplet extends Applet
long now = System.nanoTime();
if (frameCount == 0) {
- GraphicsConfiguration gc = getGraphicsConfiguration();
- if (gc == null) return;
- GraphicsDevice displayDevice =
- getGraphicsConfiguration().getDevice();
- if (displayDevice == null) return;
- Rectangle screenRect =
- displayDevice.getDefaultConfiguration().getBounds();
-// screenX = screenRect.x;
-// screenY = screenRect.y;
- displayWidth = screenRect.width;
- displayHeight = screenRect.height;
+// GraphicsConfiguration gc = getGraphicsConfiguration();
+// if (gc == null) return;
+// GraphicsDevice displayDevice =
+// getGraphicsConfiguration().getDevice();
+// if (displayDevice == null) return;
+// Rectangle screenRect =
+// displayDevice.getDefaultConfiguration().getBounds();
+//// screenX = screenRect.x;
+//// screenY = screenRect.y;
+// displayWidth = screenRect.width;
+// displayHeight = screenRect.height;
+ checkDisplaySize();
try {
//println("Calling setup()");
@@ -2333,7 +2414,9 @@ public class PApplet extends Applet
render();
} else {
Graphics screen = getGraphics();
- screen.drawImage(g.image, 0, 0, width, height, null);
+ if (screen != null) {
+ screen.drawImage(g.image, 0, 0, width, height, null);
+ }
}
} else {
repaint();
@@ -2690,10 +2773,14 @@ public class PApplet extends Applet
// also prevents mouseExited() on the mac from hosing the mouse
// position, because x/y are bizarre values on the exit event.
// see also the id check below.. both of these go together.
- // Not necessary to set mouseX/Y on PRESS or RELEASE events because the
- // actual position will have been set by a MOVE or DRAG event.
- if (event.getAction() == MouseEvent.DRAG ||
- event.getAction() == MouseEvent.MOVE) {
+ // Not necessary to set mouseX/Y on RELEASE events because the
+ // actual position will have been set by a PRESS or DRAG event.
+ // However, PRESS events might come without a preceeding move,
+ // if the sketch window gains focus on that PRESS.
+ final int action = event.getAction();
+ if (action == MouseEvent.DRAG ||
+ action == MouseEvent.MOVE ||
+ action == MouseEvent.PRESS) {
pmouseX = emouseX;
pmouseY = emouseY;
mouseX = event.getX();
@@ -2727,7 +2814,7 @@ public class PApplet extends Applet
// Do this up here in case a registered method relies on the
// boolean for mousePressed.
- switch (event.getAction()) {
+ switch (action) {
case MouseEvent.PRESS:
mousePressed = true;
break;
@@ -2738,7 +2825,7 @@ public class PApplet extends Applet
handleMethods("mouseEvent", new Object[] { event });
- switch (event.getAction()) {
+ switch (action) {
case MouseEvent.PRESS:
// mousePressed = true;
mousePressed(event);
@@ -2767,8 +2854,8 @@ public class PApplet extends Applet
break;
}
- if ((event.getAction() == MouseEvent.DRAG) ||
- (event.getAction() == MouseEvent.MOVE)) {
+ if ((action == MouseEvent.DRAG) ||
+ (action == MouseEvent.MOVE)) {
emouseX = mouseX;
emouseY = mouseY;
}
@@ -2981,11 +3068,15 @@ public class PApplet extends Applet
* @webref input:mouse
* @see PApplet#mouseX
* @see PApplet#mouseY
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
* @see PApplet#mousePressed
- * @see PApplet#mouseButton
* @see PApplet#mouseReleased()
+ * @see PApplet#mouseClicked()
* @see PApplet#mouseMoved()
* @see PApplet#mouseDragged()
+ * @see PApplet#mouseButton
+ * @see PApplet#mouseWheel(MouseEvent)
*/
public void mousePressed() { }
@@ -3005,11 +3096,15 @@ public class PApplet extends Applet
* @webref input:mouse
* @see PApplet#mouseX
* @see PApplet#mouseY
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
* @see PApplet#mousePressed
- * @see PApplet#mouseButton
* @see PApplet#mousePressed()
+ * @see PApplet#mouseClicked()
* @see PApplet#mouseMoved()
* @see PApplet#mouseDragged()
+ * @see PApplet#mouseButton
+ * @see PApplet#mouseWheel(MouseEvent)
*/
public void mouseReleased() { }
@@ -3033,11 +3128,15 @@ public class PApplet extends Applet
* @webref input:mouse
* @see PApplet#mouseX
* @see PApplet#mouseY
- * @see PApplet#mouseButton
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
+ * @see PApplet#mousePressed
* @see PApplet#mousePressed()
* @see PApplet#mouseReleased()
* @see PApplet#mouseMoved()
* @see PApplet#mouseDragged()
+ * @see PApplet#mouseButton
+ * @see PApplet#mouseWheel(MouseEvent)
*/
public void mouseClicked() { }
@@ -3057,10 +3156,15 @@ public class PApplet extends Applet
* @webref input:mouse
* @see PApplet#mouseX
* @see PApplet#mouseY
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
* @see PApplet#mousePressed
* @see PApplet#mousePressed()
* @see PApplet#mouseReleased()
+ * @see PApplet#mouseClicked()
* @see PApplet#mouseMoved()
+ * @see PApplet#mouseButton
+ * @see PApplet#mouseWheel(MouseEvent)
*/
public void mouseDragged() { }
@@ -3080,10 +3184,15 @@ public class PApplet extends Applet
* @webref input:mouse
* @see PApplet#mouseX
* @see PApplet#mouseY
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
* @see PApplet#mousePressed
* @see PApplet#mousePressed()
* @see PApplet#mouseReleased()
+ * @see PApplet#mouseClicked()
* @see PApplet#mouseDragged()
+ * @see PApplet#mouseButton
+ * @see PApplet#mouseWheel(MouseEvent)
*/
public void mouseMoved() { }
@@ -3120,6 +3229,17 @@ public class PApplet extends Applet
*
* @webref input:mouse
* @param event the MouseEvent
+ * @see PApplet#mouseX
+ * @see PApplet#mouseY
+ * @see PApplet#pmouseX
+ * @see PApplet#pmouseY
+ * @see PApplet#mousePressed
+ * @see PApplet#mousePressed()
+ * @see PApplet#mouseReleased()
+ * @see PApplet#mouseClicked()
+ * @see PApplet#mouseMoved()
+ * @see PApplet#mouseDragged()
+ * @see PApplet#mouseButton
*/
public void mouseWheel(MouseEvent event) {
mouseWheel();
@@ -3665,6 +3785,8 @@ public class PApplet extends Applet
* ( end auto-generated )
* @webref environment
* @param fps number of desired frames per second
+ * @see PApplet#frameRate
+ * @see PApplet#frameCount
* @see PApplet#setup()
* @see PApplet#draw()
* @see PApplet#loop()
@@ -3989,8 +4111,12 @@ public class PApplet extends Applet
}
}
-
- void exitActual() {
+ /**
+ * Some subclasses (I'm looking at you, processing.py) might wish to do something
+ * other than actually terminate the JVM. This gives them a chance to do whatever
+ * they have in mind when cleaning up.
+ */
+ protected void exitActual() {
try {
System.exit(0);
} catch (SecurityException e) {
@@ -4149,6 +4275,7 @@ public class PApplet extends Applet
* @webref output:image
* @see PApplet#save(String)
* @see PApplet#createGraphics(int, int, String, String)
+ * @see PApplet#frameCount
* @param filename any sequence of letters or numbers that ends with either ".tif", ".tga", ".jpg", or ".png"
*/
public void saveFrame(String filename) {
@@ -4201,6 +4328,11 @@ public class PApplet extends Applet
* @param kind either ARROW, CROSS, HAND, MOVE, TEXT, or WAIT
*/
public void cursor(int kind) {
+ // Swap the HAND cursor because MOVE doesn't seem to be available on OS X
+ // https://github.com/processing/processing/issues/2358
+ if (platform == MACOSX && kind == MOVE) {
+ kind = HAND;
+ }
setCursor(Cursor.getPredefinedCursor(kind));
cursorVisible = true;
this.cursorType = kind;
@@ -4335,8 +4467,9 @@ public class PApplet extends Applet
* ( end auto-generated )
* @webref output:text_area
* @usage IDE
- * @param what boolean, byte, char, color, int, float, String, Object
- * @see PApplet#println(byte)
+ * @param what data to print to console
+ * @see PApplet#println()
+ * @see PApplet#printArray(Object)
* @see PApplet#join(String[], char)
*/
static public void print(byte what) {
@@ -4379,6 +4512,26 @@ public class PApplet extends Applet
System.out.flush();
}
+ /**
+ * @param variables list of data, separated by commas
+ */
+ static public void print(Object... variables) {
+ StringBuilder sb = new StringBuilder();
+ for (Object o : variables) {
+ if (sb.length() != 0) {
+ sb.append(" ");
+ }
+ if (o == null) {
+ sb.append("null");
+ } else {
+ sb.append(o.toString());
+ }
+ }
+ System.out.print(sb.toString());
+ }
+
+
+ /*
static public void print(Object what) {
if (what == null) {
// special case since this does fuggly things on > 1.1
@@ -4387,9 +4540,10 @@ public class PApplet extends Applet
System.out.println(what.toString());
}
}
+ */
- //
-/**
+
+ /**
* ( begin auto-generated from println.xml )
*
* Writes to the text area of the Processing environment's console. This is
@@ -4408,14 +4562,15 @@ public class PApplet extends Applet
* @webref output:text_area
* @usage IDE
* @see PApplet#print(byte)
+ * @see PApplet#printArray(Object)
*/
static public void println() {
System.out.println();
}
- //
+
/**
- * @param what boolean, byte, char, color, int, float, String, Object
+ * @param what data to print to console
*/
static public void println(byte what) {
System.out.println(what);
@@ -4457,7 +4612,60 @@ public class PApplet extends Applet
System.out.flush();
}
+ /**
+ * @param variables list of data, separated by commas
+ */
+ static public void println(Object... variables) {
+// System.out.println("got " + variables.length + " variables");
+ print(variables);
+ println();
+ }
+
+
+ /*
+ // Breaking this out since the compiler doesn't know the difference between
+ // Object... and just Object (with an array passed in). This should take care
+ // of the confusion for at least the most common case (a String array).
+ // On second thought, we're going the printArray() route, since the other
+ // object types are also used frequently.
+ static public void println(String[] array) {
+ for (int i = 0; i < array.length; i++) {
+ System.out.println("[" + i + "] \"" + array[i] + "\"");
+ }
+ System.out.flush();
+ }
+ */
+
+
+ /**
+ * For arrays, use printArray() instead. This function causes a warning
+ * because the new print(Object...) and println(Object...) functions can't
+ * be reliably bound by the compiler.
+ */
static public void println(Object what) {
+ if (what == null) {
+ System.out.println("null");
+ } else if (what.getClass().isArray()) {
+ printArray(what);
+ } else {
+ System.out.println(what.toString());
+ System.out.flush();
+ }
+ }
+
+ /**
+ * ( begin auto-generated from printArray.xml )
+ *
+ * To come...
+ *
+ * ( end auto-generated )
+ * @webref output:text_area
+ * @param what one-dimensional array
+ * @usage IDE
+ * @see PApplet#print(byte)
+ * @see PApplet#println()
+ */
+ static public void printArray(Object what) {
if (what == null) {
// special case since this does fuggly things on > 1.1
System.out.println("null");
@@ -5141,6 +5349,8 @@ public class PApplet extends Applet
* @param amt float between 0.0 and 1.0
* @see PGraphics#curvePoint(float, float, float, float, float)
* @see PGraphics#bezierPoint(float, float, float, float, float)
+ * @see PVector#lerp(PVector, float)
+ * @see PGraphics#lerpColor(int, int, float)
*/
static public final float lerp(float start, float stop, float amt) {
return start + (stop-start) * amt;
@@ -5863,6 +6073,13 @@ public class PApplet extends Applet
* Rewritten for 0115 to read/write RLE-encoded targa images.
* For 0125, non-RLE encoded images are now supported, along with
* images whose y-order is reversed (which is standard for TGA files).
+ *
+ * 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);
@@ -5880,7 +6097,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)
@@ -6103,6 +6320,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;
@@ -6294,7 +6512,7 @@ public class PApplet extends Applet
/**
- * @webref input:files
+ * @webref output:files
* @param table the Table object to save to a file
* @param filename the filename to which the Table should be saved
* @see Table
@@ -7729,13 +7947,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.
@@ -7762,7 +8006,7 @@ 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();
@@ -7776,7 +8020,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) {
// }
@@ -8374,19 +8618,20 @@ public class PApplet extends Applet
}
static final public Object splice(Object list, Object value, int index) {
- Object[] outgoing = null;
+ Class> type = list.getClass().getComponentType();
+ Object outgoing = null;
int length = Array.getLength(list);
// check whether item being spliced in is an array
if (value.getClass().getName().charAt(0) == '[') {
int vlength = Array.getLength(value);
- outgoing = new Object[length + vlength];
+ outgoing = Array.newInstance(type, length + vlength);
System.arraycopy(list, 0, outgoing, 0, index);
System.arraycopy(value, 0, outgoing, index, vlength);
System.arraycopy(list, index, outgoing, index + vlength, length - index);
} else {
- outgoing = new Object[length + 1];
+ outgoing = Array.newInstance(type, length + 1);
System.arraycopy(list, 0, outgoing, 0, index);
Array.set(outgoing, index, value);
System.arraycopy(list, index, outgoing, index + 1, length - index);
@@ -10005,7 +10250,7 @@ public class PApplet extends Applet
int alpha = (int) falpha;
if (gray > 255) gray = 255; else if (gray < 0) gray = 0;
if (alpha > 255) alpha = 255; else if (alpha < 0) alpha = 0;
- return 0xff000000 | (gray << 16) | (gray << 8) | gray;
+ return (alpha << 24) | (gray << 16) | (gray << 8) | gray;
}
return g.color(fgray, falpha);
}
@@ -10142,6 +10387,21 @@ public class PApplet extends Applet
if (!newBounds.equals(oldBounds)) {
// the ComponentListener in PApplet will handle calling size()
setBounds(newBounds);
+
+ // In 0225, calling this via reflection so that we can still
+ // compile in Java 1.6. This is a trap since we really need
+ // to move to 1.7 and cannot support 1.6, but things like text
+ // are still a little wonky on 1.7, especially on OS X.
+ // This gives us a way to at least test against older VMs.
+ //revalidate(); // let the layout manager do its work
+ if (revalidateMethod != null) {
+ try {
+ revalidateMethod.invoke(PApplet.this);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ revalidateMethod = null;
+ }
+ }
}
}
}
@@ -10342,14 +10602,7 @@ public class PApplet extends Applet
boolean hideStop = false;
String param = null, value = null;
-
- // try to get the user folder. if running under java web start,
- // this may cause a security exception if the code is not signed.
- // http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Integrate;action=display;num=1159386274
- String folder = null;
- try {
- folder = System.getProperty("user.dir");
- } catch (Exception e) { }
+ String folder = calcSketchPath();
int argIndex = 0;
while (argIndex < args.length) {
@@ -10445,7 +10698,7 @@ public class PApplet extends Applet
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).
- frame.setBackground(new Color(0xCC, 0xCC, 0xCC));
+ ((JFrame) frame).getContentPane().setBackground(WINDOW_BGCOLOR);
// Cannot call setResizable(false) until later due to OS X (issue #467)
final PApplet applet;
@@ -10557,7 +10810,7 @@ public class PApplet extends Applet
//frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setUndecorated(true);
if (backgroundColor != null) {
- frame.setBackground(backgroundColor);
+ ((JFrame) frame).getContentPane().setBackground(backgroundColor);
}
// if (exclusive) {
// displayDevice.setFullScreenWindow(frame);
@@ -10714,7 +10967,7 @@ 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;
@@ -10782,7 +11035,7 @@ public class PApplet extends Applet
final String[] argsWithSketchName = new String[args.length + 1];
System.arraycopy(args, 0, argsWithSketchName, 0, args.length);
final String className = this.getClass().getSimpleName();
- final String cleanedClass =
+ final String cleanedClass =
className.replaceAll("__[^_]+__\\$", "").replaceAll("\\$\\d+", "");
argsWithSketchName[args.length] = cleanedClass;
runSketch(argsWithSketchName, this);
@@ -10794,6 +11047,34 @@ public class PApplet extends Applet
}
+ static protected String calcSketchPath() {
+ // try to get the user folder. if running under java web start,
+ // this may cause a security exception if the code is not signed.
+ // http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Integrate;action=display;num=1159386274
+ String folder = null;
+ try {
+ folder = System.getProperty("user.dir");
+
+ // Workaround for bug in Java for OS X from Oracle (7u51)
+ // https://github.com/processing/processing/issues/2181
+ if (platform == MACOSX) {
+ String jarPath =
+ PApplet.class.getProtectionDomain().getCodeSource().getLocation().getPath();
+ // The jarPath from above will be URL encoded (%20 for spaces)
+ jarPath = urlDecode(jarPath);
+ if (jarPath.contains("Contents/Java/")) {
+ String appPath = jarPath.substring(0, jarPath.indexOf(".app") + 4);
+ File containingFolder = new File(appPath).getParentFile();
+ folder = containingFolder.getAbsolutePath();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return folder;
+ }
+
+
//////////////////////////////////////////////////////////////
@@ -14083,7 +14364,9 @@ public class PApplet extends Applet
* ( end auto-generated )
*
* @webref color:setting
- * @see PGraphics#stroke(float, float, float, float)
+ * @see PGraphics#stroke(int, float)
+ * @see PGraphics#fill(float, float, float, float)
+ * @see PGraphics#noFill()
*/
public void noStroke() {
if (recorder != null) recorder.noStroke();
@@ -14115,7 +14398,11 @@ public class PApplet extends Applet
*
* @param rgb color value in hexadecimal notation
* @see PGraphics#noStroke()
+ * @see PGraphics#strokeWeight(float)
+ * @see PGraphics#strokeJoin(int)
+ * @see PGraphics#strokeCap(int)
* @see PGraphics#fill(int, float)
+ * @see PGraphics#noFill()
* @see PGraphics#tint(int, float)
* @see PGraphics#background(float, float, float, float)
* @see PGraphics#colorMode(int, float, float, float, float)
@@ -14279,6 +14566,8 @@ public class PApplet extends Applet
* @webref color:setting
* @usage web_application
* @see PGraphics#fill(float, float, float, float)
+ * @see PGraphics#stroke(int, float)
+ * @see PGraphics#noStroke()
*/
public void noFill() {
if (recorder != null) recorder.noFill();
@@ -14316,6 +14605,7 @@ public class PApplet extends Applet
* @param rgb color variable or hex value
* @see PGraphics#noFill()
* @see PGraphics#stroke(int, float)
+ * @see PGraphics#noStroke()
* @see PGraphics#tint(int, float)
* @see PGraphics#background(float, float, float, float)
* @see PGraphics#colorMode(int, float, float, float, float)
@@ -15155,6 +15445,7 @@ public class PApplet extends Applet
* @param amt between 0.0 and 1.0
* @see PImage#blendColor(int, int, int)
* @see PGraphics#color(float, float, float, float)
+ * @see PApplet#lerp(float, float, float)
*/
public int lerpColor(int c1, int c2, float amt) {
return g.lerpColor(c1, c2, amt);
diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java
index 037ae6fa8..517527102 100644
--- a/core/src/processing/core/PGraphics.java
+++ b/core/src/processing/core/PGraphics.java
@@ -1096,7 +1096,7 @@ public class PGraphics extends PImage implements PConstants {
if (which == ENABLE_NATIVE_FONTS ||
which == DISABLE_NATIVE_FONTS) {
showWarning("hint(ENABLE_NATIVE_FONTS) no longer supported. " +
- "Use createFont() instead.");
+ "Use createFont() instead.");
}
if (which > 0) {
hints[which] = true;
@@ -1224,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;
}
@@ -5814,6 +5817,8 @@ public class PGraphics extends PImage implements PConstants {
ellipseMode(s.ellipseMode);
shapeMode(s.shapeMode);
+ blendMode(s.blendMode);
+
if (s.tint) {
tint(s.tintColor);
} else {
@@ -5892,6 +5897,8 @@ public class PGraphics extends PImage implements PConstants {
s.ellipseMode = ellipseMode;
s.shapeMode = shapeMode;
+ s.blendMode = blendMode;
+
s.colorMode = colorMode;
s.colorModeX = colorModeX;
s.colorModeY = colorModeY;
@@ -6028,7 +6035,9 @@ public class PGraphics extends PImage implements PConstants {
* ( end auto-generated )
*
* @webref color:setting
- * @see PGraphics#stroke(float, float, float, float)
+ * @see PGraphics#stroke(int, float)
+ * @see PGraphics#fill(float, float, float, float)
+ * @see PGraphics#noFill()
*/
public void noStroke() {
stroke = false;
@@ -6059,7 +6068,11 @@ public class PGraphics extends PImage implements PConstants {
*
* @param rgb color value in hexadecimal notation
* @see PGraphics#noStroke()
+ * @see PGraphics#strokeWeight(float)
+ * @see PGraphics#strokeJoin(int)
+ * @see PGraphics#strokeCap(int)
* @see PGraphics#fill(int, float)
+ * @see PGraphics#noFill()
* @see PGraphics#tint(int, float)
* @see PGraphics#background(float, float, float, float)
* @see PGraphics#colorMode(int, float, float, float, float)
@@ -6263,6 +6276,8 @@ public class PGraphics extends PImage implements PConstants {
* @webref color:setting
* @usage web_application
* @see PGraphics#fill(float, float, float, float)
+ * @see PGraphics#stroke(int, float)
+ * @see PGraphics#noStroke()
*/
public void noFill() {
fill = false;
@@ -6299,6 +6314,7 @@ public class PGraphics extends PImage implements PConstants {
* @param rgb color variable or hex value
* @see PGraphics#noFill()
* @see PGraphics#stroke(int, float)
+ * @see PGraphics#noStroke()
* @see PGraphics#tint(int, float)
* @see PGraphics#background(float, float, float, float)
* @see PGraphics#colorMode(int, float, float, float, float)
@@ -7271,14 +7287,15 @@ public class PGraphics extends PImage implements PConstants {
* Strangely the old version of this code ignored the alpha
* value. not sure if that was a bug or what.
*
- * Note, no need for a bounds check since it's a 32 bit number.
+ * Note, no need for a bounds check for 'argb' since it's a 32 bit number.
+ * Bounds now checked on alpha, however (rev 0225).
*/
protected void colorCalcARGB(int argb, float alpha) {
if (alpha == colorModeA) {
calcAi = (argb >> 24) & 0xff;
calcColor = argb;
} else {
- calcAi = (int) (((argb >> 24) & 0xff) * (alpha / colorModeA));
+ calcAi = (int) (((argb >> 24) & 0xff) * PApplet.constrain((alpha / colorModeA), 0, 1));
calcColor = (calcAi << 24) | (argb & 0xFFFFFF);
}
calcRi = (argb >> 16) & 0xff;
@@ -7621,6 +7638,7 @@ public class PGraphics extends PImage implements PConstants {
* @param amt between 0.0 and 1.0
* @see PImage#blendColor(int, int, int)
* @see PGraphics#color(float, float, float, float)
+ * @see PApplet#lerp(float, float, float)
*/
public int lerpColor(int c1, int c2, float amt) {
return lerpColor(c1, c2, amt, colorMode);
@@ -7635,6 +7653,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 f35c83998..4b43c7e90 100644
--- a/core/src/processing/core/PGraphicsJava2D.java
+++ b/core/src/processing/core/PGraphicsJava2D.java
@@ -3,7 +3,8 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2005-11 Ben Fry and Casey Reas
+ Copyright (c) 2013-14 The Processing Foundation
+ Copyright (c) 2005-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
@@ -24,10 +25,13 @@
package processing.core;
import java.awt.*;
+import java.awt.font.TextAttribute;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.InputStream;
import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Map;
import java.util.zip.GZIPInputStream;
import processing.data.XML;
@@ -35,22 +39,15 @@ import processing.data.XML;
/**
* Subclass for PGraphics that implements the graphics API using Java2D.
- *
- *
Pixel operations too slow? As of release 0085 (the first beta),
- * the default renderer uses Java2D. It's more accurate than the renderer
- * used in alpha releases of Processing (it handles stroke caps and joins,
- * and has better polygon tessellation), but it's super slow for handling
- * pixels. At least until we get a chance to get the old 2D renderer
- * (now called P2D) working in a similar fashion, you can use
- * size(w, h, P3D) instead of size(w, h) which will
- * be faster for general pixel flipping madness.
- *
- *
To get access to the Java 2D "Graphics2D" object for the default
+ *
+ * To get access to the Java 2D "Graphics2D" object for the default
* renderer, use:
*
Graphics2D g2 = ((PGraphicsJava2D)g).g2;
* This will let you do Java 2D stuff directly, but is not supported in
* any way shape or form. Which just means "have fun, but don't complain
- * if it breaks."
+ * if it breaks."
+ *
+ * Advanced debugging notes for Java2D.
*/
public class PGraphicsJava2D extends PGraphics {
BufferStrategy strategy;
@@ -376,7 +373,7 @@ public class PGraphicsJava2D extends PGraphics {
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);
@@ -425,6 +422,14 @@ public class PGraphicsJava2D extends PGraphics {
@Override
protected void defaultSettings() {
if (!useCanvas) {
+ // Papered over another threading issue...
+ // See if this comes back now that the other issue is fixed.
+// while (g2 == null) {
+// try {
+// System.out.println("sleeping until g2 is available");
+// Thread.sleep(5);
+// } catch (InterruptedException e) { }
+// }
defaultComposite = g2.getComposite();
}
super.defaultSettings();
@@ -1187,10 +1192,26 @@ public class PGraphicsJava2D extends PGraphics {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
+
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
quality == 4 ?
RenderingHints.VALUE_INTERPOLATION_BICUBIC :
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+
+ // http://docs.oracle.com/javase/tutorial/2d/text/renderinghints.html
+ // Oracle Java text anti-aliasing on OS X looks like s*t compared to the
+ // text rendering with Apple's old Java 6. Below, several attempts to fix:
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ // Turns out this is the one that actually makes things work.
+ // Kerning is still screwed up, however.
+ g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+// g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+// RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
+// g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+// RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
+
// g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
// RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
}
@@ -1214,6 +1235,8 @@ public class PGraphicsJava2D extends PGraphics {
RenderingHints.VALUE_ANTIALIAS_OFF);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
@@ -1247,15 +1270,25 @@ public class PGraphicsJava2D extends PGraphics {
// 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)) ||
@@ -1273,8 +1306,8 @@ public class PGraphicsJava2D extends PGraphics {
(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();
@@ -1300,17 +1333,18 @@ public class PGraphicsJava2D extends PGraphics {
class ImageCache {
boolean tinted;
int tintedColor;
- int tintedPixels[]; // one row of tinted pixels
+ int[] tintedTemp; // one row of tinted pixels
BufferedImage image;
+// BufferedImage compat;
- 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
@@ -1318,29 +1352,41 @@ public class PGraphicsJava2D extends PGraphics {
* 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;
@@ -1351,12 +1397,15 @@ public class PGraphicsJava2D extends PGraphics {
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 };
@@ -1364,16 +1413,17 @@ public class PGraphicsJava2D extends PGraphics {
// 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;
@@ -1385,7 +1435,7 @@ public class PGraphicsJava2D extends PGraphics {
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);
@@ -1397,7 +1447,7 @@ public class PGraphicsJava2D extends PGraphics {
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) |
@@ -1407,11 +1457,11 @@ public class PGraphicsJava2D extends PGraphics {
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...
@@ -1420,11 +1470,30 @@ public class PGraphicsJava2D extends PGraphics {
// 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;
this.tintedColor = tintColor;
+
+// GraphicsConfiguration gc = parent.getGraphicsConfiguration();
+// compat = gc.createCompatibleImage(image.getWidth(),
+// image.getHeight(),
+// Transparency.TRANSLUCENT);
+//
+// Graphics2D g = compat.createGraphics();
+// g.drawImage(image, 0, 0, null);
+// g.dispose();
}
}
@@ -1513,7 +1582,7 @@ public class PGraphicsJava2D extends PGraphics {
@Override
public float textDescent() {
if (textFont == null) {
- defaultFontOrDeath("textAscent");
+ defaultFontOrDeath("textDescent");
}
Font font = (Font) textFont.getNative();
//if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) {
@@ -1552,7 +1621,7 @@ public class PGraphicsJava2D extends PGraphics {
@Override
public void textSize(float size) {
if (textFont == null) {
- defaultFontOrDeath("textAscent", size);
+ defaultFontOrDeath("textSize", size);
}
// if a native version available, derive this font
@@ -1564,9 +1633,24 @@ public class PGraphicsJava2D extends PGraphics {
Font font = (Font) textFont.getNative();
//if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) {
if (font != null) {
- Font dfont = font.deriveFont(size);
- g2.setFont(dfont);
- textFont.setNative(dfont);
+ Map map =
+ new Hashtable();
+ map.put(TextAttribute.SIZE, size);
+ map.put(TextAttribute.KERNING,
+ TextAttribute.KERNING_ON);
+// map.put(TextAttribute.TRACKING,
+// TextAttribute.TRACKING_TIGHT);
+ font = font.deriveFont(map);
+ g2.setFont(font);
+ textFont.setNative(font);
+
+// Font dfont = font.deriveFont(size);
+//// Map attrs = dfont.getAttributes();
+//// for (TextAttribute ta : attrs.keySet()) {
+//// System.out.println(ta + " -> " + attrs.get(ta));
+//// }
+// g2.setFont(dfont);
+// textFont.setNative(dfont);
}
// take care of setting the textSize and textLeading vars
@@ -1584,6 +1668,10 @@ public class PGraphicsJava2D extends PGraphics {
@Override
protected float textWidthImpl(char buffer[], int start, int stop) {
+ if (textFont == null) {
+ defaultFontOrDeath("textWidth");
+ }
+
Font font = (Font) textFont.getNative();
//if (font != null && (textFont.isStream() || hints[ENABLE_NATIVE_FONTS])) {
if (font != null) {
@@ -1673,31 +1761,28 @@ public class PGraphicsJava2D extends PGraphics {
RenderingHints.VALUE_ANTIALIAS_ON :
RenderingHints.VALUE_ANTIALIAS_OFF);
- //System.out.println("setting frac metrics");
- //g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
- // RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
g2.setColor(fillColorObject);
+
int length = stop - start;
+ if (length != 0) {
g2.drawChars(buffer, start, length, (int) (x + 0.5f), (int) (y + 0.5f));
+ // better to use round here? also, drawChars now just calls drawString
+// g2.drawString(new String(buffer, start, stop - start), Math.round(x), Math.round(y));
+
// better to use drawString() with floats? (nope, draws the same)
//g2.drawString(new String(buffer, start, length), x, y);
- // this didn't seem to help the scaling issue
- // and creates garbage because of the new temporary object
- //java.awt.font.GlyphVector gv = textFontNative.createGlyphVector(g2.getFontRenderContext(), new String(buffer, start, stop));
- //g2.drawGlyphVector(gv, x, y);
-
- // System.out.println("text() " + new String(buffer, start, stop));
+ // this didn't seem to help the scaling issue, and creates garbage
+ // because of a fairly heavyweight new temporary object
+// java.awt.font.GlyphVector gv =
+// font.createGlyphVector(g2.getFontRenderContext(), new String(buffer, start, stop - start));
+// g2.drawGlyphVector(gv, x, y);
+ }
// return to previous smoothing state if it was changed
//g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, textAntialias);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialias);
-// textX = x + textWidthImpl(buffer, start, stop);
-// textY = y;
-// textZ = 0; // this will get set by the caller if non-zero
-
} else { // otherwise just do the default
super.textLineImpl(buffer, start, stop, x, y);
}
@@ -2295,7 +2380,7 @@ public class PGraphicsJava2D extends PGraphics {
if (primarySurface) {
// 'offscreen' will probably be removed in the next release
if (useOffscreen) {
- raster = ((BufferedImage) offscreen).getRaster();
+ raster = offscreen.getRaster();
} else if (image instanceof VolatileImage) {
// when possible, we'll try VolatileImage
raster = ((VolatileImage) image).getSnapshot().getRaster();
@@ -2326,7 +2411,15 @@ public class PGraphicsJava2D extends PGraphics {
pixels = new int[width * height];
}
- getRaster().getDataElements(0, 0, width, height, pixels);
+ 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();
@@ -2395,8 +2488,12 @@ public class PGraphicsJava2D extends PGraphics {
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];
}
@@ -2422,6 +2519,10 @@ public class PGraphicsJava2D extends PGraphics {
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
@@ -2432,7 +2533,15 @@ public class PGraphicsJava2D extends PGraphics {
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/PGraphicsRetina2D.java b/core/src/processing/core/PGraphicsRetina2D.java
index 44c058942..786e3ba6f 100644
--- a/core/src/processing/core/PGraphicsRetina2D.java
+++ b/core/src/processing/core/PGraphicsRetina2D.java
@@ -87,11 +87,19 @@ public class PGraphicsRetina2D extends PGraphicsJava2D {
// FRAME
+
+ @Override
+ public boolean canDraw() {
+ return parent.getGraphicsConfiguration() != null;
+ }
+
+
@Override
public void beginDraw() {
// g2 = (Graphics2D) parent.getGraphics();
GraphicsConfiguration gc = parent.getGraphicsConfiguration();
+
// if (false) {
// if (image == null || ((VolatileImage) image).validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
// image = gc.createCompatibleVolatileImage(width*2, height*2);
diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java
index e3994c91e..430d67228 100644
--- a/core/src/processing/core/PImage.java
+++ b/core/src/processing/core/PImage.java
@@ -477,7 +477,7 @@ public class PImage implements PConstants, Cloneable {
if (pixels == null || pixels.length != width*height) {
pixels = new int[width*height];
}
- isLoaded();
+ setLoaded();
}
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 40ec381f5..8420f72f6 100644
--- a/core/src/processing/core/PShape.java
+++ b/core/src/processing/core/PShape.java
@@ -167,6 +167,8 @@ public class PShape implements PConstants {
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;
diff --git a/core/src/processing/core/PShapeSVG.java b/core/src/processing/core/PShapeSVG.java
index 1be0b30d6..7bac4fb62 100644
--- a/core/src/processing/core/PShapeSVG.java
+++ b/core/src/processing/core/PShapeSVG.java
@@ -586,6 +586,8 @@ public class PShapeSVG extends PShape {
case 'm': // m - move to (relative)
cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
+ movetoX = cx;
+ movetoY = cy;
parsePathMoveto(cx, cy);
implicitCommand = 'l';
i += 3;
diff --git a/core/src/processing/core/PStyle.java b/core/src/processing/core/PStyle.java
index ccea03a42..7b27695cf 100644
--- a/core/src/processing/core/PStyle.java
+++ b/core/src/processing/core/PStyle.java
@@ -30,6 +30,8 @@ public class PStyle implements PConstants {
public int ellipseMode;
public int shapeMode;
+ public int blendMode;
+
public int colorMode;
public float colorModeX;
public float colorModeY;
diff --git a/core/src/processing/core/PVector.java b/core/src/processing/core/PVector.java
index ca25eb1db..49e54a0d0 100644
--- a/core/src/processing/core/PVector.java
+++ b/core/src/processing/core/PVector.java
@@ -161,7 +161,7 @@ public class PVector implements Serializable {
* @param x the x component of the vector
* @param y the y component of the vector
* @param z the z component of the vector
- * @brief Set the x, y, and z component of the vector
+ * @brief Set the components of the vector
*/
public void set(float x, float y, float z) {
this.x = x;
@@ -170,11 +170,8 @@ public class PVector implements Serializable {
}
/**
- *
- * @webref pvector:method
* @param x the x component of the vector
* @param y the y component of the vector
- * @brief Set the x, y components of the vector
*/
public void set(float x, float y) {
this.x = x;
@@ -322,7 +319,7 @@ public class PVector implements Serializable {
* @webref pvector:method
* @usage web_application
* @brief Make a new 2D unit vector from an angle
- * @param angle the angle
+ * @param angle the angle in radians
* @return the new unit PVector
*/
static public PVector fromAngle(float angle) {
@@ -880,6 +877,7 @@ public class PVector implements Serializable {
* @brief Linear interpolate the vector to another vector
* @param v the vector to lerp to
* @param amt The amount of interpolation; some value between 0.0 (old vector) and 1.0 (new vector). 0.1 is very near the new vector. 0.5 is halfway in between.
+ * @see PApplet#lerp(float, float, float)
*/
public void lerp(PVector v, float amt) {
x = PApplet.lerp(x,v.x,amt);
diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java
index 91b2b7538..e9b902396 100644
--- a/core/src/processing/data/FloatDict.java
+++ b/core/src/processing/data/FloatDict.java
@@ -53,18 +53,16 @@ public class FloatDict {
* @nowebref
*/
public FloatDict(BufferedReader reader) {
-// public FloatHash(PApplet parent, String filename) {
String[] lines = PApplet.loadStrings(reader);
keys = new String[lines.length];
values = new float[lines.length];
-// boolean csv = (lines[0].indexOf('\t') == -1);
for (int i = 0; i < lines.length; i++) {
-// String[] pieces = csv ? Table.splitLineCSV(lines[i]) : PApplet.split(lines[i], '\t');
String[] pieces = PApplet.split(lines[i], '\t');
if (pieces.length == 2) {
keys[count] = pieces[0];
values[count] = PApplet.parseFloat(pieces[1]);
+ indices.put(pieces[0], count);
count++;
}
}
@@ -518,7 +516,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];
diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java
index 4cc3d927f..b581eaecf 100644
--- a/core/src/processing/data/IntDict.java
+++ b/core/src/processing/data/IntDict.java
@@ -76,18 +76,16 @@ public class IntDict {
* @nowebref
*/
public IntDict(BufferedReader reader) {
-// public IntHash(PApplet parent, String filename) {
String[] lines = PApplet.loadStrings(reader);
keys = new String[lines.length];
values = new int[lines.length];
-// boolean csv = (lines[0].indexOf('\t') == -1);
for (int i = 0; i < lines.length; i++) {
-// String[] pieces = csv ? Table.splitLineCSV(lines[i]) : PApplet.split(lines[i], '\t');
String[] pieces = PApplet.split(lines[i], '\t');
if (pieces.length == 2) {
keys[count] = pieces[0];
values[count] = PApplet.parseInt(pieces[1]);
+ indices.put(pieces[0], count);
count++;
}
}
@@ -526,7 +524,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];
diff --git a/core/src/processing/data/IntList.java b/core/src/processing/data/IntList.java
index 1b8860fcc..78775be3f 100644
--- a/core/src/processing/data/IntList.java
+++ b/core/src/processing/data/IntList.java
@@ -771,6 +771,13 @@ public class IntList implements Iterable {
}
+ public void print() {
+ for (int i = 0; i < size(); i++) {
+ System.out.format("[%d] %d%n", i, data[i]);
+ }
+ }
+
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/core/src/processing/data/JSONArray.java b/core/src/processing/data/JSONArray.java
index c25ac93f3..0e665c805 100644
--- a/core/src/processing/data/JSONArray.java
+++ b/core/src/processing/data/JSONArray.java
@@ -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 0b1c1127c..69add3837 100644
--- a/core/src/processing/data/JSONObject.java
+++ b/core/src/processing/data/JSONObject.java
@@ -1644,10 +1644,10 @@ public class JSONObject {
return value.toString();
}
if (value instanceof Map) {
- return new JSONObject((Map)value).toString();
+ return new JSONObject(value).toString();
}
if (value instanceof Collection) {
- return new JSONArray((Collection)value).toString();
+ return new JSONArray(value).toString();
}
if (value.getClass().isArray()) {
return new JSONArray(value).toString();
@@ -1683,13 +1683,13 @@ public class JSONObject {
}
if (object instanceof Collection) {
- return new JSONArray((Collection)object);
+ return new JSONArray(object);
}
if (object.getClass().isArray()) {
return new JSONArray(object);
}
if (object instanceof Map) {
- return new JSONObject((Map)object);
+ return new JSONObject(object);
}
Package objectPackage = object.getClass().getPackage();
String objectPackageName = objectPackage != null
@@ -1732,9 +1732,9 @@ public class JSONObject {
} else if (value instanceof JSONArray) {
((JSONArray) value).write(writer, indentFactor, indent);
} else if (value instanceof Map) {
- new JSONObject((Map) value).write(writer, indentFactor, indent);
+ new JSONObject(value).write(writer, indentFactor, indent);
} else if (value instanceof Collection) {
- new JSONArray((Collection) value).write(writer, indentFactor,
+ new JSONArray(value).write(writer, indentFactor,
indent);
} else if (value.getClass().isArray()) {
new JSONArray(value).write(writer, indentFactor, indent);
@@ -1790,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) {
@@ -1801,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..38b2175eb 100644
--- a/core/src/processing/data/StringDict.java
+++ b/core/src/processing/data/StringDict.java
@@ -63,6 +63,7 @@ public class StringDict {
if (pieces.length == 2) {
keys[count] = pieces[0];
values[count] = pieces[1];
+ indices.put(keys[count], count);
count++;
}
}
@@ -316,7 +317,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/Table.java b/core/src/processing/data/Table.java
index 4f8650a21..d98a9db51 100644
--- a/core/src/processing/data/Table.java
+++ b/core/src/processing/data/Table.java
@@ -1165,7 +1165,12 @@ public class Table {
output.writeDouble(row.getDouble(col));
break;
case CATEGORY:
- output.writeInt(columnCategories[col].index(row.getString(col)));
+ String peace = row.getString(col);
+ if (peace.equals(missingString)) {
+ output.writeInt(missingCategory);
+ } else {
+ output.writeInt(columnCategories[col].index(peace));
+ }
break;
}
}
@@ -1859,35 +1864,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;
}
@@ -2087,7 +2092,12 @@ public class Table {
if (piece == null) {
indexData[row] = missingCategory;
} else {
- indexData[row] = columnCategories[col].index(String.valueOf(piece));
+ String peace = String.valueOf(piece);
+ if (peace.equals(missingString)) { // missingString might be null
+ indexData[row] = missingCategory;
+ } else {
+ indexData[row] = columnCategories[col].index(peace);
+ }
}
break;
default:
@@ -2933,6 +2943,9 @@ public class Table {
}
+ /**
+ * Treat entries with this string as "missing". Also used for categorial.
+ */
public void setMissingString(String value) {
missingString = value;
}
@@ -3562,6 +3575,7 @@ public class Table {
read(input);
}
+ /** gets the index, and creates one if it doesn't already exist. */
int index(String key) {
Integer value = dataToIndex.get(key);
if (value != null) {
@@ -4131,7 +4145,12 @@ public class Table {
}
break;
case CATEGORY:
- output.writeInt(columnCategories[col].index(pieces[col]));
+ String peace = pieces[col];
+ if (peace.equals(missingString)) {
+ output.writeInt(missingCategory);
+ } else {
+ output.writeInt(columnCategories[col].index(peace));
+ }
break;
}
}
diff --git a/core/src/processing/data/XML.java b/core/src/processing/data/XML.java
index 28023b768..27ce09342 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);
}
@@ -233,6 +260,11 @@ public class XML implements Serializable {
// }
+ public boolean save(File file) {
+ return save(file, null);
+ }
+
+
public boolean save(File file, String options) {
PrintWriter writer = PApplet.createWriter(file);
boolean result = write(writer);
diff --git a/core/src/processing/event/MouseEvent.java b/core/src/processing/event/MouseEvent.java
index ce48658fb..bde328ff3 100644
--- a/core/src/processing/event/MouseEvent.java
+++ b/core/src/processing/event/MouseEvent.java
@@ -117,4 +117,33 @@ public class MouseEvent extends Event {
// public void setClickCount(int clickCount) {
// this.clickCount = clickCount;
// }
+
+ private String actionString() {
+ switch (action) {
+ default:
+ return "UNKNOWN";
+ case CLICK:
+ return "CLICK";
+ case DRAG:
+ return "DRAG";
+ case ENTER:
+ return "ENTER";
+ case EXIT:
+ return "EXIT";
+ case MOVE:
+ return "MOVE";
+ case PRESS:
+ return "PRESS";
+ case RELEASE:
+ return "RELEASE";
+ case WHEEL:
+ return "WHEEL";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("",
+ actionString(), x, y, count, button);
+ }
}
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/FontTexture.java b/core/src/processing/opengl/FontTexture.java
index 2a9fbadeb..8c1c66f5d 100644
--- a/core/src/processing/opengl/FontTexture.java
+++ b/core/src/processing/opengl/FontTexture.java
@@ -63,8 +63,9 @@ class FontTexture implements PConstants {
protected TextureInfo[] glyphTexinfos;
protected HashMap texinfoMap;
+
public FontTexture(PGraphicsOpenGL pg, PFont font, boolean is3D) {
- pgl = PGraphicsOpenGL.pgl;
+ pgl = pg.pgl;
this.is3D = is3D;
initTexture(pg, font);
@@ -130,15 +131,15 @@ class FontTexture implements PConstants {
if (is3D) {
// Bilinear sampling ensures that the texture doesn't look pixelated
// either when it is magnified or minified...
- tex = new Texture(w, h, new Texture.Parameters(ARGB, Texture.BILINEAR,
- false));
+ tex = new Texture(pg, w, h,
+ new Texture.Parameters(ARGB, Texture.BILINEAR, false));
} else {
// ...however, the effect of bilinear sampling is to add some blurriness
// to the text in its original size. In 2D, we assume that text will be
// shown at its original size, so linear sampling is chosen instead (which
// only affects minimized text).
- tex = new Texture(w, h, new Texture.Parameters(ARGB, Texture.LINEAR,
- false));
+ tex = new Texture(pg, w, h,
+ new Texture.Parameters(ARGB, Texture.LINEAR, false));
}
if (textures == null) {
diff --git a/core/src/processing/opengl/FrameBuffer.java b/core/src/processing/opengl/FrameBuffer.java
index 8821861c9..31d50f559 100644
--- a/core/src/processing/opengl/FrameBuffer.java
+++ b/core/src/processing/opengl/FrameBuffer.java
@@ -40,6 +40,7 @@ import java.nio.IntBuffer;
*/
public class FrameBuffer implements PConstants {
+ protected PGraphicsOpenGL pg;
protected PGL pgl;
protected int context; // The context that created this framebuffer.
@@ -67,16 +68,17 @@ public class FrameBuffer implements PConstants {
protected IntBuffer pixelBuffer;
- FrameBuffer() {
- pgl = PGraphicsOpenGL.pgl;
+ FrameBuffer(PGraphicsOpenGL pg) {
+ this.pg = pg;
+ pgl = pg.pgl;
context = pgl.createEmptyContext();
}
- FrameBuffer(int w, int h, int samples, int colorBuffers,
- int depthBits, int stencilBits, boolean packedDepthStencil,
- boolean screen) {
- this();
+ FrameBuffer(PGraphicsOpenGL pg, int w, int h, int samples, int colorBuffers,
+ int depthBits, int stencilBits, boolean packedDepthStencil,
+ boolean screen) {
+ this(pg);
glFbo = 0;
glDepth = 0;
@@ -136,13 +138,13 @@ public class FrameBuffer implements PConstants {
}
- FrameBuffer(int w, int h) {
- this(w, h, 1, 1, 0, 0, false, false);
+ FrameBuffer(PGraphicsOpenGL pg, int w, int h) {
+ this(pg, w, h, 1, 1, 0, 0, false, false);
}
- FrameBuffer(int w, int h, boolean screen) {
- this(w, h, 1, 1, 0, 0, false, screen);
+ FrameBuffer(PGraphicsOpenGL pg, int w, int h, boolean screen) {
+ this(pg, w, h, 1, 1, 0, 0, false, screen);
}
@@ -172,36 +174,47 @@ public class FrameBuffer implements PConstants {
}
public void clear() {
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
pgl.clearDepth(1);
pgl.clearStencil(0);
pgl.clearColor(0, 0, 0, 0);
pgl.clear(PGL.DEPTH_BUFFER_BIT |
PGL.STENCIL_BUFFER_BIT |
PGL.COLOR_BUFFER_BIT);
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
- public void copy(FrameBuffer dest, FrameBuffer current) {
- pgl.bindFramebuffer(PGL.READ_FRAMEBUFFER, this.glFbo);
- pgl.bindFramebuffer(PGL.DRAW_FRAMEBUFFER, dest.glFbo);
+ public void copyColor(FrameBuffer dest) {
+ copy(dest, PGL.COLOR_BUFFER_BIT);
+ }
+
+ public void copyDepth(FrameBuffer dest) {
+ copy(dest, PGL.DEPTH_BUFFER_BIT);
+ }
+
+ public void copyStencil(FrameBuffer dest) {
+ copy(dest, PGL.STENCIL_BUFFER_BIT);
+ }
+
+ public void copy(FrameBuffer dest, int mask) {
+ pgl.bindFramebufferImpl(PGL.READ_FRAMEBUFFER, this.glFbo);
+ pgl.bindFramebufferImpl(PGL.DRAW_FRAMEBUFFER, dest.glFbo);
pgl.blitFramebuffer(0, 0, this.width, this.height,
- 0, 0, dest.width, dest.height,
- PGL.COLOR_BUFFER_BIT, PGL.NEAREST);
- pgl.bindFramebuffer(PGL.READ_FRAMEBUFFER, current.glFbo);
- pgl.bindFramebuffer(PGL.DRAW_FRAMEBUFFER, current.glFbo);
+ 0, 0, dest.width, dest.height, mask, PGL.NEAREST);
+ pgl.bindFramebufferImpl(PGL.READ_FRAMEBUFFER, pg.getCurrentFB().glFbo);
+ pgl.bindFramebufferImpl(PGL.DRAW_FRAMEBUFFER, pg.getCurrentFB().glFbo);
}
public void bind() {
- pgl.bindFramebuffer(PGL.FRAMEBUFFER, glFbo);
+ pgl.bindFramebufferImpl(PGL.FRAMEBUFFER, glFbo);
}
public void disableDepthTest() {
noDepth = true;
}
- public void finish(PGraphicsOpenGL pg) {
+ public void finish() {
if (noDepth) {
// No need to clear depth buffer because depth testing was disabled.
if (pg.getHint(ENABLE_DEPTH_TEST)) {
@@ -271,8 +284,8 @@ public class FrameBuffer implements PConstants {
colorBufferTex[i] = textures[i];
}
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
// Making sure nothing is attached.
for (int i = 0; i < numColorBuffers; i++) {
@@ -288,7 +301,7 @@ public class FrameBuffer implements PConstants {
pgl.validateFramebuffer();
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
@@ -300,8 +313,8 @@ public class FrameBuffer implements PConstants {
colorBufferTex[i1] = tmp;
}
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
for (int i = 0; i < numColorBuffers; i++) {
pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0 + i,
colorBufferTex[i].glTarget,
@@ -309,7 +322,7 @@ public class FrameBuffer implements PConstants {
}
pgl.validateFramebuffer();
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
@@ -345,7 +358,7 @@ public class FrameBuffer implements PConstants {
glFbo = 0;
} else {
//create the FBO object...
- glFbo = PGraphicsOpenGL.createFrameBufferObject(context);
+ glFbo = PGraphicsOpenGL.createFrameBufferObject(context, pgl);
// ... and then create the rest of the stuff.
if (multisample) {
@@ -420,17 +433,17 @@ public class FrameBuffer implements PConstants {
protected void createColorBufferMultisample() {
if (screenFb) return;
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
- glMultisample = PGraphicsOpenGL.createRenderBufferObject(context);
+ glMultisample = PGraphicsOpenGL.createRenderBufferObject(context, pgl);
pgl.bindRenderbuffer(PGL.RENDERBUFFER, glMultisample);
pgl.renderbufferStorageMultisample(PGL.RENDERBUFFER, nsamples,
PGL.RGBA8, width, height);
pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0,
PGL.RENDERBUFFER, glMultisample);
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
@@ -441,10 +454,10 @@ public class FrameBuffer implements PConstants {
throw new RuntimeException("PFramebuffer: size undefined.");
}
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
- glDepthStencil = PGraphicsOpenGL.createRenderBufferObject(context);
+ glDepthStencil = PGraphicsOpenGL.createRenderBufferObject(context, pgl);
pgl.bindRenderbuffer(PGL.RENDERBUFFER, glDepthStencil);
if (multisample) {
@@ -460,7 +473,7 @@ public class FrameBuffer implements PConstants {
pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.STENCIL_ATTACHMENT,
PGL.RENDERBUFFER, glDepthStencil);
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
@@ -471,10 +484,10 @@ public class FrameBuffer implements PConstants {
throw new RuntimeException("PFramebuffer: size undefined.");
}
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
- glDepth = PGraphicsOpenGL.createRenderBufferObject(context);
+ glDepth = PGraphicsOpenGL.createRenderBufferObject(context, pgl);
pgl.bindRenderbuffer(PGL.RENDERBUFFER, glDepth);
int glConst = PGL.DEPTH_COMPONENT16;
@@ -496,7 +509,7 @@ public class FrameBuffer implements PConstants {
pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.DEPTH_ATTACHMENT,
PGL.RENDERBUFFER, glDepth);
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
@@ -507,10 +520,10 @@ public class FrameBuffer implements PConstants {
throw new RuntimeException("PFramebuffer: size undefined.");
}
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(this);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(this);
- glStencil = PGraphicsOpenGL.createRenderBufferObject(context);
+ glStencil = PGraphicsOpenGL.createRenderBufferObject(context, pgl);
pgl.bindRenderbuffer(PGL.RENDERBUFFER, glStencil);
int glConst = PGL.STENCIL_INDEX1;
@@ -531,7 +544,7 @@ public class FrameBuffer implements PConstants {
pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.STENCIL_ATTACHMENT,
PGL.RENDERBUFFER, glStencil);
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
}
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/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 942ad20f0..806ef8fc0 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,83 @@
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 Thread glThread;
- /** The rendering context (holds rendering state info) */
- public static GLContext context;
+ /** ID of the GL context associated to the surface **/
+ protected int glContext;
- /** The canvas where OpenGL rendering takes place */
- public static Canvas canvas;
+ /** true if this is the GL interface for a primary surface PGraphics */
+ public boolean primaryPGL;
- /** 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 +107,191 @@ 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 boolean fboLayerRequested = false;
+ protected boolean fboLayerCreated = false;
+ protected boolean fboLayerInUse = false;
+ protected boolean firstFrame = true;
+ protected int reqNumSamples;
+ protected int numSamples;
+ protected IntBuffer glColorFbo;
+ protected IntBuffer glMultiFbo;
+ protected IntBuffer glColorBuf;
+ protected IntBuffer glColorTex;
+ protected IntBuffer glDepthStencil;
+ protected IntBuffer glDepth;
+ protected IntBuffer glStencil;
+ protected int fboWidth, fboHeight;
+ protected 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 boolean loadedTex2DShader = false;
+ protected int tex2DShaderProgram;
+ protected int tex2DVertShader;
+ protected int tex2DFragShader;
+ protected int tex2DShaderContext;
+ protected int tex2DVertLoc;
+ protected int tex2DTCoordLoc;
+ protected int tex2DSamplerLoc;
+ protected int tex2DGeoVBO;
+
+ protected boolean loadedTexRectShader = false;
+ protected int texRectShaderProgram;
+ protected int texRectVertShader;
+ protected int texRectFragShader;
+ protected int texRectShaderContext;
+ protected int texRectVertLoc;
+ protected int texRectTCoordLoc;
+ protected int texRectSamplerLoc;
+ protected int texRectGeoVBO;
+
+ protected 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 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 boolean[] texturingTargets = { false, false };
+
+ /** Used to keep track of which textures are bound to each target */
+ protected int maxTexUnits;
+ protected int activeTexUnit = 0;
+ protected 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;
+
+ protected static final String NONPRIMARY_ERROR =
+ "The renderer is trying to call a PGL function that can only be called on a primary PGL. " +
+ "This is most likely due to a bug in the renderer's code, please report it with an " +
+ "issue on Processing's github page https://github.com/processing/processing/issues?state=open " +
+ "if using any of the built-in OpenGL renderers. If you are using a contributed " +
+ "library, contact the library's developers.";
+
+ // ........................................................
+
+ // 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,206 +314,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 viewBuffer;
-
- protected IntBuffer colorBuffer;
- protected FloatBuffer depthBuffer;
- protected ByteBuffer stencilBuffer;
-
- protected float[] projMatrix;
- protected float[] mvMatrix;
-
- ///////////////////////////////////////////////////////////
-
- // 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 TEXUNIT_ERROR =
- "Number of texture units not supported by this hardware (or driver)" + WIKI;
-
-
- ///////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////
// 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);
@@ -473,150 +345,28 @@ public class PGL {
}
- 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;
- }
+ public void setPrimary(boolean primary) {
+ primaryPGL = primary;
}
- 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);
- }
+ /**
+ * Return the native canvas the OpenGL context associated to this PGL object
+ * is rendering to (if any).
+ */
+ public abstract Object getCanvas();
- 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 setFps(float fps);
- // 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);
+ protected abstract void initSurface(int antialias);
- pg.parent.setLayout(new BorderLayout());
- pg.parent.add(canvasAWT, BorderLayout.CENTER);
- canvasAWT.requestFocusInWindow();
- pg.parent.removeListeners(pg.parent);
- pg.parent.addListeners(canvasAWT);
+ protected abstract void reinitSurface();
- 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);
- }
-
- canvas.setFocusTraversalKeysEnabled(false);
-
- fboLayerCreated = false;
- fboLayerInUse = false;
- firstFrame = true;
-
- setFps = false;
- }
+ protected abstract void registerListeners();
protected void deleteSurface() {
@@ -630,75 +380,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();
+ protected boolean isFBOBacked() {;
+ return fboLayerInUse;
}
@@ -712,25 +423,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);
}
@@ -749,64 +452,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(pg);
+ 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(pg);
+ 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;
}
@@ -814,44 +486,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);
}
}
}
@@ -859,35 +510,130 @@ 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) {
+ bindFramebufferImpl(READ_FRAMEBUFFER, glMultiFbo.get(0));
+ bindFramebufferImpl(DRAW_FRAMEBUFFER, glColorFbo.get(0));
+ blitFramebuffer(0, 0, fboWidth, fboHeight,
+ 0, 0, fboWidth, fboHeight,
+ COLOR_BUFFER_BIT, NEAREST);
}
}
- protected int qualityToSamples(int quality) {
- if (quality <= 1) {
- return 1;
+ ///////////////////////////////////////////////////////////
+
+ // Frame rendering
+
+
+ protected void beginDraw(boolean clear0) {
+ if (needFBOLayer(clear0)) {
+ if (!fboLayerCreated) createFBOLayer();
+
+ bindFramebufferImpl(FRAMEBUFFER, glColorFbo.get(0));
+ framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0,
+ TEXTURE_2D, glColorTex.get(backTex), 0);
+
+ if (1 < numSamples) {
+ bindFramebufferImpl(FRAMEBUFFER, glMultiFbo.get(0));
+ }
+
+ if (firstFrame) {
+ // No need to draw back color buffer because we are in the first frame.
+ int argb = pg.backgroundColor;
+ float a = ((argb >> 24) & 0xff) / 255.0f;
+ float r = ((argb >> 16) & 0xff) / 255.0f;
+ float g = ((argb >> 8) & 0xff) / 255.0f;
+ float b = ((argb) & 0xff) / 255.0f;
+ clearColor(r, g, b, a);
+ clear(COLOR_BUFFER_BIT);
+ } else if (!clear0) {
+ // Render previous back texture (now is the front) as background,
+ // because no background() is being used ("incremental drawing")
+ drawTexture(TEXTURE_2D, glColorTex.get(frontTex),
+ fboWidth, fboHeight, pg.width, pg.height,
+ 0, 0, pg.width, pg.height,
+ 0, 0, pg.width, pg.height);
+ }
+
+ fboLayerInUse = true;
} else {
- // Number of samples is always an even number:
- int n = 2 * (quality / 2);
- return n;
+ fboLayerInUse = false;
+ }
+
+ if (firstFrame) {
+ firstFrame = false;
+ }
+
+ if (!USE_FBOLAYER_BY_DEFAULT) {
+ // The result of this assignment is the following: if the user requested
+ // at some point the use of the FBO layer, but subsequently didn't
+ // request it again, then the rendering won't render to the FBO layer if
+ // not needed by the condif, since it is slower than simple onscreen
+ // rendering.
+ fboLayerRequested = false;
}
}
- protected void createFBOLayer() {
+ protected void endDraw(boolean clear0) {
+ if (fboLayerInUse) {
+ syncBackTexture();
+
+ // Draw the contents of the back texture to the screen framebuffer.
+ bindFramebufferImpl(FRAMEBUFFER, 0);
+
+ 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);
+
+ // Swapping front and back textures.
+ int temp = frontTex;
+ frontTex = backTex;
+ backTex = temp;
+ }
+ }
+
+
+ protected abstract void getGL(PGL pgl);
+
+
+ protected abstract boolean canDraw();
+
+
+ protected abstract void requestFocus();
+
+
+ protected abstract void requestDraw();
+
+
+ protected abstract void swapBuffers();
+
+
+ protected boolean threadIsCurrent() {
+ return Thread.currentThread() == glThread;
+ }
+
+
+ protected void beginGL() { }
+
+
+ protected void endGL() { }
+
+
+ private boolean needFBOLayer(boolean clear0) {
+ // TODO: need to revise this, on windows we might not want to use FBO layer
+ // even with anti-aliasing enabled...
+ return !clear0 || fboLayerRequested || 1 < numSamples;
+ }
+
+
+ private void createFBOLayer() {
String ext = getString(EXTENSIONS);
if (-1 < ext.indexOf("texture_non_power_of_two")) {
fboWidth = pg.width;
@@ -906,8 +652,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++) {
@@ -926,14 +672,14 @@ public class PGL {
frontTex = 1;
genFramebuffers(1, glColorFbo);
- bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
+ bindFramebufferImpl(FRAMEBUFFER, glColorFbo.get(0));
framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D,
glColorTex.get(backTex), 0);
if (multisample) {
// Creating multisampled FBO
genFramebuffers(1, glMultiFbo);
- bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
+ bindFramebufferImpl(FRAMEBUFFER, glMultiFbo.get(0));
// color render buffer...
genRenderbuffers(1, glColorBuf);
@@ -1022,225 +768,12 @@ public class PGL {
clearColor(r, g, b, a);
clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT);
- bindFramebuffer(FRAMEBUFFER, 0);
+ bindFramebufferImpl(FRAMEBUFFER, 0);
fboLayerCreated = true;
}
- ///////////////////////////////////////////////////////////
-
- // Frame rendering
-
-
- protected void beginDraw(boolean clear0) {
- if (!setFps) setFps(targetFps);
-
- if (USE_JOGL_FBOLAYER) return;
-
- if (needFBOLayer(clear0)) {
- if (!fboLayerCreated) createFBOLayer();
-
- bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
- framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0,
- TEXTURE_2D, glColorTex.get(backTex), 0);
-
- if (1 < numSamples) {
- bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
- }
-
- if (firstFrame) {
- // No need to draw back color buffer because we are in the first frame.
- int argb = pg.backgroundColor;
- float a = ((argb >> 24) & 0xff) / 255.0f;
- float r = ((argb >> 16) & 0xff) / 255.0f;
- float g = ((argb >> 8) & 0xff) / 255.0f;
- float b = ((argb) & 0xff) / 255.0f;
- clearColor(r, g, b, a);
- clear(COLOR_BUFFER_BIT);
- } else if (!clear0) {
- // Render previous back texture (now is the front) as background,
- // because no background() is being used ("incremental drawing")
- drawTexture(TEXTURE_2D, glColorTex.get(frontTex),
- fboWidth, fboHeight, pg.width, pg.height,
- 0, 0, pg.width, pg.height,
- 0, 0, pg.width, pg.height);
- }
-
- fboLayerInUse = true;
- } else {
- fboLayerInUse = false;
- }
-
- if (firstFrame) {
- firstFrame = false;
- }
-
- if (!USE_FBOLAYER_BY_DEFAULT) {
- // The result of this assignment is the following: if the user requested
- // at some point the use of the FBO layer, but subsequently didn't
- // request it again, then the rendering won't render to the FBO layer if
- // not needed by the condif, since it is slower than simple onscreen
- // rendering.
- fboLayerRequested = false;
- }
- }
-
-
- 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();
-
- // 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);
-
- // 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;
- }
- }
- }
-
-
- protected void requestFocus() {
- if (canvas != null) {
- canvas.requestFocus();
- }
- }
-
-
- protected boolean canDraw() {
- return pg.initialized && pg.parent.isDisplayable();
- }
-
-
- 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 void swapBuffers() {
- if (WINDOW_TOOLKIT == AWT) {
- canvasAWT.swapBuffers();
- } else if (WINDOW_TOOLKIT == NEWT) {
- window.swapBuffers();
- }
- }
-
-
- protected boolean threadIsCurrent() {
- return Thread.currentThread() == glThread;
- }
-
-
- protected boolean needFBOLayer(boolean clear0) {
- return !clear0 || fboLayerRequested || 1 < numSamples;
- }
-
-
- 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 endGL() {
- }
-
-
///////////////////////////////////////////////////////////
// Context interface
@@ -1252,144 +785,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;
}
@@ -1399,7 +795,7 @@ public class PGL {
protected boolean contextIsCurrent(int other) {
- return other == -1 || other == context.hashCode();
+ return other == -1 || other == glContext;
}
@@ -1456,7 +852,7 @@ public class PGL {
int initColor) {
int[] glcolor = new int[16 * 16];
Arrays.fill(glcolor, javaToNativeARGB(initColor));
- IntBuffer texels = PGL.allocateDirectIntBuffer(16 * 16);
+ IntBuffer texels = allocateDirectIntBuffer(16 * 16);
texels.put(glcolor);
texels.rewind();
for (int y = 0; y < height; y += 16) {
@@ -1515,29 +911,45 @@ 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);
- if (0 < tex2DVertShader && 0 < tex2DFragShader) {
- tex2DShaderProgram = createProgram(tex2DVertShader, tex2DFragShader);
+ protected PGL initTex2DShader() {
+ PGL ppgl = primaryPGL ? this : pg.getPrimaryPGL();
+
+ if (!ppgl.loadedTex2DShader || ppgl.tex2DShaderContext != ppgl.glContext) {
+ String vertSource = PApplet.join(texVertShaderSource, "\n");
+ String fragSource = PApplet.join(tex2DFragShaderSource, "\n");
+ ppgl.tex2DVertShader = createShader(VERTEX_SHADER, vertSource);
+ ppgl.tex2DFragShader = createShader(FRAGMENT_SHADER, fragSource);
+ if (0 < ppgl.tex2DVertShader && 0 < ppgl.tex2DFragShader) {
+ ppgl.tex2DShaderProgram = createProgram(ppgl.tex2DVertShader, ppgl.tex2DFragShader);
}
- if (0 < tex2DShaderProgram) {
- tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "inVertex");
- tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord");
+ if (0 < ppgl.tex2DShaderProgram) {
+ ppgl.tex2DVertLoc = getAttribLocation(ppgl.tex2DShaderProgram, "position");
+ ppgl.tex2DTCoordLoc = getAttribLocation(ppgl.tex2DShaderProgram, "texCoord");
+ ppgl.tex2DSamplerLoc = getUniformLocation(ppgl.tex2DShaderProgram, "texMap");
}
- loadedTex2DShader = true;
- tex2DShaderContext = context;
+ ppgl.loadedTex2DShader = true;
+ ppgl.tex2DShaderContext = ppgl.glContext;
+
+ genBuffers(1, intBuffer);
+ ppgl.tex2DGeoVBO = intBuffer.get(0);
+ bindBuffer(ARRAY_BUFFER, ppgl.tex2DGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
}
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
}
- if (0 < tex2DShaderProgram) {
+ return ppgl;
+ }
+
+
+ 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) {
+ PGL ppgl = initTex2DShader();
+
+ if (0 < ppgl.tex2DShaderProgram) {
// The texture overwrites anything drawn earlier.
boolean depthTest = getDepthTest();
disable(DEPTH_TEST);
@@ -1554,10 +966,10 @@ public class PGL {
getIntegerv(VIEWPORT, viewBuffer);
viewport(0, 0, scrW, scrH);
- useProgram(tex2DShaderProgram);
+ useProgram(ppgl.tex2DShaderProgram);
- enableVertexAttribArray(tex2DVertLoc);
- enableVertexAttribArray(tex2DTCoordLoc);
+ enableVertexAttribArray(ppgl.tex2DVertLoc);
+ enableVertexAttribArray(ppgl.tex2DTCoordLoc);
// Vertex coordinates of the textured quad are specified
// in normalized screen space (-1, 1):
@@ -1592,25 +1004,26 @@ public class PGL {
enabledTex = true;
}
bindTexture(TEXTURE_2D, id);
-
- bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+ uniform1i(ppgl.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(ARRAY_BUFFER, ppgl.tex2DGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, STATIC_DRAW);
+
+ vertexAttribPointer(ppgl.tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
+ vertexAttribPointer(ppgl.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);
}
- disableVertexAttribArray(tex2DVertLoc);
- disableVertexAttribArray(tex2DTCoordLoc);
+ disableVertexAttribArray(ppgl.tex2DVertLoc);
+ disableVertexAttribArray(ppgl.tex2DTCoordLoc);
useProgram(0);
@@ -1622,35 +1035,51 @@ public class PGL {
depthMask(depthMask);
viewport(viewBuffer.get(0), viewBuffer.get(1),
- viewBuffer.get(2),viewBuffer.get(3));
+ viewBuffer.get(2), viewBuffer.get(3));
}
}
+ protected PGL initTexRectShader() {
+ PGL ppgl = primaryPGL ? this : pg.getPrimaryPGL();
+
+ if (!ppgl.loadedTexRectShader || ppgl.texRectShaderContext != ppgl.glContext) {
+ String vertSource = PApplet.join(texVertShaderSource, "\n");
+ String fragSource = PApplet.join(texRectFragShaderSource, "\n");
+ ppgl.texRectVertShader = createShader(VERTEX_SHADER, vertSource);
+ ppgl.texRectFragShader = createShader(FRAGMENT_SHADER, fragSource);
+ if (0 < ppgl.texRectVertShader && 0 < ppgl.texRectFragShader) {
+ ppgl.texRectShaderProgram = createProgram(ppgl.texRectVertShader,
+ ppgl.texRectFragShader);
+ }
+ if (0 < ppgl.texRectShaderProgram) {
+ ppgl.texRectVertLoc = getAttribLocation(ppgl.texRectShaderProgram, "position");
+ ppgl.texRectTCoordLoc = getAttribLocation(ppgl.texRectShaderProgram, "texCoord");
+ ppgl.texRectSamplerLoc = getUniformLocation(ppgl.texRectShaderProgram, "texMap");
+ }
+ ppgl.loadedTexRectShader = true;
+ ppgl.texRectShaderContext = ppgl.glContext;
+
+ genBuffers(1, intBuffer);
+ ppgl.texRectGeoVBO = intBuffer.get(0);
+ bindBuffer(ARRAY_BUFFER, ppgl.texRectGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
+ }
+
+ return ppgl;
+ }
+
+
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;
- }
+ PGL ppgl = initTexRectShader();
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
}
- if (0 < texRectShaderProgram) {
+ if (0 < ppgl.texRectShaderProgram) {
// The texture overwrites anything drawn earlier.
boolean depthTest = getDepthTest();
disable(DEPTH_TEST);
@@ -1667,10 +1096,10 @@ public class PGL {
getIntegerv(VIEWPORT, viewBuffer);
viewport(0, 0, scrW, scrH);
- useProgram(texRectShaderProgram);
+ useProgram(ppgl.texRectShaderProgram);
- enableVertexAttribArray(texRectVertLoc);
- enableVertexAttribArray(texRectTCoordLoc);
+ enableVertexAttribArray(ppgl.texRectVertLoc);
+ enableVertexAttribArray(ppgl.texRectTCoordLoc);
// Vertex coordinates of the textured quad are specified
// in normalized screen space (-1, 1):
@@ -1705,25 +1134,26 @@ public class PGL {
enabledTex = true;
}
bindTexture(TEXTURE_RECTANGLE, id);
-
- bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+ uniform1i(ppgl.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(ARRAY_BUFFER, ppgl.texRectGeoVBO);
+ bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, STATIC_DRAW);
+
+ vertexAttribPointer(ppgl.texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
+ vertexAttribPointer(ppgl.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);
}
- disableVertexAttribArray(texRectVertLoc);
- disableVertexAttribArray(texRectTCoordLoc);
+ disableVertexAttribArray(ppgl.texRectVertLoc);
+ disableVertexAttribArray(ppgl.texRectTCoordLoc);
useProgram(0);
@@ -1735,7 +1165,7 @@ public class PGL {
depthMask(depthMask);
viewport(viewBuffer.get(0), viewBuffer.get(1),
- viewBuffer.get(2),viewBuffer.get(3));
+ viewBuffer.get(2), viewBuffer.get(3));
}
}
@@ -1787,7 +1217,7 @@ public class PGL {
* endian) to Java ARGB.
*/
protected static int nativeToJavaARGB(int color) {
- if (PGL.BIG_ENDIAN) { // RGBA to ARGB
+ if (BIG_ENDIAN) { // RGBA to ARGB
return (color >>> 8) | ((color << 24) & 0xFF000000);
// equivalent to
// ((color >> 8) & 0x00FFFFFF) | ((color << 24) & 0xFF000000)
@@ -2019,6 +1449,106 @@ public class PGL {
}
+ protected static int qualityToSamples(int quality) {
+ if (quality <= 1) {
+ return 1;
+ } else {
+ // Number of samples is always an even number:
+ int n = 2 * (quality / 2);
+ return n;
+ }
+ }
+
+
+ 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 static String[] convertFragmentSource(String[] fragSrc0,
+ int version0, int version1) {
+ if (version0 == 120 && version1 == 150) {
+ 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;
+ }
+ return fragSrc0;
+ }
+
+
+
+ protected static String[] convertVertexSource(String[] vertSrc0,
+ int version0, int version1) {
+ if (version0 == 120 && version1 == 150) {
+ 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;
+ }
+ return vertSrc0;
+ }
+
protected int createShader(int shaderType, String source) {
int shader = createShader(shaderType);
if (shader != 0) {
@@ -2121,13 +1651,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.
@@ -2138,9 +1676,64 @@ 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;
+ }
}
@@ -2175,7 +1768,7 @@ public class PGL {
protected static ByteBuffer allocateByteBuffer(byte[] arr) {
if (USE_DIRECT_BUFFERS) {
- return PGL.allocateDirectByteBuffer(arr.length);
+ return allocateDirectByteBuffer(arr.length);
} else {
return ByteBuffer.wrap(arr);
}
@@ -2186,7 +1779,7 @@ public class PGL {
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
- buf = PGL.allocateDirectByteBuffer(arr.length);
+ buf = allocateDirectByteBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
@@ -2264,7 +1857,7 @@ public class PGL {
protected static ShortBuffer allocateShortBuffer(short[] arr) {
if (USE_DIRECT_BUFFERS) {
- return PGL.allocateDirectShortBuffer(arr.length);
+ return allocateDirectShortBuffer(arr.length);
} else {
return ShortBuffer.wrap(arr);
}
@@ -2275,7 +1868,7 @@ public class PGL {
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
- buf = PGL.allocateDirectShortBuffer(arr.length);
+ buf = allocateDirectShortBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
@@ -2353,7 +1946,7 @@ public class PGL {
protected static IntBuffer allocateIntBuffer(int[] arr) {
if (USE_DIRECT_BUFFERS) {
- return PGL.allocateDirectIntBuffer(arr.length);
+ return allocateDirectIntBuffer(arr.length);
} else {
return IntBuffer.wrap(arr);
}
@@ -2364,7 +1957,7 @@ public class PGL {
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
- buf = PGL.allocateDirectIntBuffer(arr.length);
+ buf = allocateDirectIntBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
@@ -2441,7 +2034,7 @@ public class PGL {
protected static FloatBuffer allocateFloatBuffer(float[] arr) {
if (USE_DIRECT_BUFFERS) {
- return PGL.allocateDirectFloatBuffer(arr.length);
+ return allocateDirectFloatBuffer(arr.length);
} else {
return FloatBuffer.wrap(arr);
}
@@ -2452,7 +2045,7 @@ public class PGL {
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
- buf = PGL.allocateDirectFloatBuffer(arr.length);
+ buf = allocateDirectFloatBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
@@ -2512,271 +2105,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;
- }
- }
-
- 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 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);
- }
- 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();
}
@@ -2792,601 +2195,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 DEPTH_STENCIL = GL.GL_DEPTH_STENCIL;
+ public static int DEPTH_STENCIL;
- 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 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 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_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 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 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 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 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) {
- boolean needBeginOp = format != STENCIL_INDEX &&
- format != DEPTH_COMPONENT && format != DEPTH_STENCIL;
- if (needBeginOp) {
- PGraphicsOpenGL.pgCurrent.beginPixelsOp(PGraphicsOpenGL.OP_READ);
- }
+ public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer){
+ boolean pgCall = format != STENCIL_INDEX &&
+ format != DEPTH_COMPONENT && format != DEPTH_STENCIL;
+ if (pgCall) pg.beginReadPixels();
readPixelsImpl(x, y, width, height, format, type, buffer);
- if (needBeginOp) {
- PGraphicsOpenGL.pgCurrent.endPixelsOp();
- }
+ if (pgCall) 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();
@@ -3403,439 +2654,121 @@ 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);
+ pg.beginBindFramebuffer(target, framebuffer);
+ bindFramebufferImpl(target, framebuffer);
+ pg.endBindFramebuffer(target, framebuffer);
}
+ protected abstract void bindFramebufferImpl(int target, int 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 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 dd4089dca..b3fc4e890 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(0, width, -height, 0, -1, +1);
}
@@ -156,7 +156,8 @@ public class PGraphics2D extends PGraphicsOpenGL {
@Override
protected void defaultCamera() {
- super.camera(width/2f, height/2f);
+ cameraEyeX = cameraEyeY = cameraEyeZ = 0;
+ resetMatrix();
}
@@ -261,7 +262,7 @@ public class PGraphics2D extends PGraphicsOpenGL {
}
if (svg != null) {
- PShapeOpenGL p2d = PShapeOpenGL.createShape2D(pg.parent, svg);
+ PShapeOpenGL p2d = PShapeOpenGL.createShape2D((PGraphicsOpenGL)pg, svg);
return p2d;
} else {
return null;
@@ -276,7 +277,7 @@ public class PGraphics2D extends PGraphicsOpenGL {
@Override
public PShape createShape(PShape source) {
- return PShapeOpenGL.createShape2D(parent, source);
+ return PShapeOpenGL.createShape2D(this, source);
}
@@ -288,60 +289,31 @@ public class PGraphics2D extends PGraphicsOpenGL {
@Override
public PShape createShape(int type) {
- return createShapeImpl(parent, type);
+ return createShapeImpl(this, type);
}
@Override
public PShape createShape(int kind, float... p) {
- return createShapeImpl(parent, kind, p);
+ return createShapeImpl(this, kind, p);
}
- static protected PShapeOpenGL createShapeImpl(PApplet parent, int type) {
+ static protected PShapeOpenGL createShapeImpl(PGraphicsOpenGL pg, int type) {
PShapeOpenGL shape = null;
if (type == PConstants.GROUP) {
- shape = new PShapeOpenGL(parent, PConstants.GROUP);
+ shape = new PShapeOpenGL(pg, PConstants.GROUP);
} else if (type == PShape.PATH) {
- shape = new PShapeOpenGL(parent, PShape.PATH);
+ shape = new PShapeOpenGL(pg, PShape.PATH);
} else if (type == PShape.GEOMETRY) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
+ shape = new PShapeOpenGL(pg, 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;
}
- static protected PShapeOpenGL createShapeImpl(PApplet parent,
+ static protected PShapeOpenGL createShapeImpl(PGraphicsOpenGL pg,
int kind, float... p) {
PShapeOpenGL shape = null;
int len = p.length;
@@ -351,49 +323,49 @@ public class PGraphics2D extends PGraphicsOpenGL {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(POINT);
} else if (kind == LINE) {
if (len != 4) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(LINE);
} else if (kind == TRIANGLE) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(TRIANGLE);
} else if (kind == QUAD) {
if (len != 8) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, 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 = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
- if (len != 4) {
+ if (len != 4 && len != 5) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(ELLIPSE);
} else if (kind == ARC) {
if (len != 6 && len != 7) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(ARC);
} else if (kind == BOX) {
showWarning("Primitive not supported in 2D");
diff --git a/core/src/processing/opengl/PGraphics3D.java b/core/src/processing/opengl/PGraphics3D.java
index a60641dac..77edcc9f0 100644
--- a/core/src/processing/opengl/PGraphics3D.java
+++ b/core/src/processing/opengl/PGraphics3D.java
@@ -87,7 +87,20 @@ public class PGraphics3D extends PGraphicsOpenGL {
pushProjection();
ortho(0, width, 0, height, -1, +1);
pushMatrix();
- camera(width/2, height/2);
+
+ // Set camera for 2D rendering, it simply centers at (width/2, height/2)
+ float centerX = width/2;
+ float centerY = height/2;
+ modelview.reset();
+ modelview.translate(-centerX, -centerY);
+
+ modelviewInv.set(modelview);
+ modelviewInv.invert();
+
+ camera.set(modelview);
+ cameraInv.set(modelviewInv);
+
+ updateProjmodelview();
}
@@ -131,7 +144,7 @@ public class PGraphics3D extends PGraphicsOpenGL {
if (obj != null) {
int prevTextureMode = pg.textureMode;
pg.textureMode = NORMAL;
- PShapeOpenGL p3d = PShapeOpenGL.createShape3D(pg.parent, obj);
+ PShapeOpenGL p3d = PShapeOpenGL.createShape3D((PGraphicsOpenGL)pg, obj);
pg.textureMode = prevTextureMode;
return p3d;
} else {
@@ -147,7 +160,7 @@ public class PGraphics3D extends PGraphicsOpenGL {
@Override
public PShape createShape(PShape source) {
- return PShapeOpenGL.createShape3D(parent, source);
+ return PShapeOpenGL.createShape3D(this, source);
}
@@ -159,63 +172,31 @@ public class PGraphics3D extends PGraphicsOpenGL {
@Override
public PShape createShape(int type) {
- return createShapeImpl(parent, type);
+ return createShapeImpl(this, type);
}
@Override
public PShape createShape(int kind, float... p) {
- return createShapeImpl(parent, kind, p);
+ return createShapeImpl(this, kind, p);
}
- static protected PShapeOpenGL createShapeImpl(PApplet parent, int type) {
+ static protected PShapeOpenGL createShapeImpl(PGraphicsOpenGL pg, int type) {
PShapeOpenGL shape = null;
if (type == PConstants.GROUP) {
- shape = new PShapeOpenGL(parent, PConstants.GROUP);
+ shape = new PShapeOpenGL(pg, PConstants.GROUP);
} else if (type == PShape.PATH) {
- shape = new PShapeOpenGL(parent, PShape.PATH);
+ shape = new PShapeOpenGL(pg, PShape.PATH);
} else if (type == PShape.GEOMETRY) {
- shape = new PShapeOpenGL(parent, PShape.GEOMETRY);
+ shape = new PShapeOpenGL(pg, 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;
}
- static protected PShapeOpenGL createShapeImpl(PApplet parent,
+ static protected PShapeOpenGL createShapeImpl(PGraphicsOpenGL pg,
int kind, float... p) {
PShapeOpenGL shape = null;
int len = p.length;
@@ -225,63 +206,63 @@ public class PGraphics3D extends PGraphicsOpenGL {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(POINT);
} else if (kind == LINE) {
if (len != 4 && len != 6) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(LINE);
} else if (kind == TRIANGLE) {
if (len != 6) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(TRIANGLE);
} else if (kind == QUAD) {
if (len != 8) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, 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 = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(RECT);
} else if (kind == ELLIPSE) {
- if (len != 4) {
+ if (len != 4 && len != 5) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(ELLIPSE);
} else if (kind == ARC) {
if (len != 6 && len != 7) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(ARC);
} else if (kind == BOX) {
if (len != 1 && len != 3) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(BOX);
} else if (kind == SPHERE) {
if (len < 1 || 3 < len) {
showWarning("Wrong number of parameters");
return null;
}
- shape = new PShapeOpenGL(parent, PShape.PRIMITIVE);
+ shape = new PShapeOpenGL(pg, PShape.PRIMITIVE);
shape.setKind(SPHERE);
} else {
showWarning("Unrecognized primitive type");
diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java
index a0db323c3..12c6fe413 100644
--- a/core/src/processing/opengl/PGraphicsOpenGL.java
+++ b/core/src/processing/opengl/PGraphicsOpenGL.java
@@ -24,8 +24,6 @@ package processing.opengl;
import processing.core.*;
-import java.awt.Font;
-import java.awt.FontMetrics;
import java.net.URL;
import java.nio.*;
import java.util.*;
@@ -36,72 +34,13 @@ import java.util.*;
*/
public class PGraphicsOpenGL extends PGraphics {
/** Interface between Processing and OpenGL */
- public static PGL pgl;
-
- /** The main PApplet renderer. */
- protected static PGraphicsOpenGL pgPrimary = null;
+ public PGL pgl;
/** The renderer currently in use. */
- protected static PGraphicsOpenGL pgCurrent = null;
+ protected PGraphicsOpenGL currentPG;
/** Font cache for texture objects. */
- protected WeakHashMap fontMap =
- new WeakHashMap();
-
- // ........................................................
-
- static final String OPENGL_THREAD_ERROR =
- "Cannot run the OpenGL renderer outside the main thread, change your code" +
- "\nso the drawing calls are all inside the main thread, " +
- "\nor use the default renderer instead.";
- static final String BLEND_DRIVER_ERROR =
- "blendMode(%1$s) is not supported by this hardware (or driver)";
- static final String BLEND_RENDERER_ERROR =
- "blendMode(%1$s) is not supported by this renderer";
- static final String ALREADY_DRAWING_ERROR =
- "Already called beginDraw()";
- static final String NO_BEGIN_DRAW_ERROR =
- "Cannot call endDraw() before beginDraw()";
- static final String NESTED_DRAW_ERROR =
- "Already called drawing on another PGraphicsOpenGL object";
- static final String ALREADY_BEGAN_CONTOUR_ERROR =
- "Already called beginContour()";
- static final String NO_BEGIN_CONTOUR_ERROR =
- "Need to call beginContour() first";
- static final String UNSUPPORTED_SMOOTH_LEVEL_ERROR =
- "Smooth level %1$s is not available. Using %2$s instead";
- static final String UNSUPPORTED_SMOOTH_ERROR =
- "Smooth is not supported by this hardware (or driver)";
- static final String TOO_MANY_SMOOTH_CALLS_ERROR =
- "The smooth/noSmooth functions are being called too often.\n" +
- "This results in screen flickering, so they will be disabled\n" +
- "for the rest of the sketch's execution";
- static final String UNSUPPORTED_SHAPE_FORMAT_ERROR =
- "Unsupported shape format";
- 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 WRONG_SHADER_TYPE_ERROR =
- "shader() called with a wrong shader";
- static final String UNKNOWN_SHADER_KIND_ERROR =
- "Unknown shader kind";
- static final String NO_TEXLIGHT_SHADER_ERROR =
- "Your shader needs to be of TEXLIGHT type " +
- "to render this geometry properly, using default shader instead.";
- static final String NO_LIGHT_SHADER_ERROR =
- "Your shader needs to be of LIGHT type " +
- "to render this geometry properly, using default shader instead.";
- static final String NO_TEXTURE_SHADER_ERROR =
- "Your shader needs to be of TEXTURE type " +
- "to render this geometry properly, using default shader instead.";
- static final String NO_COLOR_SHADER_ERROR =
- "Your shader needs to be of COLOR type " +
- "to render this geometry properly, using default shader instead.";
- static final String TOO_LONG_STROKE_PATH_ERROR =
- "Stroke path is too long, some bevel triangles won't be added";
- static final String TESSELLATION_ERROR =
- "Tessellation Error: %1$s";
+ protected WeakHashMap fontMap;
// ........................................................
@@ -155,8 +94,8 @@ public class PGraphicsOpenGL extends PGraphics {
protected boolean pointBuffersCreated = false;
protected int pointBuffersContext;
- protected static final int INIT_VERTEX_BUFFER_SIZE = 256;
- protected static final int INIT_INDEX_BUFFER_SIZE = 512;
+ static protected final int INIT_VERTEX_BUFFER_SIZE = 256;
+ static protected final int INIT_INDEX_BUFFER_SIZE = 512;
// ........................................................
@@ -175,8 +114,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;
@@ -190,7 +127,7 @@ public class PGraphicsOpenGL extends PGraphics {
// ........................................................
- // GL objects:
+ // GL resources:
static protected HashMap glTextureObjects =
new HashMap();
@@ -231,32 +168,20 @@ public class PGraphicsOpenGL extends PGraphics {
PGraphicsOpenGL.class.getResource("PointVert.glsl");
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 URL maskShaderFragURL =
PGraphicsOpenGL.class.getResource("MaskFrag.glsl");
- static protected TextureShader maskShader;
- protected ColorShader colorShader;
- protected TextureShader textureShader;
- protected LightShader lightShader;
- protected TexlightShader texlightShader;
- protected LineShader lineShader;
- protected PointShader pointShader;
+ protected PShader defColorShader;
+ protected PShader defTextureShader;
+ protected PShader defLightShader;
+ protected PShader defTexlightShader;
+ protected PShader defLineShader;
+ protected PShader defPointShader;
+ protected PShader maskShader;
- // 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;
// ........................................................
@@ -264,8 +189,8 @@ public class PGraphicsOpenGL extends PGraphics {
protected InGeometry inGeo;
protected TessGeometry tessGeo;
- static protected Tessellator tessellator;
protected TexCache texCache;
+ static protected Tessellator tessellator;
// ........................................................
@@ -413,11 +338,11 @@ public class PGraphicsOpenGL extends PGraphics {
static protected final int FB_STACK_DEPTH = 16;
- static protected int fbStackDepth;
- static protected FrameBuffer[] fbStack = new FrameBuffer[FB_STACK_DEPTH];
- static protected FrameBuffer drawFramebuffer;
- static protected FrameBuffer readFramebuffer;
- static protected FrameBuffer currentFramebuffer;
+ protected int fbStackDepth;
+ protected FrameBuffer[] fbStack;
+ protected FrameBuffer drawFramebuffer;
+ protected FrameBuffer readFramebuffer;
+ protected FrameBuffer currentFramebuffer;
// .......................................................
@@ -493,7 +418,6 @@ public class PGraphicsOpenGL extends PGraphics {
protected boolean openContour = false;
protected boolean breakShape = false;
protected boolean defaultEdges = false;
- protected PImage textureImage0;
static protected final int EDGE_MIDDLE = 0;
static protected final int EDGE_START = 1;
@@ -518,22 +442,80 @@ public class PGraphicsOpenGL extends PGraphics {
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. */
static protected IntBuffer intBuffer;
static protected FloatBuffer floatBuffer;
+ // ........................................................
+
+ // Error strings:
+
+ static final String OPENGL_THREAD_ERROR =
+ "Cannot run the OpenGL renderer outside the main thread, change your code" +
+ "\nso the drawing calls are all inside the main thread, " +
+ "\nor use the default renderer instead.";
+ static final String BLEND_DRIVER_ERROR =
+ "blendMode(%1$s) is not supported by this hardware (or driver)";
+ static final String BLEND_RENDERER_ERROR =
+ "blendMode(%1$s) is not supported by this renderer";
+ static final String ALREADY_BEGAN_CONTOUR_ERROR =
+ "Already called beginContour()";
+ static final String NO_BEGIN_CONTOUR_ERROR =
+ "Need to call beginContour() first";
+ static final String UNSUPPORTED_SMOOTH_LEVEL_ERROR =
+ "Smooth level %1$s is not available. Using %2$s instead";
+ static final String UNSUPPORTED_SMOOTH_ERROR =
+ "Smooth is not supported by this hardware (or driver)";
+ static final String TOO_MANY_SMOOTH_CALLS_ERROR =
+ "The smooth/noSmooth functions are being called too often.\n" +
+ "This results in screen flickering, so they will be disabled\n" +
+ "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 cannot be used as a filter because is of type POINT or LINES";
+ 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 =
+ "Your shader needs to be of TEXLIGHT type " +
+ "to render this geometry properly, using default shader instead.";
+ static final String NO_LIGHT_SHADER_ERROR =
+ "Your shader needs to be of LIGHT type " +
+ "to render this geometry properly, using default shader instead.";
+ static final String NO_TEXTURE_SHADER_ERROR =
+ "Your shader needs to be of TEXTURE type " +
+ "to render this geometry properly, using default shader instead.";
+ static final String NO_COLOR_SHADER_ERROR =
+ "Your shader needs to be of COLOR type " +
+ "to render this geometry properly, using default shader instead.";
+ static final String TOO_LONG_STROKE_PATH_ERROR =
+ "Stroke path is too long, some bevel triangles won't be added";
+ static final String TESSELLATION_ERROR =
+ "Tessellation Error: %1$s";
+
//////////////////////////////////////////////////////////////
// INIT/ALLOCATE/FINISH
public PGraphicsOpenGL() {
- if (pgl == null) {
- pgl = new PGL(this);
- }
+ pgl = createPGL(this);
if (tessellator == null) {
tessellator = new Tessellator();
@@ -546,9 +528,9 @@ public class PGraphicsOpenGL extends PGraphics {
viewport = PGL.allocateIntBuffer(4);
- inGeo = newInGeometry(IMMEDIATE);
- tessGeo = newTessGeometry(IMMEDIATE);
- texCache = newTexCache();
+ inGeo = newInGeometry(this, IMMEDIATE);
+ tessGeo = newTessGeometry(this, IMMEDIATE);
+ texCache = newTexCache(this);
initialized = false;
}
@@ -557,7 +539,12 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void setPrimary(boolean primary) {
super.setPrimary(primary);
+ pgl.setPrimary(primary);
format = ARGB;
+ if (primary) {
+ fbStack = new FrameBuffer[FB_STACK_DEPTH];
+ fontMap = new WeakHashMap();
+ }
}
@@ -579,7 +566,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
@@ -590,10 +576,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;
}
@@ -637,17 +619,19 @@ 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();
- deletePointBuffers();
+ finalizePolyBuffers();
+ finalizeLineBuffers();
+ finalizePointBuffers();
deleteSurfaceTextures();
if (primarySurface) {
@@ -661,18 +645,19 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- deleteFinalizedGLResources();
+ deleteFinalizedGLResources(pgl);
- if (primarySurface) pgl.deleteSurface();
+ if (primarySurface) {
+ pgl.deleteSurface();
+ }
}
-// @Override
@Override
protected void finalize() throws Throwable {
try {
- deletePolyBuffers();
- deleteLineBuffers();
- deletePointBuffers();
+ finalizePolyBuffers();
+ finalizeLineBuffers();
+ finalizePointBuffers();
deleteSurfaceTextures();
if (!primarySurface) {
@@ -695,21 +680,44 @@ public class PGraphicsOpenGL extends PGraphics {
}
+ //////////////////////////////////////////////////////////////
+
+ // IMAGE METADATA FOR THIS RENDERER
+
+
+ @Override
+ public void setCache(PImage image, Object storage) {
+ getPrimaryPG().cacheMap.put(image, storage);
+ }
+
+
+ @Override
+ public Object getCache(PImage image) {
+ return getPrimaryPG().cacheMap.get(image);
+ }
+
+
+ @Override
+ public void removeCache(PImage image) {
+ getPrimaryPG().cacheMap.remove(image);
+ }
+
+
//////////////////////////////////////////////////////////////
protected void setFontTexture(PFont font, FontTexture fontTexture) {
- fontMap.put(font, fontTexture);
+ getPrimaryPG().fontMap.put(font, fontTexture);
}
protected FontTexture getFontTexture(PFont font) {
- return fontMap.get(font);
+ return getPrimaryPG().fontMap.get(font);
}
protected void removeFontTexture(PFont font) {
- fontMap.remove(font);
+ getPrimaryPG().fontMap.remove(font);
}
@@ -745,8 +753,8 @@ public class PGraphicsOpenGL extends PGraphics {
// Texture Objects -----------------------------------------------------------
- protected static int createTextureObject(int context) {
- deleteFinalizedTextureObjects();
+ protected static int createTextureObject(int context, PGL pgl) {
+ deleteFinalizedTextureObjects(pgl);
pgl.genTextures(1, intBuffer);
int id = intBuffer.get(0);
@@ -759,7 +767,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteTextureObject(int id, int context) {
+ protected static void deleteTextureObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glTextureObjects.containsKey(res)) {
intBuffer.put(0, id);
@@ -768,7 +776,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllTextureObjects() {
+ protected static void deleteAllTextureObjects(PGL pgl) {
for (GLResource res : glTextureObjects.keySet()) {
intBuffer.put(0, res.id);
if (pgl.threadIsCurrent()) pgl.deleteTextures(1, intBuffer);
@@ -784,7 +792,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedTextureObjects() {
+ protected static void deleteFinalizedTextureObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glTextureObjects.keySet()) {
@@ -809,8 +817,8 @@ public class PGraphicsOpenGL extends PGraphics {
// Vertex Buffer Objects -----------------------------------------------------
- protected static int createVertexBufferObject(int context) {
- deleteFinalizedVertexBufferObjects();
+ protected static int createVertexBufferObject(int context, PGL pgl) {
+ deleteFinalizedVertexBufferObjects(pgl);
pgl.genBuffers(1, intBuffer);
int id = intBuffer.get(0);
@@ -823,7 +831,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteVertexBufferObject(int id, int context) {
+ protected static void deleteVertexBufferObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glVertexBuffers.containsKey(res)) {
intBuffer.put(0, id);
@@ -832,7 +840,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllVertexBufferObjects() {
+ protected static void deleteAllVertexBufferObjects(PGL pgl) {
for (GLResource res : glVertexBuffers.keySet()) {
intBuffer.put(0, res.id);
if (pgl.threadIsCurrent()) pgl.deleteBuffers(1, intBuffer);
@@ -848,7 +856,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedVertexBufferObjects() {
+ protected static void deleteFinalizedVertexBufferObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glVertexBuffers.keySet()) {
@@ -873,8 +881,8 @@ public class PGraphicsOpenGL extends PGraphics {
// FrameBuffer Objects -------------------------------------------------------
- protected static int createFrameBufferObject(int context) {
- deleteFinalizedFrameBufferObjects();
+ protected static int createFrameBufferObject(int context, PGL pgl) {
+ deleteFinalizedFrameBufferObjects(pgl);
pgl.genFramebuffers(1, intBuffer);
int id = intBuffer.get(0);
@@ -887,7 +895,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteFrameBufferObject(int id, int context) {
+ protected static void deleteFrameBufferObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glFrameBuffers.containsKey(res)) {
intBuffer.put(0, id);
@@ -896,7 +904,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllFrameBufferObjects() {
+ protected static void deleteAllFrameBufferObjects(PGL pgl) {
for (GLResource res : glFrameBuffers.keySet()) {
intBuffer.put(0, res.id);
if (pgl.threadIsCurrent()) pgl.deleteFramebuffers(1, intBuffer);
@@ -912,7 +920,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedFrameBufferObjects() {
+ protected static void deleteFinalizedFrameBufferObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glFrameBuffers.keySet()) {
@@ -939,8 +947,8 @@ public class PGraphicsOpenGL extends PGraphics {
// RenderBuffer Objects ------------------------------------------------------
- protected static int createRenderBufferObject(int context) {
- deleteFinalizedRenderBufferObjects();
+ protected static int createRenderBufferObject(int context, PGL pgl) {
+ deleteFinalizedRenderBufferObjects(pgl);
pgl.genRenderbuffers(1, intBuffer);
int id = intBuffer.get(0);
@@ -953,7 +961,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteRenderBufferObject(int id, int context) {
+ protected static void deleteRenderBufferObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glRenderBuffers.containsKey(res)) {
intBuffer.put(0, id);
@@ -962,7 +970,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllRenderBufferObjects() {
+ protected static void deleteAllRenderBufferObjects(PGL pgl) {
for (GLResource res : glRenderBuffers.keySet()) {
intBuffer.put(0, res.id);
if (pgl.threadIsCurrent()) pgl.deleteRenderbuffers(1, intBuffer);
@@ -978,7 +986,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedRenderBufferObjects() {
+ protected static void deleteFinalizedRenderBufferObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glRenderBuffers.keySet()) {
@@ -1003,8 +1011,8 @@ public class PGraphicsOpenGL extends PGraphics {
// GLSL Program Objects ------------------------------------------------------
- protected static int createGLSLProgramObject(int context) {
- deleteFinalizedGLSLProgramObjects();
+ protected static int createGLSLProgramObject(int context, PGL pgl) {
+ deleteFinalizedGLSLProgramObjects(pgl);
int id = pgl.createProgram();
@@ -1016,7 +1024,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteGLSLProgramObject(int id, int context) {
+ protected static void deleteGLSLProgramObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glslPrograms.containsKey(res)) {
if (pgl.threadIsCurrent()) pgl.deleteProgram(res.id);
@@ -1024,7 +1032,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllGLSLProgramObjects() {
+ protected static void deleteAllGLSLProgramObjects(PGL pgl) {
for (GLResource res : glslPrograms.keySet()) {
if (pgl.threadIsCurrent()) pgl.deleteProgram(res.id);
}
@@ -1039,7 +1047,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedGLSLProgramObjects() {
+ protected static void deleteFinalizedGLSLProgramObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glslPrograms.keySet()) {
@@ -1063,8 +1071,8 @@ public class PGraphicsOpenGL extends PGraphics {
// GLSL Vertex Shader Objects ------------------------------------------------
- protected static int createGLSLVertShaderObject(int context) {
- deleteFinalizedGLSLVertShaderObjects();
+ protected static int createGLSLVertShaderObject(int context, PGL pgl) {
+ deleteFinalizedGLSLVertShaderObjects(pgl);
int id = pgl.createShader(PGL.VERTEX_SHADER);
@@ -1076,7 +1084,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteGLSLVertShaderObject(int id, int context) {
+ protected static void deleteGLSLVertShaderObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glslVertexShaders.containsKey(res)) {
if (pgl.threadIsCurrent()) pgl.deleteShader(res.id);
@@ -1084,7 +1092,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllGLSLVertShaderObjects() {
+ protected static void deleteAllGLSLVertShaderObjects(PGL pgl) {
for (GLResource res : glslVertexShaders.keySet()) {
if (pgl.threadIsCurrent()) pgl.deleteShader(res.id);
}
@@ -1100,7 +1108,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedGLSLVertShaderObjects() {
+ protected static void deleteFinalizedGLSLVertShaderObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glslVertexShaders.keySet()) {
@@ -1124,8 +1132,8 @@ public class PGraphicsOpenGL extends PGraphics {
// GLSL Fragment Shader Objects ----------------------------------------------
- protected static int createGLSLFragShaderObject(int context) {
- deleteFinalizedGLSLFragShaderObjects();
+ protected static int createGLSLFragShaderObject(int context, PGL pgl) {
+ deleteFinalizedGLSLFragShaderObjects(pgl);
int id = pgl.createShader(PGL.FRAGMENT_SHADER);
@@ -1137,7 +1145,7 @@ public class PGraphicsOpenGL extends PGraphics {
return id;
}
- protected static void deleteGLSLFragShaderObject(int id, int context) {
+ protected static void deleteGLSLFragShaderObject(int id, int context, PGL pgl) {
GLResource res = new GLResource(id, context);
if (glslFragmentShaders.containsKey(res)) {
if (pgl.threadIsCurrent()) pgl.deleteShader(res.id);
@@ -1145,7 +1153,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteAllGLSLFragShaderObjects() {
+ protected static void deleteAllGLSLFragShaderObjects(PGL pgl) {
for (GLResource res : glslFragmentShaders.keySet()) {
if (pgl.threadIsCurrent()) pgl.deleteShader(res.id);
}
@@ -1161,7 +1169,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
- protected static void deleteFinalizedGLSLFragShaderObjects() {
+ protected static void deleteFinalizedGLSLFragShaderObjects(PGL pgl) {
Set finalized = new HashSet();
for (GLResource res : glslFragmentShaders.keySet()) {
@@ -1185,14 +1193,14 @@ public class PGraphicsOpenGL extends PGraphics {
// All OpenGL resources ------------------------------------------------------
- protected static void deleteFinalizedGLResources() {
- deleteFinalizedTextureObjects();
- deleteFinalizedVertexBufferObjects();
- deleteFinalizedFrameBufferObjects();
- deleteFinalizedRenderBufferObjects();
- deleteFinalizedGLSLProgramObjects();
- deleteFinalizedGLSLVertShaderObjects();
- deleteFinalizedGLSLFragShaderObjects();
+ protected static void deleteFinalizedGLResources(PGL pgl) {
+ deleteFinalizedTextureObjects(pgl);
+ deleteFinalizedVertexBufferObjects(pgl);
+ deleteFinalizedFrameBufferObjects(pgl);
+ deleteFinalizedRenderBufferObjects(pgl);
+ deleteFinalizedGLSLProgramObjects(pgl);
+ deleteFinalizedGLSLVertShaderObjects(pgl);
+ deleteFinalizedGLSLFragShaderObjects(pgl);
}
@@ -1201,37 +1209,45 @@ public class PGraphicsOpenGL extends PGraphics {
// FRAMEBUFFERS
- protected static void pushFramebuffer() {
- if (fbStackDepth == FB_STACK_DEPTH) {
+ protected void pushFramebuffer() {
+ PGraphicsOpenGL ppg = getPrimaryPG();
+ if (ppg.fbStackDepth == FB_STACK_DEPTH) {
throw new RuntimeException("Too many pushFramebuffer calls");
}
- fbStack[fbStackDepth] = currentFramebuffer;
- fbStackDepth++;
+ ppg.fbStack[ppg.fbStackDepth] = ppg.currentFramebuffer;
+ ppg.fbStackDepth++;
}
- protected static void setFramebuffer(FrameBuffer fbo) {
- if (currentFramebuffer != fbo) {
- currentFramebuffer = fbo;
- currentFramebuffer.bind();
+ protected void setFramebuffer(FrameBuffer fbo) {
+ PGraphicsOpenGL ppg = getPrimaryPG();
+ if (ppg.currentFramebuffer != fbo) {
+ ppg.currentFramebuffer = fbo;
+ if (ppg.currentFramebuffer != null) ppg.currentFramebuffer.bind();
}
}
- protected static void popFramebuffer() {
- if (fbStackDepth == 0) {
+ protected void popFramebuffer() {
+ PGraphicsOpenGL ppg = getPrimaryPG();
+ if (ppg.fbStackDepth == 0) {
throw new RuntimeException("popFramebuffer call is unbalanced.");
}
- fbStackDepth--;
- FrameBuffer fbo = fbStack[fbStackDepth];
- if (currentFramebuffer != fbo) {
- currentFramebuffer.finish(pgPrimary);
- currentFramebuffer = fbo;
- currentFramebuffer.bind();
+ ppg.fbStackDepth--;
+ FrameBuffer fbo = ppg.fbStack[ppg.fbStackDepth];
+ if (ppg.currentFramebuffer != fbo) {
+ ppg.currentFramebuffer.finish();
+ ppg.currentFramebuffer = fbo;
+ if (ppg.currentFramebuffer != null) ppg.currentFramebuffer.bind();
}
}
+ protected FrameBuffer getCurrentFB() {
+ return getPrimaryPG().currentFramebuffer;
+ }
+
+
//////////////////////////////////////////////////////////////
// FRAME RENDERING
@@ -1245,41 +1261,41 @@ public class PGraphicsOpenGL extends PGraphics {
int sizei = INIT_VERTEX_BUFFER_SIZE * PGL.SIZEOF_INT;
int sizex = INIT_INDEX_BUFFER_SIZE * PGL.SIZEOF_INDEX;
- glPolyVertex = createVertexBufferObject(polyBuffersContext);
+ glPolyVertex = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, null, PGL.STATIC_DRAW);
- glPolyColor = createVertexBufferObject(polyBuffersContext);
+ glPolyColor = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glPolyNormal = createVertexBufferObject(polyBuffersContext);
+ glPolyNormal = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal);
pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, null, PGL.STATIC_DRAW);
- glPolyTexcoord = createVertexBufferObject(polyBuffersContext);
+ glPolyTexcoord = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyTexcoord);
pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef, null, PGL.STATIC_DRAW);
- glPolyAmbient = createVertexBufferObject(polyBuffersContext);
+ glPolyAmbient = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyAmbient);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glPolySpecular = createVertexBufferObject(polyBuffersContext);
+ glPolySpecular = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolySpecular);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glPolyEmissive = createVertexBufferObject(polyBuffersContext);
+ glPolyEmissive = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyEmissive);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glPolyShininess = createVertexBufferObject(polyBuffersContext);
+ glPolyShininess = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyShininess);
pgl.bufferData(PGL.ARRAY_BUFFER, sizef, null, PGL.STATIC_DRAW);
pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
- glPolyIndex = createVertexBufferObject(polyBuffersContext);
+ glPolyIndex = createVertexBufferObject(polyBuffersContext, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, sizex, null, PGL.STATIC_DRAW);
@@ -1290,7 +1306,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;
@@ -1308,11 +1325,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,
@@ -1333,8 +1345,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,
@@ -1360,37 +1378,53 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected void deletePolyBuffers() {
- if (polyBuffersCreated) {
- deleteVertexBufferObject(glPolyVertex, polyBuffersContext);
+ protected void finalizePolyBuffers() {
+ if (glPolyVertex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyVertex, polyBuffersContext);
glPolyVertex = 0;
-
- deleteVertexBufferObject(glPolyColor, polyBuffersContext);
- glPolyColor = 0;
-
- deleteVertexBufferObject(glPolyNormal, polyBuffersContext);
- glPolyNormal = 0;
-
- deleteVertexBufferObject(glPolyTexcoord, polyBuffersContext);
- glPolyTexcoord = 0;
-
- deleteVertexBufferObject(glPolyAmbient, polyBuffersContext);
- glPolyAmbient = 0;
-
- deleteVertexBufferObject(glPolySpecular, polyBuffersContext);
- glPolySpecular = 0;
-
- deleteVertexBufferObject(glPolyEmissive, polyBuffersContext);
- glPolyEmissive = 0;
-
- deleteVertexBufferObject(glPolyShininess, polyBuffersContext);
- glPolyShininess = 0;
-
- deleteVertexBufferObject(glPolyIndex, polyBuffersContext);
- glPolyIndex = 0;
-
- polyBuffersCreated = false;
}
+
+ if (glPolyColor != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyColor, polyBuffersContext);
+ glPolyColor = 0;
+ }
+
+ if (glPolyNormal != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyNormal, polyBuffersContext);
+ glPolyNormal = 0;
+ }
+
+ if (glPolyTexcoord != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyTexcoord, polyBuffersContext);
+ glPolyTexcoord = 0;
+ }
+
+ if (glPolyAmbient != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyAmbient, polyBuffersContext);
+ glPolyAmbient = 0;
+ }
+
+ if (glPolySpecular != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolySpecular, polyBuffersContext);
+ glPolySpecular = 0;
+ }
+
+ if (glPolyEmissive != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyEmissive, polyBuffersContext);
+ glPolyEmissive = 0;
+ }
+
+ if (glPolyShininess != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyShininess, polyBuffersContext);
+ glPolyShininess = 0;
+ }
+
+ if (glPolyIndex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPolyIndex, polyBuffersContext);
+ glPolyIndex = 0;
+ }
+
+ polyBuffersCreated = false;
}
@@ -1402,22 +1436,22 @@ public class PGraphicsOpenGL extends PGraphics {
int sizei = INIT_VERTEX_BUFFER_SIZE * PGL.SIZEOF_INT;
int sizex = INIT_INDEX_BUFFER_SIZE * PGL.SIZEOF_INDEX;
- glLineVertex = createVertexBufferObject(lineBuffersContext);
+ glLineVertex = createVertexBufferObject(lineBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, null, PGL.STATIC_DRAW);
- glLineColor = createVertexBufferObject(lineBuffersContext);
+ glLineColor = createVertexBufferObject(lineBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glLineAttrib = createVertexBufferObject(lineBuffersContext);
+ glLineAttrib = createVertexBufferObject(lineBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineAttrib);
pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef, null, PGL.STATIC_DRAW);
pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
- glLineIndex = createVertexBufferObject(lineBuffersContext);
+ glLineIndex = createVertexBufferObject(lineBuffersContext, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glLineIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, sizex, null, PGL.STATIC_DRAW);
@@ -1469,22 +1503,28 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected void deleteLineBuffers() {
- if (lineBuffersCreated) {
- deleteVertexBufferObject(glLineVertex, lineBuffersContext);
+ protected void finalizeLineBuffers() {
+ if (glLineVertex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glLineVertex, lineBuffersContext);
glLineVertex = 0;
-
- deleteVertexBufferObject(glLineColor, lineBuffersContext);
- glLineColor = 0;
-
- deleteVertexBufferObject(glLineAttrib, lineBuffersContext);
- glLineAttrib = 0;
-
- deleteVertexBufferObject(glLineIndex, lineBuffersContext);
- glLineIndex = 0;
-
- lineBuffersCreated = false;
}
+
+ if (glLineColor != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glLineColor, lineBuffersContext);
+ glLineColor = 0;
+ }
+
+ if (glLineAttrib != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glLineAttrib, lineBuffersContext);
+ glLineAttrib = 0;
+ }
+
+ if (glLineIndex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glLineIndex, lineBuffersContext);
+ glLineIndex = 0;
+ }
+
+ lineBuffersCreated = false;
}
@@ -1496,21 +1536,21 @@ public class PGraphicsOpenGL extends PGraphics {
int sizei = INIT_VERTEX_BUFFER_SIZE * PGL.SIZEOF_INT;
int sizex = INIT_INDEX_BUFFER_SIZE * PGL.SIZEOF_INDEX;
- glPointVertex = createVertexBufferObject(pointBuffersContext);
+ glPointVertex = createVertexBufferObject(pointBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, null, PGL.STATIC_DRAW);
- glPointColor = createVertexBufferObject(pointBuffersContext);
+ glPointColor = createVertexBufferObject(pointBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei, null, PGL.STATIC_DRAW);
- glPointAttrib = createVertexBufferObject(pointBuffersContext);
+ glPointAttrib = createVertexBufferObject(pointBuffersContext, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointAttrib);
pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef, null, PGL.STATIC_DRAW);
pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
- glPointIndex = createVertexBufferObject(pointBuffersContext);
+ glPointIndex = createVertexBufferObject(pointBuffersContext, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPointIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER, sizex, null, PGL.STATIC_DRAW);
@@ -1562,28 +1602,34 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected void deletePointBuffers() {
- if (pointBuffersCreated) {
- deleteVertexBufferObject(glPointVertex, pointBuffersContext);
+ protected void finalizePointBuffers() {
+ if (glPointVertex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPointVertex, pointBuffersContext);
glPointVertex = 0;
-
- deleteVertexBufferObject(glPointColor, pointBuffersContext);
- glPointColor = 0;
-
- deleteVertexBufferObject(glPointAttrib, pointBuffersContext);
- glPointAttrib = 0;
-
- deleteVertexBufferObject(glPointIndex, pointBuffersContext);
- glPointIndex = 0;
-
- pointBuffersCreated = false;
}
+
+ if (glPointColor != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPointColor, pointBuffersContext);
+ glPointColor = 0;
+ }
+
+ if (glPointAttrib != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPointAttrib, pointBuffersContext);
+ glPointAttrib = 0;
+ }
+
+ if (glPointIndex != 0) {
+ PGraphicsOpenGL.finalizeVertexBufferObject(glPointIndex, pointBuffersContext);
+ glPointIndex = 0;
+ }
+
+ pointBuffersCreated = false;
}
@Override
public void requestFocus() { // ignore
- //pgl.requestFocus();
+ pgl.requestFocus();
}
@@ -1601,7 +1647,8 @@ public class PGraphicsOpenGL extends PGraphics {
public void requestDraw() {
if (primarySurface) {
if (initialized) {
- pgl.requestDraw();
+ if (sized) pgl.reinitSurface();
+ if (parent.canDraw()) pgl.requestDraw();
} else {
initPrimary();
}
@@ -1611,6 +1658,13 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void beginDraw() {
+ if (primarySurface) {
+ setCurrentPG(this);
+ } else {
+ pgl.getGL(getPrimaryPGL());
+ getPrimaryPG().setCurrentPG(this);
+ }
+
report("top beginDraw()");
if (!checkGLThread()) {
@@ -1618,23 +1672,14 @@ public class PGraphicsOpenGL extends PGraphics {
}
if (drawing) {
- PGraphics.showWarning(ALREADY_DRAWING_ERROR);
return;
}
- if (pgCurrent != null && !pgCurrent.primarySurface &&
- !this.primarySurface) {
- // It seems that the user is trying to start another beginDraw()/endDraw()
- // block for an offscreen surface, still drawing on another one.
- PGraphics.showWarning(NESTED_DRAW_ERROR);
- return;
- }
-
- if (!primarySurface && pgPrimary.texCache.containsTexture(this)) {
+ if (!primarySurface && getPrimaryPG().texCache.containsTexture(this)) {
// This offscreen surface is being used as a texture earlier in draw,
- // so we should update the rendering up to this point since it will
+ // so we should update the rendering up to this point since it will be
// modified.
- pgPrimary.flush();
+ getPrimaryPG().flush();
}
if (!glParamsRead) {
@@ -1649,8 +1694,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
setDrawDefaults(); // TODO: look at using checkSettings() instead...
-
- pgCurrent = this;
drawing = true;
report("bot beginDraw()");
@@ -1662,7 +1705,6 @@ public class PGraphicsOpenGL extends PGraphics {
report("top endDraw()");
if (!drawing) {
- PGraphics.showWarning(NO_BEGIN_DRAW_ERROR);
return;
}
@@ -1670,7 +1712,7 @@ public class PGraphicsOpenGL extends PGraphics {
flush();
if (PGL.SAVE_SURFACE_TO_PIXELS_HACK &&
- (!pgPrimary.initialized || parent.frameCount == 0)) {
+ (!getPrimaryPG().initialized || parent.frameCount == 0)) {
// Smooth was disabled/enabled at some point during drawing. We save
// the current contents of the back buffer (because the buffers haven't
// been swapped yet) to the pixels array. The frameCount == 0 condition
@@ -1686,12 +1728,10 @@ public class PGraphicsOpenGL extends PGraphics {
endOffscreenDraw();
}
- if (pgCurrent == pgPrimary) {
- // Done with the main surface
- pgCurrent = null;
+ if (primarySurface) {
+ setCurrentPG(null);
} else {
- // Done with an offscreen surface, going back to onscreen drawing.
- pgCurrent = pgPrimary;
+ getPrimaryPG().setCurrentPG(getPrimaryPG());
}
drawing = false;
@@ -1699,6 +1739,37 @@ public class PGraphicsOpenGL extends PGraphics {
}
+ // Factory method
+ protected PGL createPGL(PGraphicsOpenGL pg) {
+ return new PJOGL(pg);
+ }
+
+
+ protected PGraphicsOpenGL getPrimaryPG() {
+ if (primarySurface) {
+ return this;
+ } else {
+ return (PGraphicsOpenGL)parent.g;
+ }
+ }
+
+ protected void setCurrentPG(PGraphicsOpenGL pg) {
+ currentPG = pg;
+ }
+
+ protected PGraphicsOpenGL getCurrentPG() {
+ return currentPG;
+ }
+
+ protected PGL getPrimaryPGL() {
+ if (primarySurface) {
+ return pgl;
+ } else {
+ return ((PGraphicsOpenGL)parent.g).pgl;
+ }
+ }
+
+
@Override
public PGL beginPGL() {
flush();
@@ -1739,8 +1810,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);
}
@@ -1764,10 +1833,33 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.depthMask(true);
}
- currentFramebuffer.bind();
- pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer());
+ FrameBuffer fb = getCurrentFB();
+ if (fb != null) {
+ fb.bind();
+ pgl.drawBuffer(fb.getDefaultDrawBuffer());
+ }
}
+ protected void beginBindFramebuffer(int target, int framebuffer) {
+ // Actually, nothing to do here.
+ }
+
+ protected void endBindFramebuffer(int target, int framebuffer) {
+ FrameBuffer fb = getCurrentFB();
+ if (framebuffer == 0 && fb != null && fb.glFbo != 0) {
+ // The user is setting the framebuffer to 0 (screen buffer), but the
+ // renderer is drawing into an offscreen buffer.
+ fb.bind();
+ }
+ }
+
+ protected void beginReadPixels() {
+ beginPixelsOp(OP_READ);
+ }
+
+ protected void endReadPixels() {
+ endPixelsOp();
+ }
protected void beginPixelsOp(int op) {
FrameBuffer pixfb = null;
@@ -1791,7 +1883,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (op == OP_READ) {
if (offscreenMultisample) {
// Making sure the offscreen FBO is up-to-date
- multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
+ multisampleFramebuffer.copyColor(offscreenFramebuffer);
}
// We always read the screen pixels from the color FBO.
pixfb = offscreenFramebuffer;
@@ -1804,7 +1896,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
// Set the framebuffer where the pixel operation shall be carried out.
- if (pixfb != currentFramebuffer) {
+ if (pixfb != getCurrentFB()) {
pushFramebuffer();
setFramebuffer(pixfb);
pixOpChangedFB = true;
@@ -1812,9 +1904,9 @@ public class PGraphicsOpenGL extends PGraphics {
// We read from/write to the draw buffer.
if (op == OP_READ) {
- pgl.readBuffer(currentFramebuffer.getDefaultDrawBuffer());
+ pgl.readBuffer(getCurrentFB().getDefaultDrawBuffer());
} else if (op == OP_WRITE) {
- pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer());
+ pgl.drawBuffer(getCurrentFB().getDefaultDrawBuffer());
}
pixelsOp = op;
@@ -1829,8 +1921,8 @@ public class PGraphicsOpenGL extends PGraphics {
}
// Restoring default read/draw buffer configuration.
- pgl.readBuffer(currentFramebuffer.getDefaultReadBuffer());
- pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer());
+ pgl.readBuffer(getCurrentFB().getDefaultReadBuffer());
+ pgl.drawBuffer(getCurrentFB().getDefaultDrawBuffer());
pixelsOp = OP_NONE;
}
@@ -2039,13 +2131,12 @@ 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;
// The superclass method is called to avoid an early flush.
super.noTexture();
@@ -2114,6 +2205,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);
}
@@ -2126,6 +2218,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);
}
@@ -2168,17 +2261,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;
}
@@ -2221,12 +2313,13 @@ public class PGraphicsOpenGL extends PGraphics {
tessellator.setInGeometry(inGeo);
tessellator.setTessGeometry(tessGeo);
tessellator.setFill(fill || textureImage != null);
+ tessellator.setTexCache(texCache, textureImage);
tessellator.setStroke(stroke);
tessellator.setStrokeColor(strokeColor);
tessellator.setStrokeWeight(strokeWeight);
tessellator.setStrokeCap(strokeCap);
tessellator.setStrokeJoin(strokeJoin);
- tessellator.setTexCache(texCache, textureImage0, textureImage);
+ tessellator.setRenderer(this);
tessellator.setTransform(modelview);
tessellator.set3D(is3D());
@@ -2251,8 +2344,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();
@@ -2261,7 +2352,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);
}
@@ -2277,7 +2367,7 @@ public class PGraphicsOpenGL extends PGraphics {
tessellator.setStrokeWeight(strokeWeight);
tessellator.setStrokeCap(strokeCap);
tessellator.setStrokeJoin(strokeJoin);
- tessellator.setTexCache(texCache, textureImage0, textureImage);
+ tessellator.setTexCache(texCache, textureImage);
tessellator.setTransform(modelview);
tessellator.set3D(is3D());
@@ -2364,14 +2454,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];
@@ -2402,18 +2496,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();
@@ -2422,15 +2516,218 @@ public class PGraphicsOpenGL extends PGraphics {
}
+ class Triangle {
+ int i0, i1, i2;
+ PImage tex;
+ float dist;
+ Triangle(int i0, int i1, int i2, PImage tex, float dist) {
+ this.i0 = i0;
+ this.i1 = i1;
+ this.i2 = i2;
+ this.tex = tex;
+ this.dist = dist;
+ }
+ }
+ // Adapted from Ben Van Citters code:
+ // http://openprocessing.org/sketch/100912
+ Triangle[] sortedPolyTriangles = null;
+ int sortedTriangleCount = 0;
+ void sortTriangles() {
+ if (sortedPolyTriangles == null) {
+ sortedPolyTriangles = new Triangle[512];
+ }
+
+ float[] vertices = tessGeo.polyVertices;
+ short[] indices = tessGeo.polyIndices;
+ float[] src0 = {0, 0, 0, 0};
+ float[] src1 = {0, 0, 0, 0};
+ float[] src2 = {0, 0, 0, 0};
+ float[] pt0 = {0, 0, 0, 0};
+ float[] pt1 = {0, 0, 0, 0};
+ float[] pt2 = {0, 0, 0, 0};
+
+ sortedTriangleCount = 0;
+ for (int i = 0; i < texCache.size; i++) {
+ PImage textureImage = texCache.getTextureImage(i);
+ int first = texCache.firstCache[i];
+ int last = texCache.lastCache[i];
+ IndexCache cache = tessGeo.polyIndexCache;
+ for (int n = first; n <= last; n++) {
+ int ioffset = n == first ? texCache.firstIndex[i] :
+ cache.indexOffset[n];
+ int icount = n == last ? texCache.lastIndex[i] - ioffset + 1 :
+ cache.indexOffset[n] + cache.indexCount[n] -
+ ioffset;
+ int voffset = cache.vertexOffset[n];
+ for (int tr = ioffset / 3; tr < (ioffset + icount) / 3; tr++) {
+ if (sortedPolyTriangles.length == sortedTriangleCount) {
+ // expand array
+ int newSize = sortedTriangleCount << 1;
+ Triangle[] temp = new Triangle[newSize];
+ PApplet.arrayCopy(sortedPolyTriangles, 0, temp, 0, newSize);
+ sortedPolyTriangles = temp;
+ }
+
+ int i0 = voffset + indices[3 * tr + 0];
+ int i1 = voffset + indices[3 * tr + 1];
+ int i2 = voffset + indices[3 * tr + 2];
+ PApplet.arrayCopy(vertices, 4 * i0, src0, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i1, src1, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i2, src2, 0, 4);
+ modelview.mult(src0, pt0);
+ modelview.mult(src1, pt1);
+ modelview.mult(src2, pt2);
+ // add all three verts together and divide... could use another determination
+ // of the 'depth' of the triangle such as min or max vert dist...
+ float[] pos = new float[]{(pt0[X] + pt1[X] + pt2[X]) /3,
+ (pt0[Y] + pt1[Y] + pt2[Y]) /3,
+ (pt0[Z] + pt1[Z] + pt2[Z]) /3};
+
+ // pt0, pt1 and pt2 are in eye coordinates since they have been
+ // multiplied by the modelview matrix.
+ float d = PApplet.dist(0f, 0f, 0f, pos[0], pos[1], pos[2]);
+
+ Triangle tri = new Triangle(i0, i1, i2, textureImage, d);
+ sortedPolyTriangles[sortedTriangleCount] = tri;
+ sortedTriangleCount++;
+ }
+ }
+ }
+ quickSortTris(0, sortedTriangleCount - 1);
+ }
+
+ // an 'in-place' implementation of quick I whipped together late at night
+ // based off of the algorithm found on wikipedia: http://en.wikipedia.org/wiki/Quicksort
+ private void quickSortTris(int leftI, int rightI) {
+ if (leftI < rightI) {
+ int pivotIndex = (leftI + rightI)/2;
+ int newPivotIndex = partition(leftI,rightI,pivotIndex);
+ quickSortTris(leftI, newPivotIndex-1);
+ quickSortTris(newPivotIndex+1, rightI);
+ }
+ }
+
+ //part of quicksort
+ private int partition(int leftIndex, int rightIndex, int pivotIndex) {
+ float pivotVal = sortedPolyTriangles[pivotIndex].dist;
+ swapTris(pivotIndex,rightIndex);
+ int storeIndex = leftIndex;
+ for(int i = leftIndex; i < rightIndex; i++)
+ {
+ if(sortedPolyTriangles[i].dist > pivotVal)
+ {
+ swapTris(i,storeIndex);
+ storeIndex++;
+ }
+ }
+ swapTris(rightIndex,storeIndex);
+ return storeIndex;
+ }
+
+ //part of quicksort
+ private void swapTris(int a, int b) {
+ Triangle tmp = sortedPolyTriangles[a];
+ sortedPolyTriangles[a] = sortedPolyTriangles[b];
+ sortedPolyTriangles[b] = tmp;
+ }
+
+
+
void rawPolys() {
raw.colorMode(RGB);
raw.noStroke();
raw.beginShape(TRIANGLES);
+
+ //sortTriangles();
+
float[] vertices = tessGeo.polyVertices;
int[] color = tessGeo.polyColors;
float[] uv = tessGeo.polyTexCoords;
- short[] indices = tessGeo.polyIndices;
+ short[] indices = tessGeo.polyIndices; // unused [fry]
+
+/*
+ sortTriangles();
+ for (int i = 0; i < sortedTriangleCount; i++) {
+ Triangle tri = sortedPolyTriangles[i];
+ int i0 = tri.i0;
+ int i1 = tri.i1;
+ int i2 = tri.i2;
+ PImage tex = tri.tex;
+
+ float[] pt0 = {0, 0, 0, 0};
+ float[] pt1 = {0, 0, 0, 0};
+ float[] pt2 = {0, 0, 0, 0};
+ int argb0 = PGL.nativeToJavaARGB(color[i0]);
+ int argb1 = PGL.nativeToJavaARGB(color[i1]);
+ int argb2 = PGL.nativeToJavaARGB(color[i2]);
+
+ if (flushMode == FLUSH_CONTINUOUSLY) {
+ float[] src0 = {0, 0, 0, 0};
+ float[] src1 = {0, 0, 0, 0};
+ float[] src2 = {0, 0, 0, 0};
+ PApplet.arrayCopy(vertices, 4 * i0, src0, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i1, src1, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i2, src2, 0, 4);
+ modelview.mult(src0, pt0);
+ modelview.mult(src1, pt1);
+ modelview.mult(src2, pt2);
+ } else {
+ PApplet.arrayCopy(vertices, 4 * i0, pt0, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i1, pt1, 0, 4);
+ PApplet.arrayCopy(vertices, 4 * i2, pt2, 0, 4);
+ }
+
+ if (tex != null) {
+ raw.texture(tex);
+ if (raw.is3D()) {
+ raw.fill(argb0);
+ raw.vertex(pt0[X], pt0[Y], pt0[Z], uv[2 * i0 + 0], uv[2 * i0 + 1]);
+ raw.fill(argb1);
+ raw.vertex(pt1[X], pt1[Y], pt1[Z], uv[2 * i1 + 0], uv[2 * i1 + 1]);
+ raw.fill(argb2);
+ raw.vertex(pt2[X], pt2[Y], pt2[Z], uv[2 * i2 + 0], uv[2 * i2 + 1]);
+ } else if (raw.is2D()) {
+ float sx0 = screenXImpl(pt0[0], pt0[1], pt0[2], pt0[3]);
+ float sy0 = screenYImpl(pt0[0], pt0[1], pt0[2], pt0[3]);
+ float sx1 = screenXImpl(pt1[0], pt1[1], pt1[2], pt1[3]);
+ float sy1 = screenYImpl(pt1[0], pt1[1], pt1[2], pt1[3]);
+ float sx2 = screenXImpl(pt2[0], pt2[1], pt2[2], pt2[3]);
+ float sy2 = screenYImpl(pt2[0], pt2[1], pt2[2], pt2[3]);
+ raw.fill(argb0);
+ raw.vertex(sx0, sy0, uv[2 * i0 + 0], uv[2 * i0 + 1]);
+ raw.fill(argb1);
+ raw.vertex(sx1, sy1, uv[2 * i1 + 0], uv[2 * i1 + 1]);
+ raw.fill(argb1);
+ raw.vertex(sx2, sy2, uv[2 * i2 + 0], uv[2 * i2 + 1]);
+ }
+ } else {
+ if (raw.is3D()) {
+ raw.fill(argb0);
+ raw.vertex(pt0[X], pt0[Y], pt0[Z]);
+ raw.fill(argb1);
+ raw.vertex(pt1[X], pt1[Y], pt1[Z]);
+ raw.fill(argb2);
+ raw.vertex(pt2[X], pt2[Y], pt2[Z]);
+ } else if (raw.is2D()) {
+ float sx0 = screenXImpl(pt0[0], pt0[1], pt0[2], pt0[3]);
+ float sy0 = screenYImpl(pt0[0], pt0[1], pt0[2], pt0[3]);
+ float sx1 = screenXImpl(pt1[0], pt1[1], pt1[2], pt1[3]);
+ float sy1 = screenYImpl(pt1[0], pt1[1], pt1[2], pt1[3]);
+ float sx2 = screenXImpl(pt2[0], pt2[1], pt2[2], pt2[3]);
+ float sy2 = screenYImpl(pt2[0], pt2[1], pt2[2], pt2[3]);
+ raw.fill(argb0);
+ raw.vertex(sx0, sy0);
+ raw.fill(argb1);
+ raw.vertex(sx1, sy1);
+ raw.fill(argb2);
+ raw.vertex(sx2, sy2);
+ }
+ }
+
+ }
+*/
+
for (int i = 0; i < texCache.size; i++) {
PImage textureImage = texCache.getTextureImage(i);
@@ -2524,6 +2821,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
}
+
raw.endShape();
}
@@ -2531,7 +2829,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void flushLines() {
updateLineBuffers();
- LineShader shader = getLineShader();
+ PShader shader = getLineShader();
shader.bind();
IndexCache cache = tessGeo.lineIndexCache;
@@ -2547,10 +2845,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();
@@ -2635,7 +2930,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void flushPoints() {
updatePointBuffers();
- PointShader shader = getPointShader();
+ PShader shader = getPointShader();
shader.bind();
IndexCache cache = tessGeo.pointIndexCache;
@@ -2651,10 +2946,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();
@@ -2758,9 +3050,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());
}
@@ -2786,8 +3076,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());
}
@@ -2812,8 +3101,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());
}
@@ -2904,70 +3192,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);
+ inGeo.addRect(x1, y1, x2, y2, tl, tr, br, bl, stroke);
endShape(CLOSE);
}
- // 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) {
@@ -3009,6 +3270,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;
@@ -3086,7 +3351,11 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void smooth() {
- smooth(2);
+ if (quality < 2) {
+ smooth(2);
+ } else {
+ smooth(quality);
+ }
}
@@ -3114,6 +3383,7 @@ public class PGraphicsOpenGL extends PGraphics {
lastSmoothCall = parent.frameCount;
quality = level;
+
if (quality == 1) {
quality = 0;
}
@@ -3164,8 +3434,8 @@ public class PGraphicsOpenGL extends PGraphics {
pushMatrix();
if (shapeMode == CENTER) {
- translate(x - shape.getWidth() / 2, y - shape.getHeight() / 2, z
- - shape.getDepth() / 2);
+ translate(x - shape.getWidth() / 2, y - shape.getHeight() / 2,
+ z - shape.getDepth() / 2);
} else if ((shapeMode == CORNER) || (shapeMode == CORNERS)) {
translate(x, y, z);
@@ -3277,43 +3547,45 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public float textAscent() {
- if (textFont == null) {
- defaultFontOrDeath("textAscent");
- }
- Font font = (Font) textFont.getNative();
- if (font != null) {
- FontMetrics metrics = parent.getFontMetrics(font);
- return metrics.getAscent();
- }
- return super.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");
- }
- Font font = (Font) textFont.getNative();
- if (font != null) {
- FontMetrics metrics = parent.getFontMetrics(font);
- return metrics.getDescent();
- }
- return super.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) {
- Font font = (Font) textFont.getNative();
- if (font != null) {
- // maybe should use one of the newer/fancier functions for this?
- int length = stop - start;
- FontMetrics metrics = parent.getFontMetrics(font);
- return metrics.charsWidth(buffer, start, length);
- }
+ 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;
+ }
- return super.textWidthImpl(buffer, start, stop);
+
+ @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);
}
@@ -3324,11 +3596,11 @@ public class PGraphicsOpenGL extends PGraphics {
protected void textLineImpl(char buffer[], int start, int stop,
float x, float y) {
if (textMode == MODEL) {
- textTex = pgPrimary.getFontTexture(textFont);
+ textTex = getFontTexture(textFont);
if (textTex == null || textTex.contextIsOutdated()) {
- textTex = new FontTexture(pgPrimary, textFont, is3D());
- pgPrimary.setFontTexture(textFont, textTex);
+ textTex = new FontTexture(this, textFont, is3D());
+ setFontTexture(textFont, textTex);
}
textTex.begin();
@@ -3387,7 +3659,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (tinfo == null) {
// Adding new glyph to the font texture.
- tinfo = textTex.addToTexture(pgPrimary, glyph);
+ tinfo = textTex.addToTexture(this, glyph);
}
float high = glyph.height / (float) textFont.getSize();
@@ -3466,20 +3738,19 @@ public class PGraphicsOpenGL extends PGraphics {
float lastX = 0;
float lastY = 0;
+ boolean open = false;
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 (!open) {
+ beginContour();
+ open = true;
+ }
+ if (type == PGL.SEG_MOVETO || type == PGL.SEG_LINETO) { // 1 point
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,
@@ -3493,8 +3764,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],
@@ -3504,10 +3774,9 @@ public class PGraphicsOpenGL extends PGraphics {
}
lastX = textPoints[4];
lastY = textPoints[5];
- break;
- case PGL.SEG_CLOSE:
+ } else if (type == PGL.SEG_CLOSE) {
endContour();
- break;
+ open = false;
}
outline.next();
}
@@ -4217,21 +4486,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
- // Sets a camera for 2D rendering, which only involves centering
- public void camera(float centerX, float centerY) {
- modelview.reset();
- modelview.translate(-centerX, -centerY);
-
- modelviewInv.set(modelview);
- modelviewInv.invert();
-
- camera.set(modelview);
- cameraInv.set(modelviewInv);
-
- updateProjmodelview();
- }
-
-
/**
* Print the current camera matrix.
*/
@@ -4257,7 +4511,7 @@ public class PGraphicsOpenGL extends PGraphics {
*/
@Override
public void ortho() {
- ortho(0, width, 0, height, cameraNear, cameraFar);
+ ortho(0, width, 0, height, 0, cameraEyeZ * 10);
}
@@ -4268,7 +4522,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void ortho(float left, float right,
float bottom, float top) {
- ortho(left, right, bottom, top, cameraNear, cameraFar);
+ ortho(left, right, bottom, top, 0, cameraEyeZ * 10);
}
@@ -4280,21 +4534,27 @@ public class PGraphicsOpenGL extends PGraphics {
public void ortho(float left, float right,
float bottom, float top,
float near, float far) {
- left -= width/2f;
- right -= width/2f;
- bottom -= height/2f;
- top -= height/2f;
+ float w = right - left;
+ float h = top - bottom;
+ float d = far - near;
+
+ // Applying the camera translation (only on x and y, as near and far
+ // are given as distances from the viewer)
+ left -= cameraEyeX;
+ right -= cameraEyeX;
+ bottom -= cameraEyeY;
+ top -= cameraEyeY;
// Flushing geometry with a different perspective configuration.
flush();
- float x = +2.0f / (right - left);
- float y = +2.0f / (top - bottom);
- float z = -2.0f / (far - near);
+ float x = +2.0f / w;
+ float y = +2.0f / h;
+ float z = -2.0f / d;
- float tx = -(right + left) / (right - left);
- float ty = -(top + bottom) / (top - bottom);
- float tz = -(far + near) / (far - near);
+ float tx = -(right + left) / w;
+ float ty = -(top + bottom) / h;
+ float tz = -(far + near) / d;
// The minus sign is needed to invert the Y axis.
projection.set(x, 0, 0, tx,
@@ -4562,8 +4822,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)
@@ -5047,6 +5319,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;
}
@@ -5054,13 +5331,9 @@ public class PGraphicsOpenGL extends PGraphics {
protected void backgroundImpl() {
flush();
- pgl.depthMask(true);
- pgl.clearDepth(1);
- pgl.clear(PGL.DEPTH_BUFFER_BIT);
- if (hints[DISABLE_DEPTH_MASK]) {
- pgl.depthMask(false);
- } else {
- pgl.depthMask(true);
+ if (!hints[DISABLE_DEPTH_MASK]) {
+ pgl.clearDepth(1);
+ pgl.clear(PGL.DEPTH_BUFFER_BIT);
}
pgl.clearColor(backgroundR, backgroundG, backgroundB, backgroundA);
@@ -5115,7 +5388,7 @@ public class PGraphicsOpenGL extends PGraphics {
* Don't use this inside glBegin/glEnd otherwise it'll
* throw an GL_INVALID_OPERATION error.
*/
- public void report(String where) {
+ protected void report(String where) {
if (!hints[DISABLE_OPENGL_ERRORS]) {
int err = pgl.getError();
if (err != 0) {
@@ -5141,16 +5414,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
-
- //////////////////////////////////////////////////////////////
-
- // PIMAGE METHODS
-
- // getImage
- // setCache, getCache, removeCache
- // isModified, setModified
-
-
//////////////////////////////////////////////////////////////
// LOAD/UPDATE PIXELS
@@ -5241,9 +5504,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;
@@ -5276,12 +5539,12 @@ public class PGraphicsOpenGL extends PGraphics {
// non-multisampled FBO, texture is actually the color buffer used by the
// color FBO, so with the copy operation we should be done updating the
// (off)screen buffer.
-
// First, copy the pixels to the texture. We don't need to invert the
// pixel copy because the texture will be drawn inverted.
-
+ int tw = PApplet.min(texture.glWidth - x, w);
+ int th = PApplet.min(texture.glHeight - y, h);
pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glName,
- x, y, w, h, nativePixelBuffer);
+ x, y, tw, th, nativePixelBuffer);
beginPixelsOp(OP_WRITE);
drawTexture(x, y, w, h);
endPixelsOp();
@@ -5336,6 +5599,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;
+// }
+// }
}
@@ -5344,8 +5618,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) {
@@ -5382,12 +5656,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.copyColor(offscreenFramebuffer);
}
if (needEndDraw) {
@@ -5418,41 +5690,21 @@ public class PGraphicsOpenGL extends PGraphics {
}
- /*
- public void drawTexture(int target, int id, int width, int height,
- int X0, int Y0, int X1, int Y1) {
- beginPGL();
- pgl.drawTexture(target, id, width, height, X0, Y0, X1, Y1);
- endPGL();
- }
-
-
- public void drawTexture(int target, int id, int texW, int texH,
- int texX0, int texY0, int texX1, int texY1,
- int scrX0, int scrY0, int scrX1, int scrY1) {
- beginPGL();
- pgl.drawTexture(target, id, texW, texH, width, height,
- texX0, texY0, texX1, texY1,
- scrX0, scrY0, scrX1, scrY1);
- endPGL();
- }
-*/
-
protected void loadTextureImpl(int sampling, boolean mipmap) {
if (width == 0 || height == 0) return;
if (texture == null || texture.contextIsOutdated()) {
Texture.Parameters params = new Texture.Parameters(ARGB,
sampling, mipmap);
- texture = new Texture(width, height, params);
+ texture = new Texture(this, width, height, params);
texture.invertedY(true);
texture.colorBuffer(true);
- pgPrimary.setCache(this, texture);
+ setCache(this, texture);
}
}
protected void createPTexture() {
- ptexture = new Texture(width, height, texture.getParameters());
+ ptexture = new Texture(this, width, height, texture.getParameters());
ptexture.invertedY(true);
ptexture.colorBuffer(true);
}
@@ -5524,12 +5776,13 @@ public class PGraphicsOpenGL extends PGraphics {
"the same size as the applet.");
}
- if (maskShader == null) {
- maskShader = new TextureShader(parent, defTextureShaderVertURL,
- maskShaderFragURL);
+ PGraphicsOpenGL ppg = getPrimaryPG();
+ if (ppg.maskShader == null) {
+ ppg.maskShader = new PShader(parent, defTextureShaderVertURL,
+ maskShaderFragURL);
}
- maskShader.set("mask", alpha);
- filter(maskShader);
+ ppg.maskShader.set("mask", alpha);
+ filter(ppg.maskShader);
}
@@ -5567,7 +5820,7 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
public void filter(PShader shader) {
- if (!(shader instanceof TextureShader)) {
+ if (!shader.isPolyShader()) {
PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR);
return;
}
@@ -5581,7 +5834,7 @@ public class PGraphicsOpenGL extends PGraphics {
loadTexture();
if (filterTexture == null || filterTexture.contextIsOutdated()) {
- filterTexture = new Texture(texture.width, texture.height,
+ filterTexture = new Texture(this, texture.width, texture.height,
texture.getParameters());
filterTexture.invertedY(true);
filterImage = wrapTexture(filterTexture);
@@ -5609,8 +5862,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);
@@ -5622,7 +5875,7 @@ public class PGraphicsOpenGL extends PGraphics {
end2D();
// Restoring previous configuration.
- textureShader = prevTexShader;
+ polyShader = prevShader;
stroke = prevStroke;
lights = prevLights;
textureMode = prevTextureMode;
@@ -5643,59 +5896,88 @@ 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(this, 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);
+ boolean invX = tex.invertedX();
+ boolean invY = tex.invertedY();
+ int scrX0, scrX1;
+ int scrY0, scrY1;
+ if (invX) {
+ scrX0 = dx + dw;
+ scrX1 = dx;
+ } else {
+ scrX0 = dx;
+ scrX1 = dx + dw;
+ }
+
+ int texX0 = sx;
+ int texX1 = sx + sw;
+ int texY0, texY1;
+ if (invY) {
+ scrY0 = height - (dy + dh);
+ scrY1 = height - dy;
+ texY0 = tex.height - (sy + sh);
+ texY1 = tex.height - sy;
+ } else {
+ // Because drawTexture uses bottom-to-top orientation of Y axis.
+ scrY0 = height - dy;
+ scrY1 = height - (dy + dh);
+ texY0 = sy;
+ texY1 = sy + sh;
+ }
+
+ pgl.drawTexture(tex.glTarget, tex.glName,
+ tex.glWidth, tex.glHeight, width, height,
+ texX0, texY0, texX1, texY1,
+ scrX0, scrY0, scrX1, scrY1);
+
+
+ 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.
*/
@@ -5728,9 +6010,11 @@ public class PGraphicsOpenGL extends PGraphics {
} 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 (blendMode == LIGHTEST) {
if (blendEqSupported) {
@@ -5748,14 +6032,6 @@ public class PGraphicsOpenGL extends PGraphics {
PGraphics.showWarning(BLEND_DRIVER_ERROR, "DARKEST");
}
- } else if (blendMode == DIFFERENCE) {
- if (blendEqSupported) {
- pgl.blendEquation(PGL.FUNC_REVERSE_SUBTRACT);
- pgl.blendFunc(PGL.ONE, PGL.ONE);
- } else {
- PGraphics.showWarning(BLEND_DRIVER_ERROR, "DIFFERENCE");
- }
-
} else if (blendMode == EXCLUSION) {
if (blendEqSupported) {
pgl.blendEquation(PGL.FUNC_ADD);
@@ -5774,6 +6050,9 @@ public class PGraphicsOpenGL extends PGraphics {
}
pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ONE);
+ } else if (blendMode == DIFFERENCE) {
+ PGraphics.showWarning(BLEND_RENDERER_ERROR, "DIFFERENCE");
+
} else if (blendMode == OVERLAY) {
PGraphics.showWarning(BLEND_RENDERER_ERROR, "OVERLAY");
@@ -5812,7 +6091,15 @@ public class PGraphicsOpenGL extends PGraphics {
* off the screen (or offscreen drawing surface).
*/
public Texture getTexture() {
- loadTexture();
+ return getTexture(true);
+ }
+
+
+ /**
+ * Not an approved function either, don't use it.
+ */
+ public Texture getTexture(boolean load) {
+ if (load) loadTexture();
return texture;
}
@@ -5845,12 +6132,30 @@ public class PGraphicsOpenGL extends PGraphics {
}
+ /**
+ * Not an approved function, test its use in libraries to grab the FB objects
+ * for offscreen PGraphics.
+ */
+ public FrameBuffer getFrameBuffer() {
+ return getFrameBuffer(false);
+ }
+
+
+ public FrameBuffer getFrameBuffer(boolean multi) {
+ if (multi) {
+ return multisampleFramebuffer;
+ } else {
+ return offscreenFramebuffer;
+ }
+ }
+
+
protected Object initCache(PImage img) {
if (!checkGLThread()) {
return null;
}
- Texture tex = (Texture)pgPrimary.getCache(img);
+ Texture tex = (Texture)getCache(img);
if (tex == null || tex.contextIsOutdated()) {
tex = addTexture(img);
if (tex != null) {
@@ -5903,8 +6208,8 @@ public class PGraphicsOpenGL extends PGraphics {
if (img.parent == null) {
img.parent = parent;
}
- Texture tex = new Texture(img.width, img.height, params);
- pgPrimary.setCache(img, tex);
+ Texture tex = new Texture(this, img.width, img.height, params);
+ setCache(img, tex);
return tex;
}
@@ -5938,18 +6243,22 @@ public class PGraphicsOpenGL extends PGraphics {
img.width = tex.width;
img.height = tex.height;
img.format = ARGB;
- pgPrimary.setCache(img, tex);
+ setCache(img, tex);
return img;
}
protected void updateTexture(PImage img, Texture tex) {
if (tex != null) {
- int x = img.getModifiedX1();
- int y = img.getModifiedY1();
- int w = img.getModifiedX2() - x;
- int h = img.getModifiedY2() - y;
- tex.set(img.pixels, x, y, w, h, img.format);
+ if (img.isModified()) {
+ int x = img.getModifiedX1();
+ int y = img.getModifiedY1();
+ int w = img.getModifiedX2() - x;
+ int h = img.getModifiedY2() - y;
+ tex.set(img.pixels, x, y, w, h, img.format);
+ } else if (img.isLoaded()) {
+ tex.set(img.pixels, 0, 0, img.width, img.height, img.format);
+ }
}
img.setModified(false);
img.setLoaded(false);
@@ -6000,10 +6309,9 @@ public class PGraphicsOpenGL extends PGraphics {
protected void initPrimary() {
pgl.initSurface(quality);
if (texture != null) {
- pgPrimary.removeCache(this);
+ removeCache(this);
texture = ptexture = null;
}
- pgPrimary = this;
initialized = true;
}
@@ -6012,11 +6320,11 @@ public class PGraphicsOpenGL extends PGraphics {
pgl.beginDraw(clearColorBuffer);
if (drawFramebuffer == null) {
- drawFramebuffer = new FrameBuffer(width, height, true);
+ drawFramebuffer = new FrameBuffer(this, width, height, true);
}
drawFramebuffer.setFBO(pgl.getDrawFramebuffer());
if (readFramebuffer == null) {
- readFramebuffer = new FrameBuffer(width, height, true);
+ readFramebuffer = new FrameBuffer(this, width, height, true);
}
readFramebuffer.setFBO(pgl.getReadFramebuffer());
if (currentFramebuffer == null) {
@@ -6037,7 +6345,7 @@ public class PGraphicsOpenGL extends PGraphics {
protected void initOffscreen() {
// Getting the context and capabilities from the main renderer.
- loadTextureImpl(Texture.BILINEAR, false);
+ loadTextureImpl(textureSampling, false);
// In case of reinitialization (for example, when the smooth level
// is changed), we make sure that all the OpenGL resources associated
@@ -6053,7 +6361,7 @@ public class PGraphicsOpenGL extends PGraphics {
packedDepthStencilSupported;
if (PGraphicsOpenGL.fboMultisampleSupported && 1 < quality) {
multisampleFramebuffer =
- new FrameBuffer(texture.glWidth, texture.glHeight, quality, 0,
+ new FrameBuffer(this, texture.glWidth, texture.glHeight, quality, 0,
depthBits, stencilBits, packed, false);
multisampleFramebuffer.clear();
@@ -6063,13 +6371,13 @@ public class PGraphicsOpenGL extends PGraphics {
// to doesn't need depth and stencil buffers since they are part of the
// multisampled framebuffer.
offscreenFramebuffer =
- new FrameBuffer(texture.glWidth, texture.glHeight, 1, 1, 0, 0,
+ new FrameBuffer(this, texture.glWidth, texture.glHeight, 1, 1, 0, 0,
false, false);
} else {
quality = 0;
offscreenFramebuffer =
- new FrameBuffer(texture.glWidth, texture.glHeight, 1, 1,
+ new FrameBuffer(this, texture.glWidth, texture.glHeight, 1, 1,
depthBits, stencilBits, packed, false);
offscreenMultisample = false;
}
@@ -6121,14 +6429,22 @@ public class PGraphicsOpenGL extends PGraphics {
protected void endOffscreenDraw() {
+ if (backgroundA == 1) {
+ // Set alpha channel to opaque in order to match behavior of JAVA2D:
+ pgl.colorMask(false, false, false, true);
+ pgl.clearColor(0, 0, 0, backgroundA);
+ pgl.clear(PGL.COLOR_BUFFER_BIT);
+ pgl.colorMask(true, true, true, true);
+ }
+
if (offscreenMultisample) {
- multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
+ multisampleFramebuffer.copyColor(offscreenFramebuffer);
}
popFramebuffer();
texture.updateTexels(); // Mark all texels in screen texture as modified.
- pgPrimary.restoreGL();
+ getPrimaryPG().restoreGL();
}
@@ -6178,14 +6494,19 @@ 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);
+ if (primarySurface) {
+ background(backgroundColor);
+ } else {
+ // offscreen surfaces are transparent by default.
+ background(0x00 << 24 | (backgroundColor & 0xFFFFFF));
+ }
// Sets the default projection and camera (initializes modelview).
// If the user has setup up their own projection, they'll need
@@ -6233,9 +6554,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (restoreSurface) {
restoreSurfaceFromPixels();
- //if (1 < parent.frameCount) {
restoreSurface = false;
- //}
}
if (hints[DISABLE_DEPTH_MASK]) {
@@ -6261,16 +6580,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);
@@ -6288,12 +6602,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);
@@ -6310,133 +6618,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);
}
@@ -6445,10 +6697,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) {
@@ -6459,35 +6708,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
@@ -6502,116 +6722,88 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected BaseShader getPolyShader(boolean lit, boolean tex) {
- BaseShader shader;
+ protected PShader getPolyShader(boolean lit, boolean tex) {
+ PShader shader;
+ PGraphicsOpenGL ppg = getPrimaryPG();
+ boolean useDefault = polyShader == null;
+ if (polyShader != null) {
+ polyShader.setRenderer(this);
+ polyShader.loadAttributes();
+ polyShader.loadUniforms();
+ }
if (lit) {
if (tex) {
- if (texlightShader == null) {
- if (defTexlightShader == null) {
- defTexlightShader = new TexlightShader(parent,
- defTexlightShaderVertURL,
- defTextureShaderFragURL);
+ if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) {
+ if (ppg.defTexlightShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defTexlightShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120);
+ ppg.defTexlightShader = new PShader(parent, vertSource, fragSource);
}
- shader = defTexlightShader;
- texlightShaderCheck();
+ shader = ppg.defTexlightShader;
} else {
- shader = texlightShader;
+ shader = polyShader;
}
} else {
- if (lightShader == null) {
- if (defLightShader == null) {
- defLightShader = new LightShader(parent,
- defLightShaderVertURL,
- defColorShaderFragURL);
+ if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) {
+ if (ppg.defLightShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defLightShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120);
+ ppg.defLightShader = new PShader(parent, vertSource, fragSource);
}
- shader = defLightShader;
- lightShaderCheck();
+ shader = ppg.defLightShader;
} 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 (defTextureShader == null) {
- defTextureShader = new TextureShader(parent,
- defTextureShaderVertURL,
- defTextureShaderFragURL);
+ if (useDefault || !polyShader.checkPolyType(PShader.TEXTURE)) {
+ if (ppg.defTextureShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defTextureShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defTextureShaderFragURL, 120);
+ ppg.defTextureShader = new PShader(parent, vertSource, fragSource);
}
- shader = defTextureShader;
- textureShaderCheck();
+ shader = ppg.defTextureShader;
} else {
- shader = textureShader;
+ shader = polyShader;
}
} else {
- if (colorShader == null) {
- if (defColorShader == null) {
- defColorShader = new ColorShader(parent,
- defColorShaderVertURL,
- defColorShaderFragURL);
+ if (useDefault || !polyShader.checkPolyType(PShader.COLOR)) {
+ if (ppg.defColorShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defColorShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defColorShaderFragURL, 120);
+ ppg.defColorShader = new PShader(parent, vertSource, fragSource);
}
- shader = defColorShader;
- colorShaderCheck();
+ shader = ppg.defColorShader;
} 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;
+ PGraphicsOpenGL ppg = getPrimaryPG();
if (lineShader == null) {
- if (defLineShader == null) {
- defLineShader = new LineShader(parent, defLineShaderVertURL,
- defLineShaderFragURL);
+ if (ppg.defLineShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defLineShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defLineShaderFragURL, 120);
+ ppg.defLineShader = new PShader(parent, vertSource, fragSource);
}
- shader = defLineShader;
+ shader = ppg.defLineShader;
} else {
shader = lineShader;
}
@@ -6622,14 +6814,16 @@ public class PGraphicsOpenGL extends PGraphics {
}
- protected PointShader getPointShader() {
- PointShader shader;
+ protected PShader getPointShader() {
+ PShader shader;
+ PGraphicsOpenGL ppg = getPrimaryPG();
if (pointShader == null) {
- if (defPointShader == null) {
- defPointShader = new PointShader(parent, defPointShaderVertURL,
- defPointShaderFragURL);
+ if (ppg.defPointShader == null) {
+ String[] vertSource = pgl.loadVertexShader(defPointShaderVertURL, 120);
+ String[] fragSource = pgl.loadFragmentShader(defPointShaderFragURL, 120);
+ ppg.defPointShader = new PShader(parent, vertSource, fragSource);
}
- shader = defPointShader;
+ shader = ppg.defPointShader;
} else {
shader = pointShader;
}
@@ -6640,765 +6834,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
@@ -7416,24 +6851,25 @@ 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() {
- return new TexCache();
+ static protected TexCache newTexCache(PGraphicsOpenGL pg) {
+ return new TexCache(pg);
}
// Holds an array of textures and the range of vertex
// indices each texture applies to.
- protected class TexCache {
+ static protected class TexCache {
+ PGraphicsOpenGL pg;
int size;
PImage[] textures;
int[] firstIndex;
@@ -7442,7 +6878,8 @@ public class PGraphicsOpenGL extends PGraphics {
int[] lastCache;
boolean hasTextures;
- TexCache() {
+ TexCache(PGraphicsOpenGL pg) {
+ this.pg = pg;
allocate();
}
@@ -7478,7 +6915,7 @@ public class PGraphicsOpenGL extends PGraphics {
Texture tex = null;
if (img != null) {
- tex = pgPrimary.getTexture(img);
+ tex = pg.getTexture(img);
}
return tex;
@@ -7551,7 +6988,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;
@@ -7656,23 +7093,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;
@@ -7680,8 +7108,10 @@ public class PGraphicsOpenGL extends PGraphics {
int[] strokeColors;
float[] strokeWeights;
- // lines
- boolean[] breaks;
+ // vertex codes
+ int[] codes;
+
+ // Stroke edges
int[][] edges;
// Material properties
@@ -7700,7 +7130,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();
}
@@ -7710,12 +7141,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() {
@@ -7729,7 +7161,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();
@@ -7749,7 +7180,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);
}
}
@@ -7791,17 +7229,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--;
@@ -7813,10 +7251,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--;
@@ -7922,10 +7360,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) {
@@ -7950,7 +7388,10 @@ public class PGraphicsOpenGL extends PGraphics {
trimSpecular();
trimEmissive();
trimShininess();
- trimBreaks();
+ }
+
+ if (0 < codeCount && codeCount < codes.length) {
+ trimCodes();
}
if (0 < edgeCount && edgeCount < edges.length) {
@@ -8018,10 +7459,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() {
@@ -8034,8 +7475,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,
@@ -8043,12 +7488,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,
@@ -8056,11 +7507,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,
@@ -8068,12 +7523,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,
@@ -8081,7 +7542,7 @@ public class PGraphicsOpenGL extends PGraphics {
strokeColor, strokeWeight,
ambientColor, specularColor, emissiveColor,
shininessFactor,
- code);
+ code, brk);
}
int addVertex(float x, float y, float z,
@@ -8090,12 +7551,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;
@@ -8120,147 +7579,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.
@@ -8291,29 +7653,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
@@ -8332,10 +7697,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) {
@@ -8344,16 +7708,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;
@@ -8366,8 +7729,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;
@@ -8379,7 +7742,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) {
@@ -8398,7 +7761,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;
@@ -8413,11 +7776,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);
@@ -8427,50 +7790,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
@@ -8530,7 +7849,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;
@@ -8540,8 +7859,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;
@@ -8550,7 +7869,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) {
@@ -8567,7 +7886,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;
@@ -8579,11 +7898,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);
@@ -8613,14 +7932,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);
}
@@ -8628,9 +7947,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);
@@ -8643,11 +7962,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);
@@ -8658,151 +7977,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;
@@ -8810,10 +8023,10 @@ 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.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY,
@@ -8822,7 +8035,7 @@ public class PGraphicsOpenGL extends PGraphics {
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;
@@ -8830,7 +8043,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) {
@@ -8844,7 +8057,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);
@@ -8864,37 +8077,33 @@ public class PGraphicsOpenGL extends PGraphics {
int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH);
int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH);
- if (fill) {
- addVertex(centerX, centerY, VERTEX);
- }
+ int idx0 = addVertex(centerX, centerY, VERTEX, true);
int increment = 1; // what's a good algorithm? stopLUT - startLUT;
- int idx0, pidx, idx;
- idx0 = pidx = idx = 0;
+ int pidx = 0, idx = 0;
for (int i = startLUT; i < stopLUT; i += increment) {
int ii = i % SINCOS_LENGTH;
// modulo won't make the value positive
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) {
addEdge(pidx, idx, i == startLUT, false);
} else if (startLUT < i) {
addEdge(pidx, idx, i == startLUT + 1, arcMode == 0 &&
- i == stopLUT - 1);
+ i == stopLUT - 1);
}
}
- if (startLUT == i) idx0 = idx;
pidx = idx;
}
// 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);
@@ -8909,7 +8118,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);
}
@@ -8924,12 +8133,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);
@@ -8938,12 +8147,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);
@@ -8954,10 +8163,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);
@@ -8968,24 +8177,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);
@@ -8996,10 +8191,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);
@@ -9014,13 +8223,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];
@@ -9040,21 +8242,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++) {
@@ -9079,16 +8283,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++) {
@@ -9125,7 +8329,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;
@@ -9149,8 +8353,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;
@@ -9221,7 +8426,8 @@ public class PGraphicsOpenGL extends PGraphics {
float[] pointOffsets;
short[] pointIndices;
- TessGeometry(int mode) {
+ TessGeometry(PGraphicsOpenGL pg, int mode) {
+ this.pg = pg;
renderMode = mode;
allocate();
}
@@ -10023,8 +9229,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;
@@ -10046,16 +9252,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;
@@ -10079,27 +9285,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;
@@ -10164,9 +9370,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) {
@@ -10212,7 +9418,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) {
@@ -10225,9 +9431,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;
@@ -10521,8 +9727,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;
@@ -10545,6 +9750,7 @@ public class PGraphicsOpenGL extends PGraphics {
PMatrix transform;
float transformScale;
boolean is2D, is3D;
+ protected PGraphicsOpenGL pg;
int[] rawIndices;
int rawSize;
@@ -10558,9 +9764,22 @@ 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);
rawIndices = new int[512];
accurate2DStrokes = true;
transform = null;
@@ -10568,6 +9787,13 @@ public class PGraphicsOpenGL extends PGraphics {
is3D = true;
}
+ void initGluTess() {
+ if (gluTess == null) {
+ callback = new TessellatorCallback();
+ gluTess = pg.pgl.createTessellator(callback);
+ }
+ }
+
void setInGeometry(InGeometry in) {
this.in = in;
@@ -10587,6 +9813,11 @@ public class PGraphicsOpenGL extends PGraphics {
this.fill = fill;
}
+ void setTexCache(TexCache texCache, PImage newTexImage) {
+ this.texCache = texCache;
+ this.newTexImage = newTexImage;
+ }
+
void setStroke(boolean stroke) {
this.stroke = stroke;
}
@@ -10599,23 +9830,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) {
@@ -10633,6 +9861,10 @@ public class PGraphicsOpenGL extends PGraphics {
transformScale = -1;
}
+ void resetCurveVertexCount() {
+ pg.curveVertexCount = 0;
+ }
+
// -----------------------------------------------------------------
//
// Point tessellation
@@ -10646,7 +9878,7 @@ 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
@@ -10681,7 +9913,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];
@@ -10741,7 +9973,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.
@@ -10784,7 +10016,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.
@@ -10814,7 +10046,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) {
@@ -10869,7 +10101,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) {
@@ -10909,7 +10141,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() {
@@ -10921,8 +10153,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) {
@@ -10942,15 +10177,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;
@@ -10960,7 +10194,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);
@@ -10970,16 +10203,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],
@@ -10992,10 +10225,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;
}
@@ -11004,8 +10236,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) {
@@ -11028,10 +10263,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 {
@@ -11053,21 +10288,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]);
}
@@ -11078,10 +10311,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;
}
}
@@ -11089,8 +10320,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) {
@@ -11113,11 +10347,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);
@@ -11126,10 +10360,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;
}
@@ -11145,23 +10378,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]);
}
@@ -11173,10 +10403,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;
}
}
@@ -11186,6 +10414,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) {
@@ -11208,7 +10439,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];
@@ -11242,7 +10473,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];
@@ -11252,34 +10483,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();
@@ -11293,12 +10524,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;
}
}
@@ -11308,7 +10539,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];
@@ -11324,26 +10555,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);
@@ -11351,7 +10584,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);
@@ -11399,11 +10632,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);
@@ -11438,7 +10671,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) {
@@ -11449,15 +10682,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;
@@ -11502,8 +10735,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;
@@ -11538,7 +10771,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;
@@ -11562,7 +10795,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;
@@ -11599,19 +10832,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);
@@ -11623,7 +10861,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;
@@ -11641,7 +10879,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);
@@ -11674,14 +10912,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;
}
@@ -11694,8 +10932,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;
@@ -11711,13 +10949,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;
@@ -11736,7 +10974,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) {
@@ -11759,17 +10997,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;
@@ -11789,10 +11027,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);
@@ -11804,17 +11042,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;
@@ -11834,10 +11072,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);
@@ -11869,7 +11107,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
@@ -12041,7 +11279,6 @@ public class PGraphicsOpenGL extends PGraphics {
}
void beginNoTex() {
- prevTexImage = newTexImage;
newTexImage = null;
setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1);
}
@@ -12071,82 +11308,541 @@ public class PGraphicsOpenGL extends PGraphics {
texCache.setLastIndex(lastIndex, lastCache);
}
}
+ prevTexImage = newTexImage;
}
// -----------------------------------------------------------------
//
- // 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;
+ initGluTess();
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() {
@@ -12157,8 +11853,8 @@ public class PGraphicsOpenGL extends PGraphics {
// Based on the opengl stroke hack described here:
// http://wiki.processing.org/w/Stroke_attributes_in_OpenGL
public void tessellateLinePath(LinePath path) {
+ initGluTess();
boolean clamp = clampLinePath();
-
callback.init(in.renderMode == RETAINED, true, false, clamp);
int cap = strokeCap == ROUND ? LinePath.CAP_ROUND :
@@ -12224,7 +11920,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
//
@@ -12245,6 +11941,7 @@ public class PGraphicsOpenGL extends PGraphics {
int cacheIndex;
int vertFirst;
int vertCount;
+ int vertOffset;
int primitive;
public void init(boolean addCache, boolean strokeTess, boolean calcNorm,
@@ -12269,19 +11966,12 @@ public class PGraphicsOpenGL extends PGraphics {
}
vertFirst = cache.vertexCount[cacheIndex];
+ vertOffset = cache.vertexOffset[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() {
@@ -12293,7 +11983,8 @@ public class PGraphicsOpenGL extends PGraphics {
// every time a new vertex was emitted (see vertex() below).
//tessBlock = tess.addFillIndexBlock(tessBlock);
cacheIndex = cache.addNew();
- vertFirst = 0;
+ vertFirst = cache.vertexCount[cacheIndex];
+ vertOffset = cache.vertexOffset[cacheIndex];
}
int indCount = 0;
@@ -12353,8 +12044,9 @@ public class PGraphicsOpenGL extends PGraphics {
}
protected void calcTriNormal(int tessIdx0, int tessIdx1, int tessIdx2) {
- tess.calcPolyNormal(vertFirst + tessIdx0, vertFirst + tessIdx1,
- vertFirst + tessIdx2);
+ tess.calcPolyNormal(vertFirst + vertOffset + tessIdx0,
+ vertFirst + vertOffset + tessIdx1,
+ vertFirst + vertOffset + tessIdx2);
}
public void vertex(Object data) {
@@ -12398,7 +12090,7 @@ public class PGraphicsOpenGL extends PGraphics {
}
public void error(int errnum) {
- String estring = pgl.tessError(errnum);
+ String estring = pg.pgl.tessError(errnum);
PGraphics.showWarning(TESSELLATION_ERROR, estring);
}
diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java
new file mode 100644
index 000000000..9957204c8
--- /dev/null
+++ b/core/src/processing/opengl/PJOGL.java
@@ -0,0 +1,2529 @@
+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 GL gl;
+
+ /** GLU interface **/
+ public GLU glu;
+
+ /** The rendering context (holds rendering state info) */
+ public GLContext context;
+
+ /** The canvas where OpenGL rendering takes place */
+ public 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 GLCapabilitiesImmutable capabilities;
+
+ /** The rendering surface */
+ protected GLDrawable drawable;
+
+ /** GLES2 functionality (shaders, etc) */
+ protected GL2ES2 gl2;
+
+ /** GL3 interface */
+ protected GL2GL3 gl3;
+
+ /** GL2 desktop functionality (blit framebuffer, map buffer range,
+ * multisampled renerbuffers) */
+ protected GL2 gl2x;
+
+ /** The AWT-OpenGL canvas */
+ protected GLCanvas canvasAWT;
+
+ /** The shared AWT-OpenGL canvas */
+// protected static GLCanvas sharedCanvasAWT;
+
+ /** The NEWT window */
+ protected GLWindow windowNEWT;
+
+ /** The shared NEWT window */
+// protected static GLWindow sharedWindowNEWT;
+
+ /** The NEWT-OpenGL canvas */
+ protected NewtCanvasAWT canvasNEWT;
+
+ /** The listener that fires the frame rendering in Processing */
+ protected 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 FBObject backFBO;
+ /** Sink buffer, used in the multisampled case */
+ protected FBObject sinkFBO;
+ /** Front (== read, previous frame) buffer */
+ protected FBObject frontFBO;
+ protected FBObject.TextureAttachment backTexAttach;
+ protected 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);
+ glu = new GLU();
+ }
+
+
+ @Override
+ public Canvas getCanvas() {
+ return canvas;
+ }
+
+
+ @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);
+ }
+ }
+
+ if (canvasAWT != null || canvasNEWT != null) {
+ // Restarting...
+ if (canvasAWT != null) {
+// sharedCanvasAWT = null;
+ canvasAWT.removeGLEventListener(listener);
+ pg.parent.removeListeners(canvasAWT);
+ pg.parent.remove(canvasAWT);
+ } else if (canvasNEWT != null) {
+// sharedWindowNEWT = null;
+ windowNEWT.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);
+// if (sharedCanvasAWT == null) {
+// sharedCanvasAWT = canvasAWT;
+// } else {
+// canvasAWT.setSharedAutoDrawable(sharedCanvasAWT);
+// }
+ 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) {
+ windowNEWT = GLWindow.create(caps);
+// if (sharedWindowNEWT == null) {
+// sharedWindowNEWT = windowNEWT;
+// } else {
+// windowNEWT.setSharedAutoDrawable(sharedWindowNEWT);
+// }
+ canvasNEWT = new NewtCanvasAWT(windowNEWT);
+ 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;
+ }
+
+ pg.parent.defaultSize = false;
+ registerListeners();
+
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = true;
+ setFps = false;
+ }
+
+
+ @Override
+ protected void reinitSurface() {
+ sinkFBO = backFBO = frontFBO = null;
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = true;
+ pg.parent.defaultSize = false;
+ }
+
+
+ @Override
+ protected void registerListeners() {
+ if (WINDOW_TOOLKIT == AWT) {
+ pg.parent.addListeners(canvasAWT);
+
+ listener = new PGLListener();
+ canvasAWT.addGLEventListener(listener);
+ } else if (WINDOW_TOOLKIT == NEWT) {
+ if (EVENTS_TOOLKIT == NEWT) {
+ NEWTMouseListener mouseListener = new NEWTMouseListener();
+ windowNEWT.addMouseListener(mouseListener);
+ NEWTKeyListener keyListener = new NEWTKeyListener();
+ windowNEWT.addKeyListener(keyListener);
+ NEWTWindowListener winListener = new NEWTWindowListener();
+ windowNEWT.addWindowListener(winListener);
+ } else if (EVENTS_TOOLKIT == AWT) {
+ pg.parent.addListeners(canvasNEWT);
+ }
+
+ listener = new PGLListener();
+ windowNEWT.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) {
+ windowNEWT.removeGLEventListener(listener);
+ }
+ }
+
+
+ @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(pg);
+ 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(pg);
+ 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 != null) {
+ 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() &&
+ frontFBO != null && backFBO != null) {
+ // 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 void getGL(PGL pgl) {
+ PJOGL pjogl = (PJOGL)pgl;
+
+ this.drawable = pjogl.drawable;
+ this.context = pjogl.context;
+ this.glContext = pjogl.glContext;
+ this.glThread = pjogl.glThread;
+
+ this.gl = pjogl.gl;
+ this.gl2 = pjogl.gl2;
+ this.gl2x = pjogl.gl2x;
+ this.gl3 = pjogl.gl3;
+ }
+
+
+ protected void getGL(GLAutoDrawable 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;
+ }
+ }
+
+
+ @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) {
+ windowNEWT.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) {
+ windowNEWT.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 {
+ changedFrontTex = changedBackTex = sinkFBO == null;
+
+ // 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 (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 {
+ public NEWTWindowListener() {
+ super();
+ }
+ @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 {
+ public NEWTMouseListener() {
+ super();
+ }
+ @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 {
+ public NEWTKeyListener() {
+ super();
+ }
+ @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;
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // 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
+ protected void bindFramebufferImpl(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 8f751dc2e..a6e37b84e 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,53 @@ 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 primaryPG;
+ protected PGraphicsOpenGL currentPG;
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 +95,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 +109,54 @@ public class PShader {
protected IntBuffer intBuffer;
protected FloatBuffer floatBuffer;
+ protected boolean loadedAttributes = false;
+ protected boolean loadedUniforms = false;
+
+ // Uniforms common to all shader types
+ protected int transformMatLoc;
+ protected int modelviewMatLoc;
+ protected int projectionMatLoc;
+ protected int ppixelsLoc;
+ protected int ppixelsUnit;
+ 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,14 +173,16 @@ 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;
+ primaryPG = (PGraphicsOpenGL)parent.g;
+ pgl = primaryPG.pgl;
context = pgl.createEmptyContext();
}
@@ -125,13 +197,15 @@ public class PShader {
*/
public PShader(PApplet parent, String vertFilename, String fragFilename) {
this.parent = parent;
- pgMain = (PGraphicsOpenGL) parent.g;
- pgl = PGraphicsOpenGL.pgl;
+ primaryPG = (PGraphicsOpenGL)parent.g;
+ pgl = primaryPG.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 +213,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 +236,15 @@ public class PShader {
*/
public PShader(PApplet parent, URL vertURL, URL fragURL) {
this.parent = parent;
- pgMain = (PGraphicsOpenGL) parent.g;
- pgl = PGraphicsOpenGL.pgl;
+ primaryPG = (PGraphicsOpenGL)parent.g;
+ pgl = primaryPG.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 +252,54 @@ 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;
+ primaryPG = (PGraphicsOpenGL)parent.g;
+ pgl = primaryPG.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 +323,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 +365,8 @@ public class PShader {
consumeUniforms();
bindTextures();
}
+
+ if (hasType()) bindTyped();
}
@@ -221,6 +374,8 @@ public class PShader {
* Unbinds the shader program.
*/
public void unbind() {
+ if (hasType()) unbindTyped();
+
if (bound) {
unbindTextures();
pgl.useProgram(0);
@@ -264,7 +419,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 +451,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 +522,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 +577,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.
@@ -622,7 +833,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 = currentPG.getTexture(img);
if (textures == null) textures = new HashMap();
textures.put(loc, tex);
@@ -685,54 +896,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!");
- }
+ glProgram = PGraphicsOpenGL.createGLSLProgramObject(context, pgl);
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 +956,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);
+ glVertex = PGraphicsOpenGL.createGLSLVertShaderObject(context, pgl);
- pgl.shaderSource(glVertex, vertexShaderSource);
+ pgl.shaderSource(glVertex, PApplet.join(vertexShaderSource, "\n"));
pgl.compileShader(glVertex);
pgl.getShaderiv(glVertex, PGL.COMPILE_STATUS, intBuffer);
@@ -850,9 +990,9 @@ public class PShader {
* @param shaderSource a string containing the shader's code
*/
protected boolean compileFragmentShader() {
- glFragment = PGraphicsOpenGL.createGLSLFragShaderObject(context);
+ glFragment = PGraphicsOpenGL.createGLSLFragShaderObject(context, pgl);
- pgl.shaderSource(glFragment, fragmentShaderSource);
+ pgl.shaderSource(glFragment, PApplet.join(fragmentShaderSource, "\n"));
pgl.compileShader(glFragment);
pgl.getShaderiv(glFragment, PGL.COMPILE_STATUS, intBuffer);
@@ -867,31 +1007,434 @@ 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);
+ PGraphicsOpenGL.deleteGLSLVertShaderObject(glVertex, context, pgl);
glVertex = 0;
}
if (glFragment != 0) {
- PGraphicsOpenGL.deleteGLSLFragShaderObject(glFragment, context);
+ PGraphicsOpenGL.deleteGLSLFragShaderObject(glFragment, context, pgl);
glFragment = 0;
}
if (glProgram != 0) {
- PGraphicsOpenGL.deleteGLSLProgramObject(glProgram, context);
+ PGraphicsOpenGL.deleteGLSLProgramObject(glProgram, context, pgl);
glProgram = 0;
}
}
+ 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.currentPG = pg;
+ }
+
+
+ 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;
+ }
+
+
+ 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");
+ ppixelsLoc = getUniformLoc("ppixels");
+
+ 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) {
+ currentPG.updateGLProjmodelview();
+ setUniformMatrix(transformMatLoc, currentPG.glProjmodelview);
+ }
+
+ if (-1 < modelviewMatLoc) {
+ currentPG.updateGLModelview();
+ setUniformMatrix(modelviewMatLoc, currentPG.glModelview);
+ }
+
+ if (-1 < projectionMatLoc) {
+ currentPG.updateGLProjection();
+ setUniformMatrix(projectionMatLoc, currentPG.glProjection);
+ }
+
+ if (-1 < viewportLoc) {
+ float x = currentPG.viewport.get(0);
+ float y = currentPG.viewport.get(1);
+ float w = currentPG.viewport.get(2);
+ float h = currentPG.viewport.get(3);
+ setUniformValue(viewportLoc, x, y, w, h);
+ }
+
+ if (-1 < ppixelsLoc) {
+ ppixelsUnit = getLastTexUnit() + 1;
+ setUniformValue(ppixelsLoc, ppixelsUnit);
+ pgl.activeTexture(PGL.TEXTURE0 + ppixelsUnit);
+ currentPG.bindFrontTexture();
+ } else {
+ ppixelsUnit = -1;
+ }
+ }
+
+ protected void bindTyped() {
+ if (currentPG == null) {
+ setRenderer(primaryPG.getCurrentPG());
+ 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) {
+ currentPG.updateGLNormal();
+ setUniformMatrix(normalMatLoc, currentPG.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 = currentPG.lightCount;
+ setUniformValue(lightCountLoc, count);
+ if (0 < count) {
+ setUniformVector(lightPositionLoc, currentPG.lightPosition, 4, count);
+ setUniformVector(lightNormalLoc, currentPG.lightNormal, 3, count);
+ setUniformVector(lightAmbientLoc, currentPG.lightAmbient, 3, count);
+ setUniformVector(lightDiffuseLoc, currentPG.lightDiffuse, 3, count);
+ setUniformVector(lightSpecularLoc, currentPG.lightSpecular, 3, count);
+ setUniformVector(lightFalloffLoc, currentPG.lightFalloffCoefficients,
+ 3, count);
+ setUniformVector(lightSpotLoc, currentPG.lightSpotParameters, 2, count);
+ }
+
+ if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc);
+
+ if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc);
+
+ if (-1 < perspectiveLoc) {
+ if (currentPG.getHint(ENABLE_STROKE_PERSPECTIVE) &&
+ currentPG.nonOrthoProjection()) {
+ setUniformValue(perspectiveLoc, 1);
+ } else {
+ setUniformValue(perspectiveLoc, 0);
+ }
+ }
+
+ if (-1 < scaleLoc) {
+ if (currentPG.getHint(DISABLE_OPTIMIZED_STROKE)) {
+ setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f);
+ } else {
+ float f = PGL.STROKE_DISPLACEMENT;
+ if (currentPG.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 < ppixelsLoc) {
+ pgl.requestFBOLayer();
+ pgl.activeTexture(PGL.TEXTURE0 + ppixelsUnit);
+ currentPG.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 < ppixelsUnit ? ppixelsUnit + 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 e0fde4a2c..6db7fddca 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,14 +261,38 @@ 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;
- pgl = PGraphicsOpenGL.pgl;
+ public PShapeOpenGL(PGraphicsOpenGL pg, int family) {
+ this.pg = pg;
+ pgl = pg.pgl;
context = pgl.createEmptyContext();
glPolyVertex = 0;
@@ -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.
@@ -333,6 +357,15 @@ public class PShapeOpenGL extends PShape {
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;
@@ -340,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.
@@ -535,20 +568,19 @@ public class PShapeOpenGL extends PShape {
// Shape creation (temporary hack)
- public static PShapeOpenGL createShape3D(PApplet parent, PShape src) {
+ public static PShapeOpenGL createShape3D(PGraphicsOpenGL pg, PShape src) {
PShapeOpenGL dest = null;
if (src.getFamily() == GROUP) {
- dest = PGraphics3D.createShapeImpl(parent, GROUP);
- copyGroup3D(parent, src, dest);
+ dest = PGraphics3D.createShapeImpl(pg, GROUP);
+ copyGroup3D(pg, src, dest);
} else if (src.getFamily() == PRIMITIVE) {
- dest = PGraphics3D.createShapeImpl(parent, src.getKind(),
- src.getParams());
+ dest = PGraphics3D.createShapeImpl(pg, src.getKind(), src.getParams());
PShape.copyPrimitive(src, dest);
} else if (src.getFamily() == GEOMETRY) {
- dest = PGraphics3D.createShapeImpl(parent, PShape.GEOMETRY);
+ dest = PGraphics3D.createShapeImpl(pg, PShape.GEOMETRY);
PShape.copyGeometry(src, dest);
} else if (src.getFamily() == PATH) {
- dest = PGraphics3D.createShapeImpl(parent, PATH);
+ dest = PGraphics3D.createShapeImpl(pg, PATH);
PShape.copyPath(src, dest);
}
dest.setName(src.getName());
@@ -559,20 +591,19 @@ public class PShapeOpenGL extends PShape {
}
- static public PShapeOpenGL createShape2D(PApplet parent, PShape src) {
+ static public PShapeOpenGL createShape2D(PGraphicsOpenGL pg, PShape src) {
PShapeOpenGL dest = null;
if (src.getFamily() == GROUP) {
- dest = PGraphics2D.createShapeImpl(parent, GROUP);
- copyGroup2D(parent, src, dest);
+ dest = PGraphics2D.createShapeImpl(pg, GROUP);
+ copyGroup2D(pg, src, dest);
} else if (src.getFamily() == PRIMITIVE) {
- dest = PGraphics2D.createShapeImpl(parent, src.getKind(),
- src.getParams());
+ dest = PGraphics2D.createShapeImpl(pg, src.getKind(), src.getParams());
PShape.copyPrimitive(src, dest);
} else if (src.getFamily() == GEOMETRY) {
- dest = PGraphics2D.createShapeImpl(parent, PShape.GEOMETRY);
+ dest = PGraphics2D.createShapeImpl(pg, PShape.GEOMETRY);
PShape.copyGeometry(src, dest);
} else if (src.getFamily() == PATH) {
- dest = PGraphics2D.createShapeImpl(parent, PATH);
+ dest = PGraphics2D.createShapeImpl(pg, PATH);
PShape.copyPath(src, dest);
}
dest.setName(src.getName());
@@ -582,25 +613,25 @@ public class PShapeOpenGL extends PShape {
}
- static public void copyGroup3D(PApplet parent, PShape src, PShape dest) {
+ static public void copyGroup3D(PGraphicsOpenGL pg, PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
for (int i = 0; i < src.getChildCount(); i++) {
- PShape c = createShape3D(parent, src.getChild(i));
+ PShape c = createShape3D(pg, src.getChild(i));
dest.addChild(c);
}
}
- static public void copyGroup2D(PApplet parent, PShape src, PShape dest) {
+ static public void copyGroup2D(PGraphicsOpenGL pg, PShape src, PShape dest) {
copyMatrix(src, dest);
copyStyles(src, dest);
copyImage(src, dest);
for (int i = 0; i < src.getChildCount(); i++) {
- PShape c = createShape2D(parent, src.getChild(i));
+ PShape c = createShape2D(pg, src.getChild(i));
dest.addChild(c);
}
}
@@ -951,14 +982,11 @@ public class PShapeOpenGL extends PShape {
child.solid(solid);
}
} else {
- isSolid = solid;
+ this.solid = solid;
}
}
-//public void beginContour() {
-//super.beginContour();
-
@Override
protected void beginContourImpl() {
breakShape = true;
@@ -970,10 +998,11 @@ public class PShapeOpenGL extends PShape {
}
-
@Override
public void vertex(float x, float y) {
vertexImpl(x, y, 0, 0, 0);
+ if (image != null)
+ PGraphics.showWarning(PGraphicsOpenGL.MISSING_UV_TEXCOORDS_ERROR);
}
@@ -986,6 +1015,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);
}
@@ -1033,24 +1064,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;
}
@@ -1090,7 +1120,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;
}
@@ -1132,7 +1162,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);
+ }
}
@@ -1174,13 +1208,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);
+ }
}
@@ -1219,46 +1261,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();
@@ -1269,30 +1296,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],
@@ -1304,9 +1338,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,
@@ -1342,7 +1396,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??
}
@@ -1373,9 +1430,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);
}
@@ -1401,8 +1465,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);
}
@@ -1416,14 +1484,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();
+ }
}
@@ -1443,8 +1517,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);
}
@@ -1816,7 +1892,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;
@@ -1937,7 +2013,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();
}
@@ -1951,7 +2027,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();
}
@@ -1987,7 +2063,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();
}
@@ -2011,7 +2087,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();
}
@@ -2271,6 +2347,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];
+ }
+
///////////////////////////////////////////////////////////
@@ -2278,6 +2398,7 @@ public class PShapeOpenGL extends PShape {
// Tessellated geometry getter.
+
@Override
public PShape getTessellation() {
updateTessellation();
@@ -2290,9 +2411,9 @@ public class PShapeOpenGL extends PShape {
PShape tess;
if (is3D()) {
- tess = PGraphics3D.createShapeImpl(pg.parent, PShape.GEOMETRY);
+ tess = PGraphics3D.createShapeImpl(pg, PShape.GEOMETRY);
} else if (is2D()) {
- tess = PGraphics2D.createShapeImpl(pg.parent, PShape.GEOMETRY);
+ tess = PGraphics2D.createShapeImpl(pg, PShape.GEOMETRY);
} else {
PGraphics.showWarning("This shape is not either 2D or 3D!");
return null;
@@ -2373,6 +2494,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.");
+ }
+ }
+
+
///////////////////////////////////////////////////////////
//
@@ -2452,7 +2601,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();
@@ -2492,12 +2641,13 @@ public class PShapeOpenGL extends PShape {
tessellator.setInGeometry(inGeo);
tessellator.setTessGeometry(tessGeo);
tessellator.setFill(fill || image != null);
+ tessellator.setTexCache(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());
@@ -2531,9 +2681,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
@@ -2680,7 +2839,7 @@ public class PShapeOpenGL extends PShape {
x2, y2, 0,
x3, y3, 0,
x4, y4, 0,
- fill, stroke);
+ stroke);
tessellator.tessellateQuads();
}
@@ -2689,20 +2848,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];
@@ -2711,20 +2868,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();
}
}
@@ -2732,17 +2929,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();
}
@@ -2750,25 +2982,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();
+ }
+ }
}
@@ -2803,10 +3071,23 @@ public class PShapeOpenGL extends PShape {
}
}
+ 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);
+ }
}
@@ -2817,18 +3098,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
@@ -2836,16 +3118,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 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;
@@ -2853,20 +3135,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
@@ -2875,8 +3156,8 @@ 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;
@@ -2887,12 +3168,11 @@ public class PShapeOpenGL extends PShape {
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],
@@ -2903,8 +3183,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;
@@ -2912,22 +3192,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);
+ }
+ }
///////////////////////////////////////////////////////////
@@ -3018,7 +3339,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);
@@ -3329,56 +3649,56 @@ public class PShapeOpenGL extends PShape {
tessGeo.updatePolyVerticesBuffer();
if (glPolyVertex == 0)
- glPolyVertex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef,
tessGeo.polyVerticesBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyColorsBuffer();
if (glPolyColor == 0)
- glPolyColor = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.polyColorsBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyNormalsBuffer();
if (glPolyNormal == 0)
- glPolyNormal = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyNormal = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal);
pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef,
tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyTexCoordsBuffer();
if (glPolyTexcoord == 0)
- glPolyTexcoord = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyTexcoord = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyTexcoord);
pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef,
tessGeo.polyTexCoordsBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyAmbientBuffer();
if (glPolyAmbient == 0)
- glPolyAmbient = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyAmbient = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyAmbient);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.polyAmbientBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolySpecularBuffer();
if (glPolySpecular == 0)
- glPolySpecular = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolySpecular = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolySpecular);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.polySpecularBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyEmissiveBuffer();
if (glPolyEmissive == 0)
- glPolyEmissive = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyEmissive = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyEmissive);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.polyEmissiveBuffer, PGL.STATIC_DRAW);
tessGeo.updatePolyShininessBuffer();
if (glPolyShininess == 0)
- glPolyShininess = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyShininess = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyShininess);
pgl.bufferData(PGL.ARRAY_BUFFER, sizef,
tessGeo.polyShininessBuffer, PGL.STATIC_DRAW);
@@ -3387,7 +3707,7 @@ public class PShapeOpenGL extends PShape {
tessGeo.updatePolyIndicesBuffer();
if (glPolyIndex == 0)
- glPolyIndex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPolyIndex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER,
tessGeo.polyIndexCount * PGL.SIZEOF_INDEX,
@@ -3404,21 +3724,21 @@ public class PShapeOpenGL extends PShape {
tessGeo.updateLineVerticesBuffer();
if (glLineVertex == 0)
- glLineVertex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glLineVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef,
tessGeo.lineVerticesBuffer, PGL.STATIC_DRAW);
tessGeo.updateLineColorsBuffer();
if (glLineColor == 0)
- glLineColor = PGraphicsOpenGL.createVertexBufferObject(context);
+ glLineColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.lineColorsBuffer, PGL.STATIC_DRAW);
tessGeo.updateLineDirectionsBuffer();
if (glLineAttrib == 0)
- glLineAttrib = PGraphicsOpenGL.createVertexBufferObject(context);
+ glLineAttrib = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glLineAttrib);
pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef,
tessGeo.lineDirectionsBuffer, PGL.STATIC_DRAW);
@@ -3427,7 +3747,7 @@ public class PShapeOpenGL extends PShape {
tessGeo.updateLineIndicesBuffer();
if (glLineIndex == 0)
- glLineIndex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glLineIndex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glLineIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER,
tessGeo.lineIndexCount * PGL.SIZEOF_INDEX,
@@ -3444,21 +3764,21 @@ public class PShapeOpenGL extends PShape {
tessGeo.updatePointVerticesBuffer();
if (glPointVertex == 0)
- glPointVertex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPointVertex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointVertex);
pgl.bufferData(PGL.ARRAY_BUFFER, 4 * sizef,
tessGeo.pointVerticesBuffer, PGL.STATIC_DRAW);
tessGeo.updatePointColorsBuffer();
if (glPointColor == 0)
- glPointColor = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPointColor = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointColor);
pgl.bufferData(PGL.ARRAY_BUFFER, sizei,
tessGeo.pointColorsBuffer, PGL.STATIC_DRAW);
tessGeo.updatePointOffsetsBuffer();
if (glPointAttrib == 0)
- glPointAttrib = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPointAttrib = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ARRAY_BUFFER, glPointAttrib);
pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef,
tessGeo.pointOffsetsBuffer, PGL.STATIC_DRAW);
@@ -3467,7 +3787,7 @@ public class PShapeOpenGL extends PShape {
tessGeo.updatePointIndicesBuffer();
if (glPointIndex == 0)
- glPointIndex = PGraphicsOpenGL.createVertexBufferObject(context);
+ glPointIndex = PGraphicsOpenGL.createVertexBufferObject(context, pgl);
pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPointIndex);
pgl.bufferData(PGL.ELEMENT_ARRAY_BUFFER,
tessGeo.pointIndexCount * PGL.SIZEOF_INDEX,
@@ -3548,47 +3868,47 @@ public class PShapeOpenGL extends PShape {
protected void deletePolyBuffers() {
if (glPolyVertex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyVertex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyVertex, context, pgl);
glPolyVertex = 0;
}
if (glPolyColor != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyColor, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyColor, context, pgl);
glPolyColor = 0;
}
if (glPolyNormal != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyNormal, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyNormal, context, pgl);
glPolyNormal = 0;
}
if (glPolyTexcoord != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyTexcoord, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyTexcoord, context, pgl);
glPolyTexcoord = 0;
}
if (glPolyAmbient != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyAmbient, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyAmbient, context, pgl);
glPolyAmbient = 0;
}
if (glPolySpecular != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolySpecular, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolySpecular, context, pgl);
glPolySpecular = 0;
}
if (glPolyEmissive != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyEmissive, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyEmissive, context, pgl);
glPolyEmissive = 0;
}
if (glPolyShininess != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyShininess, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyShininess, context, pgl);
glPolyShininess = 0;
}
if (glPolyIndex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPolyIndex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPolyIndex, context, pgl);
glPolyIndex = 0;
}
}
@@ -3596,22 +3916,22 @@ public class PShapeOpenGL extends PShape {
protected void deleteLineBuffers() {
if (glLineVertex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glLineVertex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glLineVertex, context, pgl);
glLineVertex = 0;
}
if (glLineColor != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glLineColor, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glLineColor, context, pgl);
glLineColor = 0;
}
if (glLineAttrib != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glLineAttrib, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glLineAttrib, context, pgl);
glLineAttrib = 0;
}
if (glLineIndex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glLineIndex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glLineIndex, context, pgl);
glLineIndex = 0;
}
}
@@ -3619,22 +3939,22 @@ public class PShapeOpenGL extends PShape {
protected void deletePointBuffers() {
if (glPointVertex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPointVertex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPointVertex, context, pgl);
glPointVertex = 0;
}
if (glPointColor != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPointColor, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPointColor, context, pgl);
glPointColor = 0;
}
if (glPointAttrib != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPointAttrib, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPointAttrib, context, pgl);
glPointAttrib = 0;
}
if (glPointIndex != 0) {
- PGraphicsOpenGL.deleteVertexBufferObject(glPointIndex, context);
+ PGraphicsOpenGL.deleteVertexBufferObject(glPointIndex, context, pgl);
glPointIndex = 0;
}
}
@@ -4055,10 +4375,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) {
@@ -4232,10 +4605,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 ||
@@ -4291,19 +4668,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()) {
@@ -4408,7 +4784,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;
@@ -4424,10 +4800,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();
@@ -4508,7 +4881,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;
@@ -4524,10 +4897,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();
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 323d6f818..5ffd60b0b 100644
--- a/core/src/processing/opengl/Texture.java
+++ b/core/src/processing/opengl/Texture.java
@@ -1,5 +1,3 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
/*
Part of the Processing project - http://processing.org
@@ -38,8 +36,6 @@ import java.util.NoSuchElementException;
*
*/
public class Texture implements PConstants {
- // texture constants
-
/**
* Texture with normalized UV.
*/
@@ -56,15 +52,25 @@ public class Texture implements PConstants {
* 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
+ * minification either to linear-mipmap-nearest (linear interpolation 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. */
+ * interpolates linearly between these two values. */
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;
@@ -77,6 +83,7 @@ public class Texture implements PConstants {
public int glWidth;
public int glHeight;
+ protected PGraphicsOpenGL pg;
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
@@ -94,6 +101,8 @@ public class Texture implements PConstants {
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;
@@ -110,8 +119,9 @@ public class Texture implements PConstants {
// Constructors.
- public Texture() {
- pgl = PGraphicsOpenGL.pgl;
+ public Texture(PGraphicsOpenGL pg) {
+ this.pg = pg;
+ pgl = pg.pgl;
context = pgl.createEmptyContext();
colorBuffer = false;
@@ -126,8 +136,8 @@ public class Texture implements PConstants {
* @param width int
* @param height int
*/
- public Texture(int width, int height) {
- this(width, height, new Parameters());
+ public Texture(PGraphicsOpenGL pg, int width, int height) {
+ this(pg, width, height, new Parameters());
}
@@ -138,8 +148,9 @@ public class Texture implements PConstants {
* @param height int
* @param params Parameters
*/
- public Texture(int width, int height, Object params) {
- pgl = PGraphicsOpenGL.pgl;
+ public Texture(PGraphicsOpenGL pg, int width, int height, Object params) {
+ this.pg = pg;
+ pgl = pg.pgl;
context = pgl.createEmptyContext();
colorBuffer = false;
@@ -241,7 +252,7 @@ public class Texture implements PConstants {
dispose();
// Creating new texture with the appropriate size.
- Texture tex = new Texture(wide, high, getParameters());
+ Texture tex = new Texture(pg, wide, high, getParameters());
// Copying the contents of this texture into tex.
tex.set(this);
@@ -318,8 +329,7 @@ public class Texture implements PConstants {
return;
}
- if (pixels.length == 0) {
- // Nothing to do (means that w == h == 0) but not an erroneous situation
+ if (pixels.length == 0 || w == 0 || h == 0) {
return;
}
@@ -334,7 +344,7 @@ public class Texture implements PConstants {
if (PGraphicsOpenGL.autoMipmapGenSupported) {
// Automatic mipmap generation.
loadPixels(w * h);
- convertToRGBA(pixels, rgbaPixels, format, w, h);
+ convertToRGBA(pixels, format, w, h);
updatePixelBuffer(rgbaPixels);
pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
pixelBuffer);
@@ -395,14 +405,14 @@ public class Texture implements PConstants {
*/
loadPixels(w * h);
- convertToRGBA(pixels, rgbaPixels, format, 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, rgbaPixels, format, w, h);
+ convertToRGBA(pixels, format, w, h);
updatePixelBuffer(rgbaPixels);
pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE,
pixelBuffer);
@@ -413,6 +423,9 @@ public class Texture implements PConstants {
pgl.disableTexturing(glTarget);
}
+ releasePixelBuffer();
+ releaseRGBAPixels();
+
updateTexels(x, y, w, h);
}
@@ -430,6 +443,7 @@ public class Texture implements PConstants {
public void setNative(int[] pixels, int x, int y, int w, int h) {
updatePixelBuffer(pixels);
setNative(pixelBuffer, x, y, w, h);
+ releasePixelBuffer();
}
@@ -499,17 +513,17 @@ public class Texture implements PConstants {
}
if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
+ tempFbo = new FrameBuffer(pg, 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);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(tempFbo);
tempFbo.readPixels();
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
tempFbo.getPixels(pixels);
convertToARGB(pixels);
@@ -815,6 +829,7 @@ public class Texture implements PConstants {
protected void updatePixelBuffer(int[] pixels) {
pixelBuffer = PGL.updateIntBuffer(pixelBuffer, pixels, true);
+ pixBufUpdateCount++;
}
@@ -866,20 +881,35 @@ public class Texture implements PConstants {
}
public void getBufferPixels(int[] pixels) {
+ // We get the buffer either from the used buffers or the cache, giving
+ // priority to the used buffers. Why? Because the used buffer was already
+ // transferred to the texture, so the pixels should be in sync with the
+ // texture.
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();
+ data = bufferCache.getLast();
}
if (data != null) {
+ if ((data.w != width) || (data.h != height)) {
+ init(data.w, data.h);
+ }
+
data.rgbBuf.rewind();
data.rgbBuf.get(pixels);
convertToARGB(pixels);
+
+ // In order to avoid a cached buffer to overwrite the texture when the
+ // renderer draws the texture, and hence put the pixels put of sync, we
+ // simply empty the cache.
+ if (usedBuffers == null) {
+ usedBuffers = new LinkedList();
+ }
+ while (0 < bufferCache.size()) {
+ data = bufferCache.remove(0);
+ usedBuffers.add(data);
+ }
}
}
@@ -993,38 +1023,36 @@ public class Texture implements PConstants {
/**
* 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
+ * 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[] intArray, int[] tIntArray, int arrayFormat,
- int w, int h) {
+ protected void convertToRGBA(int[] pixels, int format, int w, int h) {
if (PGL.BIG_ENDIAN) {
- switch (arrayFormat) {
+ 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< intArray.length; i++) {
- tIntArray[i] = 0xFFFFFF00 | intArray[i];
+ 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< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = (pixel << 8) | 0xFF;
+ 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< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
+ for (int i = 0; i< pixels.length; i++) {
+ int pixel = pixels[i];
+ rgbaPixels[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
}
break;
}
@@ -1034,43 +1062,44 @@ public class Texture implements PConstants {
// 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) {
+ switch (format) {
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;
+ 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< intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = 0xFF000000 |
- ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
- (pixel & 0x0000FF00);
+ 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 < intArray.length; i++) {
- int pixel = intArray[i];
- tIntArray[i] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
- (pixel & 0xFF00FF00);
+ 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 intArray int[]
+ * @param pixels int[]
*/
- protected void convertToARGB(int[] intArray) {
+ protected void convertToARGB(int[] pixels) {
int t = 0;
int p = 0;
if (PGL.BIG_ENDIAN) {
@@ -1078,8 +1107,8 @@ public class Texture implements PConstants {
// 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);
+ int pixel = pixels[p++];
+ pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000);
}
}
} else {
@@ -1087,8 +1116,8 @@ public class Texture implements PConstants {
// 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) |
+ int pixel = pixels[p++];
+ pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) |
(pixel & 0xFF00FF00);
}
}
@@ -1145,7 +1174,7 @@ public class Texture implements PConstants {
}
context = pgl.getCurrentContext();
- glName = PGraphicsOpenGL.createTextureObject(context);
+ glName = PGraphicsOpenGL.createTextureObject(context, pgl);
pgl.bindTexture(glTarget, glName);
pgl.texParameteri(glTarget, PGL.TEXTURE_MIN_FILTER, glMinFilter);
@@ -1225,7 +1254,7 @@ public class Texture implements PConstants {
}
if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
+ tempFbo = new FrameBuffer(pg, glWidth, glHeight);
}
// This texture is the color (destination) buffer of the FBO.
@@ -1233,8 +1262,8 @@ public class Texture implements PConstants {
tempFbo.disableDepthTest();
// FBO copy:
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(tempFbo);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(tempFbo);
// Clear the color buffer to make sure that the alpha channel is set to
// full transparency
pgl.clearColor(0, 0, 0, 0);
@@ -1244,7 +1273,7 @@ public class Texture implements PConstants {
// 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);
+ x, y, x + w, y + h, 0, 0, width, height);
} else {
// Rendering tex into "this" but without scaling so the contents
@@ -1252,9 +1281,9 @@ public class Texture implements PConstants {
// destination.
pgl.drawTexture(tex.glTarget, tex.glName,
tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
- x, y, w, h, x, y, w, h);
+ x, y, x + w, y + h, x, y, x + w, y + h);
}
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
updateTexels(x, y, w, h);
}
@@ -1265,7 +1294,7 @@ public class Texture implements PConstants {
int texWidth, int texHeight,
int x, int y, int w, int h, boolean scale) {
if (tempFbo == null) {
- tempFbo = new FrameBuffer(glWidth, glHeight);
+ tempFbo = new FrameBuffer(pg, glWidth, glHeight);
}
// This texture is the color (destination) buffer of the FBO.
@@ -1273,8 +1302,8 @@ public class Texture implements PConstants {
tempFbo.disableDepthTest();
// FBO copy:
- PGraphicsOpenGL.pushFramebuffer();
- PGraphicsOpenGL.setFramebuffer(tempFbo);
+ pg.pushFramebuffer();
+ pg.setFramebuffer(tempFbo);
if (scale) {
// Rendering tex into "this", and scaling the source rectangle
// to cover the entire destination region.
@@ -1290,7 +1319,7 @@ public class Texture implements PConstants {
texWidth, texHeight, tempFbo.width, tempFbo.height,
x, y, w, h, x, y, w, h);
}
- PGraphicsOpenGL.popFramebuffer();
+ pg.popFramebuffer();
updateTexels(x, y, w, h);
}
@@ -1322,6 +1351,26 @@ public class Texture implements PConstants {
}
+ // 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
@@ -1404,21 +1453,27 @@ public class Texture implements PConstants {
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 = params.mipmaps && PGL.MIPMAPS_ENABLED ?
- PGL.LINEAR_MIPMAP_NEAREST : PGL.LINEAR;
+ glMinFilter = mipmaps ? 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;
+ glMinFilter = mipmaps ? 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;
+ glMinFilter = mipmaps ? PGL.LINEAR_MIPMAP_LINEAR : PGL.LINEAR;
} else {
throw new RuntimeException("Unknown texture filtering mode");
}
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 de76d6a2e..ea362845a 100644
--- a/core/todo.txt
+++ b/core/todo.txt
@@ -1,64 +1,70 @@
-0221 core
-X fix options parsing on loadTable() to handle spaces
-X add static versions of loadJSONObject and loadJSONArray that take File inputs
+0228 core
-andres
-X blendMode() change causes OpenGL renderer to be very slow
-X https://github.com/processing/processing/issues/2021
-X serious OpenGL performance issues on OS X (fixed earlier?)
-X https://github.com/processing/processing/issues/1714
-X fixed with a recent JOGL update
-X P2D low quality text rendering
-X https://github.com/processing/processing/issues/1972
-X Rendering artifacts on the diagonal line (topleft to bottomright) in P2D
-X https://github.com/processing/processing/issues/1964
-X Fix issues with slow text rendering and OpenGL
-X https://github.com/processing/processing/issues/2025
-X loadShape doesn't load OBJ files in subdirectories properly
-X https://github.com/processing/processing/issues/2003
-X more OpenGL issues fixed by JOGL or newer drivers
-X https://github.com/processing/processing/issues/1986
-X Vertical offset when sketch height is indivisible by 2
-X https://github.com/processing/processing/issues/1985
-X ellipse() causes RuntimeException: java.lang.OutOfMemoryError
-X https://github.com/processing/processing/issues/1941
-X beginShape()..endShape() lines look wrong at joins/caps with P2D
-X https://github.com/processing/processing/issues/1927
-X Corrupted text with large font and OpenGL
-X https://github.com/processing/processing/issues/1869
-X loadFont hangs on Processing 2.0 with any OpenGL renderer
-X https://github.com/processing/processing/issues/1854
-
-video
-X problem with bit shifting
-X https://github.com/processing/processing/pull/2023
-X https://github.com/processing/processing/pull/2022
-X https://github.com/processing/processing/issues/2021
-
-
-critical
-_ loadPixels doesn't set alpha value for pixels on Java2D
-_ https://github.com/processing/processing/issues/2030
high
+_ pull for image resize and alpha issues
+_ https://github.com/processing/processing/pull/2324
+_ dataPath() not working when app is not run from app dir on Linux
+_ https://github.com/processing/processing/issues/2195
+_ "Buffers have not been created" error for sketches w/o draw()
+_ https://github.com/processing/processing/issues/2469
+_ could not reproduce
+_ Sketch runs with default size if size() is followed by large memory allocation
+_ some sort of threading issue happening here
+_ https://github.com/processing/processing/issues/1672
+_ https://github.com/processing/processing/issues/2039 (dupe)
+_ https://github.com/processing/processing/issues/2294 (dupe)
+_ point() rendering differently in 2.0.3 and 2.1
+_ https://github.com/processing/processing/issues/2278
+_ internally, we probably have to call set() if it's a 1 pixel point
+_ but that's going to be a mess.. need to first check the CTM
+_ tint() not working in PDF (regression between 2.0.3 and 2.1)
+_ https://github.com/processing/processing/issues/2428
+_ default font fixes
+_ https://github.com/processing/processing/issues/2331
+_ https://github.com/processing/processing/pull/2338
+_ add print() method to other data types (not just IntList)
+_ Sort out blending differences with P2D/P3D
+_ might be that compatible images not setting alpha mode correctly
+_ image = gc.createCompatibleVolatileImage(source.width, source.height, Transparency.TRANSLUCENT);
+_ 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
+_ https://github.com/processing/processing/issues/2275
+_ https://github.com/processing/processing/issues/2276
+_ https://github.com/processing/processing/issues/2483
_ 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
-_ 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
-_ 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
+
+hidpi
+_ saveFrame() with retina render is making black images
+_ zero alpha values still a problem with retina renderer
+_ https://github.com/processing/processing/issues/2030
+_ how to name the retina pixel stuff
+_ hint(ENABLE_RETINA_PIXELS) or hint(ENABLE_HIDPI_PIXELS)
+_ hint(ENABLE_2X_PIXELS)?
+_ hidpi is Apple's name as well
+_ no high-res display support for OpenGL
+_ no high-dpi support for core on Windows
+_ https://github.com/processing/processing/issues/2411
+_ retina sketches slow to start
+_ https://github.com/processing/processing/issues/2357
+
+cantfix
+_ crash on startup when "Mirror Displays" selected
+_ suspect that this is a specific chipset since Oracle didn't reproduce
+_ https://github.com/processing/processing/issues/2186
table
_ addRow() is not efficient, probably need to do the doubling
@@ -72,6 +78,8 @@ _ save the constructor for the version that actually copies data
_ the table pointer version will be speedy and allow chaining
decisions/misc
+_ make join() work with Iterable?
+_ will this collide with the current String[] version?
_ add options for image.save() (or saveImage?)
_ add quality=[0,1] for jpeg images
_ add dpi=[0,n] for for png images
@@ -80,7 +88,7 @@ _ possible addition for 'implementation' variable
X http://code.google.com/p/processing/issues/detail?id=281
_ https://github.com/processing/processing/issues/320
_ should map() actually constrain to the low and high values?
-_ or have an alternate version that does that? (boolean param at end?)
+_ or have an alternate version that does that? (or boolean param at end?)
_ decide whether to keep:
_ public float textWidth(char[] chars, int start, int length)
_ add version of math functions that use doubles?
@@ -109,14 +117,6 @@ _ nasty errors when loadImage/Font/createFont/etc used outside
_ decision: add error messages where possible
_ idea: set frameCount to -1 when setup not run yet?
_ then set frameCount to 0 when setup() starts?
-_ how much of com.benfry.* should go in?
-_ Table? StringIntPairs? JSON? MD5? Integrator? ColorIntegrator?
-_ decision: depends on if we can think of a good name
-_ check on DXFWriter, since it used to subclass P3D
-_ at least implement is3D?
-_ sleep time needs to be set *much* higher for dormant applets
-_ 10s should be fine--no need to keep spinning (bad for android too)
-_ just call interrupt() when it's time to get back to work
_ need to clean up the hints in the reference/source
_ sort out edge + 1 issue on stroke/fill for rectangles
_ http://code.google.com/p/processing/issues/detail?id=509
@@ -155,14 +155,6 @@ _ online is there but deprecated
_ doesn't test net connection to see if 'online'
_ only tests whether running inside an applet viewer (not relevant)
_ remove 'online' from the docs
-_ createGraphics() with no renderer param to point to JAVA2D
-_ docs: P2D and P3D are now OpenGL variations
-_ shader support - make decisions, Andres email, etc
-_ setAntiAlias() should instead just use parent.smooth
-_ antialias -> smoothMode(), smoothQuality(), quality()
-_ NEAREST, BILINEAR, BICUBIC, or 0, 2, 4? (need 8x too, so maybe numbers)
-_ final decision on pg.setQuality(sketchQuality())
-_ should probably be setQuality(parent.sketchQuality())
_ add reference/docs for urlEncode() and urlDecode()
_ verify (and document) public access members of PApplet
_ http://code.google.com/p/processing/issues/detail?id=83
@@ -178,6 +170,9 @@ _ OpenGL offscreen requires primary surface to be OpenGL
_ explain the new PGL interface
_ can't really change the smoothing/options on offscreen
_ is this still true?
+_ decide how disconnectEvent should actually be handled (and name?)
+_ was disconnect always there?
+_ will need documentation
@@ -352,6 +347,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
@@ -479,6 +476,8 @@ _ Updating graphics drivers may prevent the problem
_ ellipse scaling method isn't great
_ http://code.google.com/p/processing/issues/detail?id=87
_ improve hint(ENABLE_DEPTH_SORT) to use proper painter's algo
+_ https://github.com/processing/processing/issues/90
+_ for begin/endRaw: https://github.com/processing/processing/issues/2235
_ http://code.google.com/p/processing/issues/detail?id=51
_ polygon z-order depth sorting with alpha in opengl
_ complete the implementation of hint() with proper implementation
@@ -530,8 +529,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 51ff8262d..225f3aa3a 100644
--- a/done.txt
+++ b/done.txt
@@ -1,3 +1,440 @@
+0227 pde (2.2.1)
+X use mouseReleased() instead of mousePressed() in color selector
+X otherwise it registers the release as a click in the color window
+X https://github.com/processing/processing/issues/2514
+X missing 'version' in contrib causes NPE
+X https://github.com/processing/processing/issues/2517
+X bring back setIcon(Frame) for PDE X and others
+X https://github.com/processing/processing-experimental/issues/64
+X how was PDE X able to crash 2.2?
+X add additional code to rework how this is handled
+X Auto Format patch mess
+X https://github.com/processing/processing/pull/2271
+X why is the JDK path showing up as a ._ feller in OS X?
+X https://github.com/processing/processing/issues/2520
+X "Archive Sketch" Tool doesn't force a .zip file extension
+X https://github.com/processing/processing/issues/2526
+
+python
+J modifications for captureEvent and Python
+J https://github.com/processing/processing/pull/2527
+J Permit implementing movieEvent without having to link to Movie at build time
+J https://github.com/processing/processing/pull/2528
+J implement serial events without having to link to Serial at build time
+J https://github.com/processing/processing/pull/2529
+
+
+0226 pde (2.2)
+X sketches only starting once, or half-starting and hanging
+X https://github.com/processing/processing/issues/2402
+X https://github.com/processing/processing/pull/2455
+X reopen current sketch in new mode editor if file extension is compatible
+X https://github.com/processing/processing/pull/2457
+X https://github.com/processing/processing/issues/2456
+X crash in the 'recent' menu on startup
+X https://github.com/processing/processing/issues/2463
+X sketchbook location is set to an actual sketch (huh?)
+X sketch sometimes simply does not launch
+X https://github.com/processing/processing/issues/2402
+X https://github.com/processing/processing/pull/2455
+X helpful fix contributed by David Fokkema
+X remove the google code uploader
+X JNA conflicts can be avoided with "-Djna.nosys=true"
+X https://github.com/processing/processing/issues/2239
+X fix for Windows launchers
+X fix for Windows export
+X fix for Windows export 64-bit
+X fix for Windows command line
+X fix for Linux launcher
+X fix for Linux export
+X fix for Linux command line
+X fix for OS X launcher
+X fix for OS X export
+X fix for OS X command line
+X import static causes exception (with fix)
+X https://github.com/processing/processing/issues/8
+o https://github.com/processing/processing/pull/2273
+X improve handling of tool loading
+X QuickReference tool was able to bring down the environment
+X https://github.com/processing/processing/issues/2229
+X save the previous open dialog so that we return to the directory
+X https://github.com/processing/processing/pull/2366
+X "if-else" block formatting doesn't follow Processing conventions
+X https://github.com/processing/processing/issues/364
+X https://github.com/processing/processing/pull/2477
+X tab characters not recognized/drawn in the editor (2.1)
+X https://github.com/processing/processing/issues/2180
+X https://github.com/processing/processing/issues/2183
+o udp library has tabs in the text
+X decision to be made on nextTabStop() inside TextAreaPainter
+X Chinese text is overlapped in Processing 2.1 editor
+X https://github.com/processing/processing/issues/2173
+X https://github.com/processing/processing/pull/2318
+X https://github.com/processing/processing/pull/2323
+o maybe user prefs should only cover things that've changed?
+o how to balance colors/etc being stored elsewhere
+o ton of work to maintain this...
+X yeah, no
+X remove video for macosx32 from the repo permanently
+o fix for various net issues
+o https://github.com/processing/processing/pull/2475
+X incorporates other unrelated code, had to close
+
+earlier (2.1.2)
+X added get/set methods for status lines (Manindra)
+X https://github.com/processing/processing/issues/2430
+X https://github.com/processing/processing/pull/2433
+X allow non-pde file extensions (JDF)
+X https://github.com/processing/processing/issues/2420
+
+export
+X exported apps on Windows 64 not working?
+X https://github.com/processing/processing/issues/2468
+X just needed to add the local path for Java
+X when exporting with local Java embedded, use that version
+X https://github.com/processing/processing/issues/2349
+X (we can do this now since we're actually doing the embedding)
+o export application folder location (for Manindra)
+X https://github.com/processing/processing/issues/2399
+X incorporate new launch4j 3.4
+X http://sourceforge.net/projects/launch4j/files/launch4j-3/3.4/
+X change Windows export to use launch4j instead of the launcher.cpp file
+X actually call ant from inside p5?
+X re-implement an icon for exported applications on Windows
+X make sure that Windows export uses the local Java
+X double-checked with a clean XP install
+X make sure Windows export includes library DLLs
+X remove build/windows/export from repo
+o make sure launch4j export isn't printing to console unless trouble
+X OS X is doing this, though Windows is pushing some stuff through
+X bring back multi-platform export?
+X embed Java only works for the current platform
+o OS X applications can only be exported from OS X
+X actually it's just the embedding, which is a problem on any platform
+X add all sorts of language to the export dialog
+X make available the background colors for present mode, stop button color
+X isolate color chooser into a simpler/smaller class outside tools
+X then can also use from inside processing applications as well
+X http://code.google.com/p/processing/issues/detail?id=30
+X https://github.com/processing/processing/issues/69
+X exported apps reporting as "damaged" on OS X
+X https://github.com/processing/processing/issues/2095
+X implement a call to codesign, and a message box re: installing Xcode
+X use launch4j for export and p5 app itself
+X perhaps even calling it through an ant task
+X windows exported exe problems (pcho)
+o updated launch4j 3.1 beta
+o http://sourceforge.net/projects/launch4j/files/launch4j-3/
+X exe instead of bat to make exported apps run in 64-bit
+X http://code.google.com/p/processing/issues/detail?id=885
+X https://github.com/processing/processing/issues/923
+
+
+0225 pde (2.1.2)
+X Fix exception caused by Runner when it can't find location
+X https://github.com/processing/processing/issues/2346
+X https://github.com/processing/processing/pull/2359
+G Serial: Update to latest upstream (fixes potential port handle leak)
+G https://github.com/processing/processing/pull/2361
+J add affordance for mode developers to run from Eclipse
+J https://github.com/processing/processing/pull/2422
+J non-pde extensions for modes cause a crash
+J https://github.com/processing/processing/issues/2419
+J some hardcoding for .pde still exists
+J https://github.com/processing/processing/issues/2420
+X the PDE uses 15% of CPU while just sitting idle (thx to David Fokkema)
+X https://github.com/processing/processing/issues/1561
+X https://github.com/processing/processing/pull/2451
+X Update code signing for Processing.app for Mavericks changes
+X https://github.com/processing/processing/issues/2453
+o use --deep for codesign to work? (nope)
+o http://furbo.org/2013/10/17/code-signing-and-mavericks/
+o http://brockerhoff.net/RB/AppCheckerLite/
+J permit modes to specify alternate extension (.py for .pyde stuff)
+J https://github.com/processing/processing/pull/2452
+X sketchPath() returns user.home in exported apps on OSX
+X https://github.com/processing/processing/issues/2181
+
+
+0224 pde (2.1.1)
+M fix infinite loop in Find/Replace
+M https://github.com/processing/processing/issues/2082
+X updated to Minim 2.2
+X https://github.com/processing/processing/pull/2250
+X minor change to bracket handling
+X https://github.com/processing/processing/pull/2313
+X app is called procesing.app.Base
+X https://github.com/processing/processing/issues/2217
+X noJavaArg set to --export
+X https://github.com/processing/processing/issues/2182
+X export not working on Windows
+X https://github.com/processing/processing/issues/2219
+X right-click on selection is a problem on Windows
+X https://github.com/processing/processing/issues/2210
+G Add Contents/Java to java.library.path for loadLibrary to find .jnilib files
+X jnilib not loading on OS X because Contents/Java needs to be added to path
+X https://github.com/processing/processing/pull/2269
+
+serial
+G readStringUntil() missing from new serial library
+G https://github.com/processing/processing/issues/2174
+G updates to serial library
+G https://github.com/processing/processing/pull/2265
+G serial running slowly
+G https://github.com/processing/processing/issues/2249
+G https://github.com/processing/processing/issues/2214
+G Only read a single character at a time to emulate RXTX behavior
+G https://github.com/processing/processing/pull/2240
+G Add basic tests for throughput and latency
+G https://github.com/processing/processing/pull/2225
+G Add a debug() method to Serial
+G https://github.com/processing/processing/pull/2237
+G Switch the examples over to printArray()
+G https://github.com/processing/processing/pull/2226
+G Handle the UnsatisfiedLinkError when loading the native library fails
+G https://github.com/processing/processing/pull/2266
+
+fixed in 2.1
+X init() not called on tools until later
+X https://github.com/processing/processing/issues/1859
+X Finish changes so the PDE can use an unmodified JRE
+X https://github.com/processing/processing/issues/1840
+
+
+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
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/bin/processing/mode/experimental/ArrayFieldNode.class b/experimental/bin/processing/mode/experimental/ArrayFieldNode.class
new file mode 100644
index 000000000..d810c99f6
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ArrayFieldNode.class differ
diff --git a/experimental/bin/processing/mode/experimental/ClassLoadListener.class b/experimental/bin/processing/mode/experimental/ClassLoadListener.class
new file mode 100644
index 000000000..7bc9c8c57
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ClassLoadListener.class differ
diff --git a/experimental/bin/processing/mode/experimental/Compiler$1.class b/experimental/bin/processing/mode/experimental/Compiler$1.class
new file mode 100644
index 000000000..9d42778a3
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Compiler$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/Compiler.class b/experimental/bin/processing/mode/experimental/Compiler.class
new file mode 100644
index 000000000..a14e4885a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Compiler.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugBuild.class b/experimental/bin/processing/mode/experimental/DebugBuild.class
new file mode 100644
index 000000000..4a663d33e
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugBuild.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$1.class b/experimental/bin/processing/mode/experimental/DebugEditor$1.class
new file mode 100644
index 000000000..bd9e889f2
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$2.class b/experimental/bin/processing/mode/experimental/DebugEditor$2.class
new file mode 100644
index 000000000..a5ed608e0
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$3.class b/experimental/bin/processing/mode/experimental/DebugEditor$3.class
new file mode 100644
index 000000000..bdb47ccb8
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$3.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$4.class b/experimental/bin/processing/mode/experimental/DebugEditor$4.class
new file mode 100644
index 000000000..5601253fb
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$4.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$5.class b/experimental/bin/processing/mode/experimental/DebugEditor$5.class
new file mode 100644
index 000000000..5d4c1998b
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$5.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$6.class b/experimental/bin/processing/mode/experimental/DebugEditor$6.class
new file mode 100644
index 000000000..1020dc4d7
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$6.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor$7.class b/experimental/bin/processing/mode/experimental/DebugEditor$7.class
new file mode 100644
index 000000000..f09aa01f5
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor$7.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugEditor.class b/experimental/bin/processing/mode/experimental/DebugEditor.class
new file mode 100644
index 000000000..aa284462e
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugEditor.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugRunner.class b/experimental/bin/processing/mode/experimental/DebugRunner.class
new file mode 100644
index 000000000..44b0e4c33
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugRunner.class differ
diff --git a/experimental/bin/processing/mode/experimental/DebugToolbar.class b/experimental/bin/processing/mode/experimental/DebugToolbar.class
new file mode 100644
index 000000000..0e43e41cc
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/DebugToolbar.class differ
diff --git a/experimental/bin/processing/mode/experimental/Debugger$1.class b/experimental/bin/processing/mode/experimental/Debugger$1.class
new file mode 100644
index 000000000..9fb972059
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Debugger$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/Debugger$2.class b/experimental/bin/processing/mode/experimental/Debugger$2.class
new file mode 100644
index 000000000..11bb9aca4
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Debugger$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/Debugger$3.class b/experimental/bin/processing/mode/experimental/Debugger$3.class
new file mode 100644
index 000000000..f46084b84
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Debugger$3.class differ
diff --git a/experimental/bin/processing/mode/experimental/Debugger.class b/experimental/bin/processing/mode/experimental/Debugger.class
new file mode 100644
index 000000000..37f813aa1
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Debugger.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar$1.class b/experimental/bin/processing/mode/experimental/ErrorBar$1.class
new file mode 100644
index 000000000..fc02ee6e8
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar$2$1.class b/experimental/bin/processing/mode/experimental/ErrorBar$2$1.class
new file mode 100644
index 000000000..2e9331c51
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar$2$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar$2.class b/experimental/bin/processing/mode/experimental/ErrorBar$2.class
new file mode 100644
index 000000000..33292428e
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar$3$1.class b/experimental/bin/processing/mode/experimental/ErrorBar$3$1.class
new file mode 100644
index 000000000..59f997ae5
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar$3$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar$3.class b/experimental/bin/processing/mode/experimental/ErrorBar$3.class
new file mode 100644
index 000000000..79949bd9a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar$3.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorBar.class b/experimental/bin/processing/mode/experimental/ErrorBar.class
new file mode 100644
index 000000000..1cb4fa38a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorBar.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorCheckerService$1.class b/experimental/bin/processing/mode/experimental/ErrorCheckerService$1.class
new file mode 100644
index 000000000..8aa36c468
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorCheckerService$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorCheckerService$2.class b/experimental/bin/processing/mode/experimental/ErrorCheckerService$2.class
new file mode 100644
index 000000000..0fb2f0358
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorCheckerService$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorCheckerService.class b/experimental/bin/processing/mode/experimental/ErrorCheckerService.class
new file mode 100644
index 000000000..3f6d985ca
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorCheckerService.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorMarker.class b/experimental/bin/processing/mode/experimental/ErrorMarker.class
new file mode 100644
index 000000000..03082b261
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorMarker.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow$1.class b/experimental/bin/processing/mode/experimental/ErrorWindow$1.class
new file mode 100644
index 000000000..960e8e87f
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow$2.class b/experimental/bin/processing/mode/experimental/ErrorWindow$2.class
new file mode 100644
index 000000000..debae2269
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow$3.class b/experimental/bin/processing/mode/experimental/ErrorWindow$3.class
new file mode 100644
index 000000000..e1e0263b4
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow$3.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow$4.class b/experimental/bin/processing/mode/experimental/ErrorWindow$4.class
new file mode 100644
index 000000000..01edf192a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow$4.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow$DockTool2Base.class b/experimental/bin/processing/mode/experimental/ErrorWindow$DockTool2Base.class
new file mode 100644
index 000000000..209f57f8a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow$DockTool2Base.class differ
diff --git a/experimental/bin/processing/mode/experimental/ErrorWindow.class b/experimental/bin/processing/mode/experimental/ErrorWindow.class
new file mode 100644
index 000000000..7fdede082
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ErrorWindow.class differ
diff --git a/experimental/bin/processing/mode/experimental/ExperimentalMode.class b/experimental/bin/processing/mode/experimental/ExperimentalMode.class
new file mode 100644
index 000000000..4b3b49906
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ExperimentalMode.class differ
diff --git a/experimental/bin/processing/mode/experimental/FieldNode.class b/experimental/bin/processing/mode/experimental/FieldNode.class
new file mode 100644
index 000000000..47df32561
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/FieldNode.class differ
diff --git a/experimental/bin/processing/mode/experimental/ImportStatement.class b/experimental/bin/processing/mode/experimental/ImportStatement.class
new file mode 100644
index 000000000..b7cd604b5
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/ImportStatement.class differ
diff --git a/experimental/bin/processing/mode/experimental/LineBreakpoint.class b/experimental/bin/processing/mode/experimental/LineBreakpoint.class
new file mode 100644
index 000000000..584e0731b
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/LineBreakpoint.class differ
diff --git a/experimental/bin/processing/mode/experimental/LineHighlight.class b/experimental/bin/processing/mode/experimental/LineHighlight.class
new file mode 100644
index 000000000..dc2af19f9
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/LineHighlight.class differ
diff --git a/experimental/bin/processing/mode/experimental/LineID.class b/experimental/bin/processing/mode/experimental/LineID.class
new file mode 100644
index 000000000..2999a5254
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/LineID.class differ
diff --git a/experimental/bin/processing/mode/experimental/LineListener.class b/experimental/bin/processing/mode/experimental/LineListener.class
new file mode 100644
index 000000000..b61b03aa6
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/LineListener.class differ
diff --git a/experimental/bin/processing/mode/experimental/LocalVariableNode.class b/experimental/bin/processing/mode/experimental/LocalVariableNode.class
new file mode 100644
index 000000000..c1bca7c71
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/LocalVariableNode.class differ
diff --git a/experimental/bin/processing/mode/experimental/Problem.class b/experimental/bin/processing/mode/experimental/Problem.class
new file mode 100644
index 000000000..647bebe1f
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/Problem.class differ
diff --git a/experimental/bin/processing/mode/experimental/TextArea$MouseHandler.class b/experimental/bin/processing/mode/experimental/TextArea$MouseHandler.class
new file mode 100644
index 000000000..1443acd29
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/TextArea$MouseHandler.class differ
diff --git a/experimental/bin/processing/mode/experimental/TextArea.class b/experimental/bin/processing/mode/experimental/TextArea.class
new file mode 100644
index 000000000..35092f97c
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/TextArea.class differ
diff --git a/experimental/bin/processing/mode/experimental/TextAreaPainter.class b/experimental/bin/processing/mode/experimental/TextAreaPainter.class
new file mode 100644
index 000000000..e30560f62
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/TextAreaPainter.class differ
diff --git a/experimental/bin/processing/mode/experimental/VMEventListener.class b/experimental/bin/processing/mode/experimental/VMEventListener.class
new file mode 100644
index 000000000..9c3388a89
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VMEventListener.class differ
diff --git a/experimental/bin/processing/mode/experimental/VMEventReader.class b/experimental/bin/processing/mode/experimental/VMEventReader.class
new file mode 100644
index 000000000..f82358344
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VMEventReader.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$1.class b/experimental/bin/processing/mode/experimental/VariableInspector$1.class
new file mode 100644
index 000000000..8a600c79d
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$ExpansionHandler.class b/experimental/bin/processing/mode/experimental/VariableInspector$ExpansionHandler.class
new file mode 100644
index 000000000..fce996cc7
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$ExpansionHandler.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$LocalHidesThisFilter.class b/experimental/bin/processing/mode/experimental/VariableInspector$LocalHidesThisFilter.class
new file mode 100644
index 000000000..d05f3f2d3
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$LocalHidesThisFilter.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$OutlineRenderer.class b/experimental/bin/processing/mode/experimental/VariableInspector$OutlineRenderer.class
new file mode 100644
index 000000000..bcb9d6730
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$OutlineRenderer.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$P5BuiltinsFilter.class b/experimental/bin/processing/mode/experimental/VariableInspector$P5BuiltinsFilter.class
new file mode 100644
index 000000000..d33057608
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$P5BuiltinsFilter.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$ThisFilter.class b/experimental/bin/processing/mode/experimental/VariableInspector$ThisFilter.class
new file mode 100644
index 000000000..d3eca6f36
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$ThisFilter.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellEditor.class b/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellEditor.class
new file mode 100644
index 000000000..ea0c75006
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellEditor.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellRenderer.class b/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellRenderer.class
new file mode 100644
index 000000000..066a623dd
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$ValueCellRenderer.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$VariableNodeFilter.class b/experimental/bin/processing/mode/experimental/VariableInspector$VariableNodeFilter.class
new file mode 100644
index 000000000..8f4cc601b
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$VariableNodeFilter.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector$VariableRowModel.class b/experimental/bin/processing/mode/experimental/VariableInspector$VariableRowModel.class
new file mode 100644
index 000000000..e0fe9c45c
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector$VariableRowModel.class differ
diff --git a/experimental/bin/processing/mode/experimental/VariableInspector.class b/experimental/bin/processing/mode/experimental/VariableInspector.class
new file mode 100644
index 000000000..0d6855fbd
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableInspector.class differ
diff --git a/experimental/src/processing/mode/experimental/VariableInspector.form b/experimental/bin/processing/mode/experimental/VariableInspector.form
similarity index 100%
rename from experimental/src/processing/mode/experimental/VariableInspector.form
rename to experimental/bin/processing/mode/experimental/VariableInspector.form
diff --git a/experimental/bin/processing/mode/experimental/VariableNode.class b/experimental/bin/processing/mode/experimental/VariableNode.class
new file mode 100644
index 000000000..4f9319a7f
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/VariableNode.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQConsoleToggle.class b/experimental/bin/processing/mode/experimental/XQConsoleToggle.class
new file mode 100644
index 000000000..1cb46898d
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQConsoleToggle.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQErrorTable$1.class b/experimental/bin/processing/mode/experimental/XQErrorTable$1.class
new file mode 100644
index 000000000..0293992a3
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQErrorTable$1.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQErrorTable$2.class b/experimental/bin/processing/mode/experimental/XQErrorTable$2.class
new file mode 100644
index 000000000..9801e5bbf
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQErrorTable$2.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQErrorTable$3.class b/experimental/bin/processing/mode/experimental/XQErrorTable$3.class
new file mode 100644
index 000000000..72b64419d
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQErrorTable$3.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQErrorTable.class b/experimental/bin/processing/mode/experimental/XQErrorTable.class
new file mode 100644
index 000000000..d092c182c
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQErrorTable.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQPreprocessor$XQASTVisitor.class b/experimental/bin/processing/mode/experimental/XQPreprocessor$XQASTVisitor.class
new file mode 100644
index 000000000..14124898a
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQPreprocessor$XQASTVisitor.class differ
diff --git a/experimental/bin/processing/mode/experimental/XQPreprocessor.class b/experimental/bin/processing/mode/experimental/XQPreprocessor.class
new file mode 100644
index 000000000..81a3e361f
Binary files /dev/null and b/experimental/bin/processing/mode/experimental/XQPreprocessor.class differ
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 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/experimental/mode/.gitignore b/experimental/mode/.gitignore
deleted file mode 100644
index 9acf0e7e9..000000000
--- a/experimental/mode/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-experimental.jar
diff --git a/experimental/mode/readme.txt b/experimental/mode/readme.txt
deleted file mode 100644
index 2152b63de..000000000
--- a/experimental/mode/readme.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Packages from Eclipse 4.2.1:
-http://download.eclipse.org/eclipse/downloads/
-
-The jdi.jar and jdimodel.jar files are unpacked
-from the org.eclipse.jdt.debug JAR file.
diff --git a/experimental/src/processing/mode/experimental/ArrayFieldNode.java b/experimental/src/processing/mode/experimental/ArrayFieldNode.java
deleted file mode 100755
index 04b3fb111..000000000
--- a/experimental/src/processing/mode/experimental/ArrayFieldNode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.ArrayReference;
-import com.sun.jdi.ClassNotLoadedException;
-import com.sun.jdi.InvalidTypeException;
-import com.sun.jdi.Value;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Specialized {@link VariableNode} for representing single fields in an array.
- * Overrides {@link #setValue} to properly change the value of the encapsulated
- * array field.
- *
- * @author Martin Leopold
- */
-public class ArrayFieldNode extends VariableNode {
-
- protected ArrayReference array;
- protected int index;
-
- /**
- * Construct an {@link ArrayFieldNode}.
- *
- * @param name the name
- * @param type the type
- * @param value the value
- * @param array a reference to the array
- * @param index the index inside the array
- */
- public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) {
- super(name, type, value);
- this.array = array;
- this.index = index;
- }
-
- @Override
- public void setValue(Value value) {
- try {
- array.setValue(index, value);
- } catch (InvalidTypeException ex) {
- Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex);
- } catch (ClassNotLoadedException ex) {
- Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex);
- }
- this.value = value;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/ClassLoadListener.java b/experimental/src/processing/mode/experimental/ClassLoadListener.java
deleted file mode 100755
index 64bd5516b..000000000
--- a/experimental/src/processing/mode/experimental/ClassLoadListener.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.ReferenceType;
-
-/**
- * Listener to be notified when a class is loaded in the debugger. Used by
- * {@link LineBreakpoint}s to activate themselves as soon as the respective
- * class is loaded.
- *
- * @author Martin Leopold
- */
-public interface ClassLoadListener {
-
- /**
- * Event handler called when a class is loaded.
- *
- * @param theClass the class
- */
- public void classLoaded(ReferenceType theClass);
-}
diff --git a/experimental/src/processing/mode/experimental/Compiler.java b/experimental/src/processing/mode/experimental/Compiler.java
deleted file mode 100755
index 1a85c6a29..000000000
--- a/experimental/src/processing/mode/experimental/Compiler.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.io.*;
-import java.lang.reflect.Method;
-import processing.app.Base;
-import processing.app.SketchException;
-import processing.core.PApplet;
-
-/**
- * Copied from processing.mode.java.Compiler, just added -g switch to generate
- * debugging info.
- *
- * @author Martin Leopold
- */
-public class Compiler extends processing.mode.java.Compiler {
- /**
- * Compile with ECJ. See http://j.mp/8paifz for documentation.
- *
- * @return true if successful.
- * @throws RunnerException Only if there's a problem. Only then.
- */
-// public boolean compile(Sketch sketch,
-// File srcFolder,
-// File binFolder,
-// String primaryClassName,
-// String sketchClassPath,
-// String bootClassPath) throws RunnerException {
- static public boolean compile(DebugBuild build) throws SketchException {
-
- // This will be filled in if anyone gets angry
- SketchException exception = null;
- boolean success = false;
-
- String baseCommand[] = new String[] {
- "-g",
- "-Xemacs",
- //"-noExit", // not necessary for ecj
- "-source", "1.6",
- "-target", "1.6",
- "-classpath", build.getClassPath(),
- "-nowarn", // we're not currently interested in warnings (works in ecj)
- "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath
- };
- //PApplet.println(baseCommand);
-
- // make list of code files that need to be compiled
-// String[] sourceFiles = new String[sketch.getCodeCount()];
-// int sourceCount = 0;
-// sourceFiles[sourceCount++] =
-// new File(buildPath, primaryClassName + ".java").getAbsolutePath();
-//
-// for (SketchCode code : sketch.getCode()) {
-// if (code.isExtension("java")) {
-// String path = new File(buildPath, code.getFileName()).getAbsolutePath();
-// sourceFiles[sourceCount++] = path;
-// }
-// }
- String[] sourceFiles = Base.listFiles(build.getSrcFolder(), false, ".java");
-
-// String[] command = new String[baseCommand.length + sourceFiles.length];
-// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
-// // append each of the files to the command string
-// System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount);
- String[] command = PApplet.concat(baseCommand, sourceFiles);
-
- //PApplet.println(command);
-
- try {
- // Load errors into a local StringBuffer
- final StringBuffer errorBuffer = new StringBuffer();
-
- // Create single method dummy writer class to slurp errors from ecj
- Writer internalWriter = new Writer() {
- public void write(char[] buf, int off, int len) {
- errorBuffer.append(buf, off, len);
- }
-
- public void flush() { }
-
- public void close() { }
- };
- // Wrap as a PrintWriter since that's what compile() wants
- PrintWriter writer = new PrintWriter(internalWriter);
-
- //result = com.sun.tools.javac.Main.compile(command, writer);
-
- PrintWriter outWriter = new PrintWriter(System.out);
-
- // Version that's not dynamically loaded
- //CompilationProgress progress = null;
- //success = BatchCompiler.compile(command, outWriter, writer, progress);
-
- // Version that *is* dynamically loaded. First gets the mode class loader
- // so that it can grab the compiler JAR files from it.
- ClassLoader loader = build.getMode().getJavaModeClassLoader();
- //ClassLoader loader = build.getMode().getClassLoader();
- try {
- Class batchClass =
- Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader);
- Class progressClass =
- Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader);
- Class[] compileArgs =
- new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass };
- Method compileMethod = batchClass.getMethod("compile", compileArgs);
- success = (Boolean)
- compileMethod.invoke(null, new Object[] { command, outWriter, writer, null });
- } catch (Exception e) {
- e.printStackTrace();
- throw new SketchException("Unknown error inside the compiler.");
- }
-
- // Close out the stream for good measure
- writer.flush();
- writer.close();
-
- BufferedReader reader =
- new BufferedReader(new StringReader(errorBuffer.toString()));
- //System.err.println(errorBuffer.toString());
-
- String line = null;
- while ((line = reader.readLine()) != null) {
- //System.out.println("got line " + line); // debug
-
- // get first line, which contains file name, line number,
- // and at least the first line of the error message
- String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*";
- String[] pieces = PApplet.match(line, errorFormat);
- //PApplet.println(pieces);
-
- // if it's something unexpected, die and print the mess to the console
- if (pieces == null) {
- exception = new SketchException("Cannot parse error text: " + line);
- exception.hideStackTrace();
- // Send out the rest of the error message to the console.
- System.err.println(line);
- while ((line = reader.readLine()) != null) {
- System.err.println(line);
- }
- break;
- }
-
- // translate the java filename and line number into a un-preprocessed
- // location inside a source file or tab in the environment.
- String dotJavaFilename = pieces[1];
- // Line numbers are 1-indexed from javac
- int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1;
- String errorMessage = pieces[4];
-
- exception = build.placeException(errorMessage,
- dotJavaFilename,
- dotJavaLineIndex);
- /*
- int codeIndex = 0; //-1;
- int codeLine = -1;
-
- // first check to see if it's a .java file
- for (int i = 0; i < sketch.getCodeCount(); i++) {
- SketchCode code = sketch.getCode(i);
- if (code.isExtension("java")) {
- if (dotJavaFilename.equals(code.getFileName())) {
- codeIndex = i;
- codeLine = dotJavaLineIndex;
- }
- }
- }
-
- // if it's not a .java file, codeIndex will still be 0
- if (codeIndex == 0) { // main class, figure out which tab
- //for (int i = 1; i < sketch.getCodeCount(); i++) {
- for (int i = 0; i < sketch.getCodeCount(); i++) {
- SketchCode code = sketch.getCode(i);
-
- if (code.isExtension("pde")) {
- if (code.getPreprocOffset() <= dotJavaLineIndex) {
- codeIndex = i;
- //System.out.println("i'm thinkin file " + i);
- codeLine = dotJavaLineIndex - code.getPreprocOffset();
- }
- }
- }
- }
- //System.out.println("code line now " + codeLine);
- exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false);
- */
-
- if (exception == null) {
- exception = new SketchException(errorMessage);
- }
-
- // for a test case once message parsing is implemented,
- // use new Font(...) since that wasn't getting picked up properly.
-
- /*
- if (errorMessage.equals("cannot find symbol")) {
- handleCannotFindSymbol(reader, exception);
-
- } else if (errorMessage.indexOf("is already defined") != -1) {
- reader.readLine(); // repeats the line of code w/ error
- int codeColumn = caretColumn(reader.readLine());
- exception = new RunnerException(errorMessage,
- codeIndex, codeLine, codeColumn);
-
- } else if (errorMessage.startsWith("package") &&
- errorMessage.endsWith("does not exist")) {
- // Because imports are stripped out and re-added to the 0th line of
- // the preprocessed code, codeLine will always be wrong for imports.
- exception = new RunnerException("P" + errorMessage.substring(1) +
- ". You might be missing a library.");
- } else {
- exception = new RunnerException(errorMessage);
- }
- */
- if (errorMessage.startsWith("The import ") &&
- errorMessage.endsWith("cannot be resolved")) {
- // The import poo cannot be resolved
- //import poo.shoe.blah.*;
- //String what = errorMessage.substring("The import ".length());
- String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved");
- //what = what.substring(0, what.indexOf(' '));
- if (m != null) {
-// System.out.println("'" + m[1] + "'");
- if (m[1].equals("processing.xml")) {
- exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0.");
- System.err.println("The processing.xml library has been replaced " +
- "with a new 'XML' class that's built-in.");
- handleCrustyCode();
-
- } else {
- exception.setMessage("The package " +
- "\u201C" + m[1] + "\u201D" +
- " does not exist. " +
- "You might be missing a library.");
- System.err.println("Libraries must be " +
- "installed in a folder named 'libraries' " +
- "inside the 'sketchbook' folder.");
- }
- }
-
-// // Actually create the folder and open it for the user
-// File sketchbookLibraries = Base.getSketchbookLibrariesFolder();
-// if (!sketchbookLibraries.exists()) {
-// if (sketchbookLibraries.mkdirs()) {
-// Base.openFolder(sketchbookLibraries);
-// }
-// }
-
- } else if (errorMessage.endsWith("cannot be resolved to a type")) {
- // xxx cannot be resolved to a type
- //xxx c;
-
- String what = errorMessage.substring(0, errorMessage.indexOf(' '));
-
- if (what.equals("BFont") ||
- what.equals("BGraphics") ||
- what.equals("BImage")) {
- exception.setMessage(what + " has been replaced with P" + what.substring(1));
- handleCrustyCode();
-
- } else {
- exception.setMessage("Cannot find a class or type " +
- "named \u201C" + what + "\u201D");
- }
-
- } else if (errorMessage.endsWith("cannot be resolved")) {
- // xxx cannot be resolved
- //println(xxx);
-
- String what = errorMessage.substring(0, errorMessage.indexOf(' '));
-
- if (what.equals("LINE_LOOP") ||
- what.equals("LINE_STRIP")) {
- exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " +
- "please update your code.");
- handleCrustyCode();
-
- } else if (what.equals("framerate")) {
- exception.setMessage("framerate should be changed to frameRate.");
- handleCrustyCode();
-
- } else if (what.equals("screen")) {
- exception.setMessage("Change screen.width and screen.height to " +
- "displayWidth and displayHeight.");
- handleCrustyCode();
-
- } else if (what.equals("screenWidth") ||
- what.equals("screenHeight")) {
- exception.setMessage("Change screenWidth and screenHeight to " +
- "displayWidth and displayHeight.");
- handleCrustyCode();
-
- } else {
- exception.setMessage("Cannot find anything " +
- "named \u201C" + what + "\u201D");
- }
-
- } else if (errorMessage.startsWith("Duplicate")) {
- // "Duplicate nested type xxx"
- // "Duplicate local variable xxx"
-
- } else {
- String[] parts = null;
-
- // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX
- //xxx("blah");
- // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX
- //xxx("blah", 34);
- // The method xxx(String, int) is undefined for the type PApplet
- //PApplet.sub("ding");
- String undefined =
- "The method (\\S+\\(.*\\)) is undefined for the type (.*)";
- parts = PApplet.match(errorMessage, undefined);
- if (parts != null) {
- if (parts[1].equals("framerate(int)")) {
- exception.setMessage("framerate() no longer exists, use frameRate() instead.");
- handleCrustyCode();
-
- } else if (parts[1].equals("push()")) {
- exception.setMessage("push() no longer exists, use pushMatrix() instead.");
- handleCrustyCode();
-
- } else if (parts[1].equals("pop()")) {
- exception.setMessage("pop() no longer exists, use popMatrix() instead.");
- handleCrustyCode();
-
- } else {
- String mess = "The function " + parts[1] + " does not exist.";
- exception.setMessage(mess);
- }
- break;
- }
- }
- if (exception != null) {
- // The stack trace just shows that this happened inside the compiler,
- // which is a red herring. Don't ever show it for compiler stuff.
- exception.hideStackTrace();
- break;
- }
- }
- } catch (IOException e) {
- String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
- exception = new SketchException(bigSigh);
- e.printStackTrace();
- success = false;
- }
- // In case there was something else.
- if (exception != null) throw exception;
-
- return success;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/DebugBuild.java b/experimental/src/processing/mode/experimental/DebugBuild.java
deleted file mode 100755
index fdb9b34e3..000000000
--- a/experimental/src/processing/mode/experimental/DebugBuild.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.io.File;
-import processing.app.Sketch;
-import processing.app.SketchException;
-import processing.mode.java.JavaBuild;
-
-/**
- * Copied from processing.mode.java.JavaBuild, just changed compiler.
- *
- * @author Martin Leopold
- */
-public class DebugBuild extends JavaBuild {
-
- public DebugBuild(Sketch sketch) {
- super(sketch);
- }
-
- /**
- * Preprocess and compile sketch. Copied from
- * processing.mode.java.JavaBuild, just changed compiler.
- *
- * @param srcFolder
- * @param binFolder
- * @param sizeWarning
- * @return main class name or null on compile failure
- * @throws SketchException
- */
- @Override
- public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException {
- this.srcFolder = srcFolder;
- this.binFolder = binFolder;
-
-// Base.openFolder(srcFolder);
-// Base.openFolder(binFolder);
-
- // run the preprocessor
- String classNameFound = preprocess(srcFolder, sizeWarning);
-
- // compile the program. errors will happen as a RunnerException
- // that will bubble up to whomever called build().
-// Compiler compiler = new Compiler(this);
-// String bootClasses = System.getProperty("sun.boot.class.path");
-// if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) {
-
- if (Compiler.compile(this)) { // use compiler with debug info enabled (-g switch flicked)
- sketchClassName = classNameFound;
- return classNameFound;
- }
- return null;
- }
-
- public ExperimentalMode getMode() {
- return (ExperimentalMode)mode;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/DebugEditor.java b/experimental/src/processing/mode/experimental/DebugEditor.java
deleted file mode 100755
index 91bf862b9..000000000
--- a/experimental/src/processing/mode/experimental/DebugEditor.java
+++ /dev/null
@@ -1,1141 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Color;
-import java.awt.EventQueue;
-import java.awt.Frame;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.swing.Box;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.border.EtchedBorder;
-import javax.swing.table.TableModel;
-import javax.swing.text.Document;
-import processing.app.*;
-import processing.app.syntax.JEditTextArea;
-import processing.app.syntax.PdeTextAreaDefaults;
-import processing.core.PApplet;
-import processing.mode.java.JavaEditor;
-
-/**
- * Main View Class. Handles the editor window including tool bar and menu. Has
- * access to the Sketch. Provides line highlighting (for breakpoints and the
- * debuggers current line).
- *
- * @author Martin Leopold
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- *
- */
-public class DebugEditor extends JavaEditor implements ActionListener {
- // important fields from superclass
- //protected Sketch sketch;
- //private JMenu fileMenu;
- //protected EditorToolbar toolbar;
-
- // highlighting
- protected Color breakpointColor = new Color(240, 240, 240); // the background color for highlighting lines
- protected Color currentLineColor = new Color(255, 255, 150); // the background color for highlighting lines
- protected Color breakpointMarkerColor = new Color(74, 84, 94); // the color of breakpoint gutter markers
- protected Color currentLineMarkerColor = new Color(226, 117, 0); // the color of current line gutter markers
- protected List breakpointedLines = new ArrayList(); // breakpointed lines
- protected LineHighlight currentLine; // line the debugger is currently suspended at
- protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment
- // menus
- protected JMenu debugMenu; // the debug menu
- // debugger control
- protected JMenuItem debugMenuItem;
- protected JMenuItem continueMenuItem;
- protected JMenuItem stopMenuItem;
- // breakpoints
- protected JMenuItem toggleBreakpointMenuItem;
- protected JMenuItem listBreakpointsMenuItem;
- // stepping
- protected JMenuItem stepOverMenuItem;
- protected JMenuItem stepIntoMenuItem;
- protected JMenuItem stepOutMenuItem;
- // info
- protected JMenuItem printStackTraceMenuItem;
- protected JMenuItem printLocalsMenuItem;
- protected JMenuItem printThisMenuItem;
- protected JMenuItem printSourceMenuItem;
- protected JMenuItem printThreads;
- // variable inspector
- protected JMenuItem toggleVariableInspectorMenuItem;
- // references
- protected ExperimentalMode dmode; // the mode
- protected Debugger dbg; // the debugger
- protected VariableInspector vi; // the variable inspector frame
- protected TextArea ta; // the text area
-
-
- protected ErrorBar errorBar;
- /**
- * Show Console button
- */
- protected XQConsoleToggle btnShowConsole;
-
- /**
- * Show Problems button
- */
- protected XQConsoleToggle btnShowErrors;
-
- /**
- * Scroll pane for Error Table
- */
- protected JScrollPane errorTableScrollPane;
-
- /**
- * Panel with card layout which contains the p5 console and Error Table
- * panes
- */
- protected JPanel consoleProblemsPane;
-
- protected XQErrorTable errorTable;
-
- /**
- * Enable/Disable compilation checking
- */
- protected boolean compilationCheckEnabled = true;
-
- /**
- * Show warnings menu item
- */
- protected JCheckBoxMenuItem showWarnings;
-
- /**
- * Check box menu item for show/hide Problem Window
- */
- public JCheckBoxMenuItem problemWindowMenuCB;
-
- public DebugEditor(Base base, String path, EditorState state, Mode mode) {
- super(base, path, state, mode);
-
- // get mode
- dmode = (ExperimentalMode) mode;
-
- // init controller class
- dbg = new Debugger(this);
-
- // variable inspector window
- vi = new VariableInspector(this);
-
- // access to customized (i.e. subclassed) text area
- ta = (TextArea) textarea;
-
- // set action on frame close
-// addWindowListener(new WindowAdapter() {
-// @Override
-// public void windowClosing(WindowEvent e) {
-// onWindowClosing(e);
-// }
-// });
-
- // load settings from theme.txt
- ExperimentalMode theme = dmode;
- breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor);
- breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor);
- currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor);
- currentLineMarkerColor = theme.getThemeColor("currentline.marker.color", currentLineMarkerColor);
-
- // set breakpoints from marker comments
- for (LineID lineID : stripBreakpointComments()) {
- //System.out.println("setting: " + lineID);
- dbg.setBreakpoint(lineID);
- }
- getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here
-
- checkForJavaTabs();
- initializeErrorChecker();
- ta.setECSandThemeforTextArea(errorCheckerService, dmode);
- addXQModeUI();
- }
-
- private void addXQModeUI(){
-
- // Adding ErrorBar
- JPanel textAndError = new JPanel();
- Box box = (Box) textarea.getParent();
- box.remove(2); // Remove textArea from it's container, i.e Box
- textAndError.setLayout(new BorderLayout());
- errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode);
- textAndError.add(errorBar, BorderLayout.EAST);
- textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight());
- textAndError.add(textarea);
- box.add(textAndError);
-
- // Adding Error Table in a scroll pane
- errorTableScrollPane = new JScrollPane();
- errorTable = new XQErrorTable(errorCheckerService);
- // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2));
- errorTableScrollPane.setBorder(new EtchedBorder());
- errorTableScrollPane.setViewportView(errorTable);
-
- // Adding toggle console button
- consolePanel.remove(2);
- JPanel lineStatusPanel = new JPanel();
- lineStatusPanel.setLayout(new BorderLayout());
- btnShowConsole = new XQConsoleToggle(this,
- XQConsoleToggle.text[0], lineStatus.getHeight());
- btnShowErrors = new XQConsoleToggle(this,
- XQConsoleToggle.text[1], lineStatus.getHeight());
- btnShowConsole.addMouseListener(btnShowConsole);
-
- // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST);
- // lineStatusPanel.add(btnShowErrors);
- btnShowErrors.addMouseListener(btnShowErrors);
-
- JPanel toggleButtonPanel = new JPanel(new BorderLayout());
- toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST);
- toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST);
- lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST);
- lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1,
- toggleButtonPanel.getHeight());
- lineStatusPanel.add(lineStatus);
- consolePanel.add(lineStatusPanel, BorderLayout.SOUTH);
- lineStatusPanel.repaint();
-
- // Adding JPanel with CardLayout for Console/Problems Toggle
- consolePanel.remove(1);
- consoleProblemsPane = new JPanel(new CardLayout());
- consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.text[1]);
- consoleProblemsPane.add(console, XQConsoleToggle.text[0]);
- consolePanel.add(consoleProblemsPane, BorderLayout.CENTER);
- }
-
-// /**
-// * Event handler called when closing the editor window. Kills the variable
-// * inspector window.
-// *
-// * @param e the event object
-// */
-// protected void onWindowClosing(WindowEvent e) {
-// // remove var.inspector
-// vi.dispose();
-// // quit running debug session
-// dbg.stopDebug();
-// }
- /**
- * Used instead of the windowClosing event handler, since it's not called on
- * mode switch. Called when closing the editor window. Stops running debug
- * sessions and kills the variable inspector window.
- */
- @Override
- public void dispose() {
- //System.out.println("window dispose");
- // quit running debug session
- dbg.stopDebug();
- // remove var.inspector
- vi.dispose();
- // original dispose
- super.dispose();
- }
-
- /**
- * Overrides sketch menu creation to change keyboard shortcuts from "Run".
- *
- * @return the sketch menu
- */
- @Override
- public JMenu buildSketchMenu() {
- JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R);
- runItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- handleRun();
- }
- });
-
- JMenuItem presentItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.RUN, true));
- presentItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- handlePresent();
- }
- });
-
- JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, false));
- stopItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- handleStop();
- }
- });
- return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem});
- }
-
- /**
- * Creates the debug menu. Includes ActionListeners for the menu items.
- * Intended for adding to the menu bar.
- *
- * @return The debug menu
- */
- protected JMenu buildDebugMenu() {
- debugMenu = new JMenu("Debug");
-
- debugMenuItem = Toolkit.newJMenuItem("Debug", KeyEvent.VK_R);
- debugMenuItem.addActionListener(this);
- continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U);
- continueMenuItem.addActionListener(this);
- stopMenuItem = new JMenuItem("Stop");
- stopMenuItem.addActionListener(this);
-
- toggleBreakpointMenuItem = Toolkit.newJMenuItem("Toggle Breakpoint", KeyEvent.VK_B);
- toggleBreakpointMenuItem.addActionListener(this);
- listBreakpointsMenuItem = new JMenuItem("List Breakpoints");
- listBreakpointsMenuItem.addActionListener(this);
-
- stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_J);
- stepOverMenuItem.addActionListener(this);
- stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_J);
- stepIntoMenuItem.addActionListener(this);
- stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_J);
- stepOutMenuItem.addActionListener(this);
-
- printStackTraceMenuItem = new JMenuItem("Print Stack Trace");
- printStackTraceMenuItem.addActionListener(this);
- printLocalsMenuItem = new JMenuItem("Print Locals");
- printLocalsMenuItem.addActionListener(this);
- printThisMenuItem = new JMenuItem("Print Fields");
- printThisMenuItem.addActionListener(this);
- printSourceMenuItem = new JMenuItem("Print Source Location");
- printSourceMenuItem.addActionListener(this);
- printThreads = new JMenuItem("Print Threads");
- printThreads.addActionListener(this);
-
- toggleVariableInspectorMenuItem = Toolkit.newJMenuItem("Toggle Variable Inspector", KeyEvent.VK_I);
- toggleVariableInspectorMenuItem.addActionListener(this);
-
- debugMenu.add(debugMenuItem);
- debugMenu.add(continueMenuItem);
- debugMenu.add(stopMenuItem);
- debugMenu.addSeparator();
- debugMenu.add(toggleBreakpointMenuItem);
- debugMenu.add(listBreakpointsMenuItem);
- debugMenu.addSeparator();
- debugMenu.add(stepOverMenuItem);
- debugMenu.add(stepIntoMenuItem);
- debugMenu.add(stepOutMenuItem);
- debugMenu.addSeparator();
- debugMenu.add(printStackTraceMenuItem);
- debugMenu.add(printLocalsMenuItem);
- debugMenu.add(printThisMenuItem);
- debugMenu.add(printSourceMenuItem);
- debugMenu.add(printThreads);
- debugMenu.addSeparator();
- debugMenu.add(toggleVariableInspectorMenuItem);
- debugMenu.addSeparator();
-
- // XQMode menu items
-
- JCheckBoxMenuItem item;
- final DebugEditor thisEditor = this;
- item = new JCheckBoxMenuItem("Error Checker Enabled");
- item.setSelected(true);
- item.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
-
- if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) {
- // unticked Menu Item
- errorCheckerService.pauseThread();
- System.out.println(thisEditor.getSketch().getName()
- + " - Error Checker paused.");
- errorBar.errorPoints.clear();
- errorCheckerService.problemsList.clear();
- errorCheckerService.updateErrorTable();
- errorCheckerService.updateEditorStatus();
- getTextArea().repaint();
- errorBar.repaint();
- } else {
- errorCheckerService.resumeThread();
- System.out.println(thisEditor.getSketch().getName()
- + " - Error Checker resumed.");
- }
- }
- });
- debugMenu.add(item);
-
- problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window");
- // problemWindowMenuCB.setSelected(true);
- problemWindowMenuCB.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (errorCheckerService.errorWindow == null) {
- return;
- }
- errorCheckerService.errorWindow
- .setVisible(((JCheckBoxMenuItem) e.getSource())
- .isSelected());
- // switch to console, now that Error Window is open
- toggleView(XQConsoleToggle.text[0]);
- }
- });
- debugMenu.add(problemWindowMenuCB);
-
- showWarnings = new JCheckBoxMenuItem("Warnings Enabled");
- showWarnings.setSelected(true);
- showWarnings.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e
- .getSource()).isSelected();
- }
- });
- debugMenu.add(showWarnings);
-
-
- return debugMenu;
- }
-
- @Override
- public JMenu buildModeMenu() {
- return buildDebugMenu();
- }
-
- /**
- * Callback for menu items. Implementation of Swing ActionListener.
- *
- * @param ae Action event
- */
- @Override
- public void actionPerformed(ActionEvent ae) {
- //System.out.println("ActionEvent: " + ae.toString());
-
- JMenuItem source = (JMenuItem) ae.getSource();
- if (source == debugMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item");
- //dmode.handleDebug(sketch, this);
- dbg.startDebug();
- } else if (source == stopMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item");
- //dmode.handleDebug(sketch, this);
- dbg.stopDebug();
- } else if (source == continueMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item");
- //dmode.handleDebug(sketch, this);
- dbg.continueDebug();
- } else if (source == stepOverMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item");
- dbg.stepOver();
- } else if (source == stepIntoMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item");
- dbg.stepInto();
- } else if (source == stepOutMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item");
- dbg.stepOut();
- } else if (source == printStackTraceMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item");
- dbg.printStackTrace();
- } else if (source == printLocalsMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item");
- dbg.printLocals();
- } else if (source == printThisMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item");
- dbg.printThis();
- } else if (source == printSourceMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item");
- dbg.printSource();
- } else if (source == printThreads) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item");
- dbg.printThreads();
- } else if (source == toggleBreakpointMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item");
- dbg.toggleBreakpoint();
- } else if (source == listBreakpointsMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item");
- dbg.listBreakpoints();
- } else if (source == toggleVariableInspectorMenuItem) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item");
- toggleVariableInspector();
- }
- }
-
-// @Override
-// public void handleRun() {
-// dbg.continueDebug();
-// }
- /**
- * Event handler called when hitting the stop button. Stops a running debug
- * session or performs standard stop action if not currently debugging.
- */
- @Override
- public void handleStop() {
- if (dbg.isStarted()) {
- dbg.stopDebug();
- } else {
- super.handleStop();
- }
- }
-
- /**
- * Event handler called when loading another sketch in this editor. Clears
- * breakpoints of previous sketch.
- *
- * @param path
- * @return true if a sketch was opened, false if aborted
- */
- @Override
- protected boolean handleOpenInternal(String path) {
- boolean didOpen = super.handleOpenInternal(path);
- if (didOpen && dbg != null) {
- // should already been stopped (open calls handleStop)
- dbg.clearBreakpoints();
- clearBreakpointedLines(); // force clear breakpoint highlights
- variableInspector().reset(); // clear contents of variable inspector
- }
- return didOpen;
- }
-
- /**
- * Extract breakpointed lines from source code marker comments. This removes
- * marker comments from the editor text. Intended to be called on loading a
- * sketch, since re-setting the sketches contents after removing the markers
- * will clear all breakpoints.
- *
- * @return the list of {@link LineID}s where breakpoint marker comments were
- * removed from.
- */
- protected List stripBreakpointComments() {
- List bps = new ArrayList();
- // iterate over all tabs
- Sketch sketch = getSketch();
- for (int i = 0; i < sketch.getCodeCount(); i++) {
- SketchCode tab = sketch.getCode(i);
- String code = tab.getProgram();
- String lines[] = code.split("\\r?\\n"); // newlines not included
- //System.out.println(code);
-
- // scan code for breakpoint comments
- int lineIdx = 0;
- for (String line : lines) {
- //System.out.println(line);
- if (line.endsWith(breakpointMarkerComment)) {
- LineID lineID = new LineID(tab.getFileName(), lineIdx);
- bps.add(lineID);
- //System.out.println("found breakpoint: " + lineID);
- // got a breakpoint
- //dbg.setBreakpoint(lineID);
- int index = line.lastIndexOf(breakpointMarkerComment);
- lines[lineIdx] = line.substring(0, index);
- }
- lineIdx++;
- }
- //tab.setProgram(code);
- code = PApplet.join(lines, "\n");
- setTabContents(tab.getFileName(), code);
- }
- return bps;
- }
-
- /**
- * Add breakpoint marker comments to the source file of a specific tab. This
- * acts on the source file on disk, not the editor text. Intended to be
- * called just after saving the sketch.
- *
- * @param tabFilename the tab file name
- */
- protected void addBreakpointComments(String tabFilename) {
- SketchCode tab = getTab(tabFilename);
- List bps = dbg.getBreakpoints(tab.getFileName());
-
- // load the source file
- File sourceFile = new File(sketch.getFolder(), tab.getFileName());
- //System.out.println("file: " + sourceFile);
- try {
- String code = Base.loadFile(sourceFile);
- //System.out.println("code: " + code);
- String lines[] = code.split("\\r?\\n"); // newlines not included
- for (LineBreakpoint bp : bps) {
- //System.out.println("adding bp: " + bp.lineID());
- lines[bp.lineID().lineIdx()] += breakpointMarkerComment;
- }
- code = PApplet.join(lines, "\n");
- //System.out.println("new code: " + code);
- Base.saveFile(code, sourceFile);
- } catch (IOException ex) {
- Logger.getLogger(DebugEditor.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- @Override
- public boolean handleSave(boolean immediately) {
- //System.out.println("handleSave " + immediately);
-
- // note modified tabs
- final List modified = new ArrayList();
- for (int i = 0; i < getSketch().getCodeCount(); i++) {
- SketchCode tab = getSketch().getCode(i);
- if (tab.isModified()) {
- modified.add(tab.getFileName());
- }
- }
-
- boolean saved = super.handleSave(immediately);
- if (saved) {
- if (immediately) {
- for (String tabFilename : modified) {
- addBreakpointComments(tabFilename);
- }
- } else {
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- for (String tabFilename : modified) {
- addBreakpointComments(tabFilename);
- }
- }
- });
- }
- }
- return saved;
- }
-
- @Override
- public boolean handleSaveAs() {
- //System.out.println("handleSaveAs");
- String oldName = getSketch().getCode(0).getFileName();
- //System.out.println("old name: " + oldName);
- boolean saved = super.handleSaveAs();
- if (saved) {
- // re-set breakpoints in first tab (name has changed)
- List bps = dbg.getBreakpoints(oldName);
- dbg.clearBreakpoints(oldName);
- String newName = getSketch().getCode(0).getFileName();
- //System.out.println("new name: " + newName);
- for (LineBreakpoint bp : bps) {
- LineID line = new LineID(newName, bp.lineID().lineIdx());
- //System.out.println("setting: " + line);
- dbg.setBreakpoint(line);
- }
- // add breakpoint marker comments to source file
- for (int i = 0; i < getSketch().getCodeCount(); i++) {
- addBreakpointComments(getSketch().getCode(i).getFileName());
- }
-
- // set new name of variable inspector
- vi.setTitle(getSketch().getName());
- }
- return saved;
- }
-
- /**
- * Set text contents of a specific tab. Updates underlying document and text
- * area. Clears Breakpoints.
- *
- * @param tabFilename the tab file name
- * @param code the text to set
- */
- protected void setTabContents(String tabFilename, String code) {
- // remove all breakpoints of this tab
- dbg.clearBreakpoints(tabFilename);
-
- SketchCode currentTab = getCurrentTab();
-
- // set code of tab
- SketchCode tab = getTab(tabFilename);
- if (tab != null) {
- tab.setProgram(code);
- // this updates document and text area
- // TODO: does this have any negative effects? (setting the doc to null)
- tab.setDocument(null);
- setCode(tab);
-
- // switch back to original tab
- setCode(currentTab);
- }
- }
-
- /**
- * Clear the console.
- */
- public void clearConsole() {
- console.clear();
- }
-
- /**
- * Clear current text selection.
- */
- public void clearSelection() {
- setSelection(getCaretOffset(), getCaretOffset());
- }
-
- /**
- * Select a line in the current tab.
- *
- * @param lineIdx 0-based line number
- */
- public void selectLine(int lineIdx) {
- setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx));
- }
-
- /**
- * Set the cursor to the start of a line.
- *
- * @param lineIdx 0-based line number
- */
- public void cursorToLineStart(int lineIdx) {
- setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx));
- }
-
- /**
- * Set the cursor to the end of a line.
- *
- * @param lineIdx 0-based line number
- */
- public void cursorToLineEnd(int lineIdx) {
- setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx));
- }
-
- /**
- * Switch to a tab.
- *
- * @param tabFileName the file name identifying the tab. (as in
- * {@link SketchCode#getFileName()})
- */
- public void switchToTab(String tabFileName) {
- Sketch s = getSketch();
- for (int i = 0; i < s.getCodeCount(); i++) {
- if (tabFileName.equals(s.getCode(i).getFileName())) {
- s.setCurrentCode(i);
- break;
- }
- }
- }
-
- /**
- * Access the debugger.
- *
- * @return the debugger controller object
- */
- public Debugger dbg() {
- return dbg;
- }
-
- /**
- * Access the mode.
- *
- * @return the mode object
- */
- public ExperimentalMode mode() {
- return dmode;
- }
-
- /**
- * Access the custom text area object.
- *
- * @return the text area object
- */
- public TextArea textArea() {
- return ta;
- }
-
- /**
- * Access variable inspector window.
- *
- * @return the variable inspector object
- */
- public VariableInspector variableInspector() {
- return vi;
- }
-
- public DebugToolbar toolbar() {
- return (DebugToolbar) toolbar;
- }
-
- /**
- * Show the variable inspector window.
- */
- public void showVariableInspector() {
- vi.setVisible(true);
- }
-
- /**
- * Set visibility of the variable inspector window.
- *
- * @param visible true to set the variable inspector visible, false for
- * invisible.
- */
- public void showVariableInspector(boolean visible) {
- vi.setVisible(visible);
- }
-
- /**
- * Hide the variable inspector window.
- */
- public void hideVariableInspector() {
- vi.setVisible(true);
- }
-
- /**
- * Toggle visibility of the variable inspector window.
- */
- public void toggleVariableInspector() {
- vi.setFocusableWindowState(false); // to not get focus when set visible
- vi.setVisible(!vi.isVisible());
- vi.setFocusableWindowState(true); // allow to get focus again
- }
-
- /**
- * Text area factory method. Instantiates the customized TextArea.
- *
- * @return the customized text area object
- */
- @Override
- protected JEditTextArea createTextArea() {
- //System.out.println("overriding creation of text area");
- return new TextArea(new PdeTextAreaDefaults(mode), this);
- }
-
- /**
- * Set the line to highlight as currently suspended at. Will override the
- * breakpoint color, if set. Switches to the appropriate tab and scroll to
- * the line by placing the cursor there.
- *
- * @param line the line to highlight as current suspended line
- */
- public void setCurrentLine(LineID line) {
- clearCurrentLine();
- if (line == null) {
- return; // safety, e.g. when no line mapping is found and the null line is used.
- }
- switchToTab(line.fileName());
- // scroll to line, by setting the cursor
- cursorToLineStart(line.lineIdx());
- // highlight line
- currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this);
- currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor);
- currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down
- }
-
- /**
- * Clear the highlight for the debuggers current line.
- */
- public void clearCurrentLine() {
- if (currentLine != null) {
- currentLine.clear();
- currentLine.dispose();
-
- // revert to breakpoint color if any is set on this line
- for (LineHighlight hl : breakpointedLines) {
- if (hl.lineID().equals(currentLine.lineID())) {
- hl.paint();
- break;
- }
- }
- currentLine = null;
- }
- }
-
- /**
- * Add highlight for a breakpointed line.
- *
- * @param lineID the line id to highlight as breakpointed
- */
- public void addBreakpointedLine(LineID lineID) {
- LineHighlight hl = new LineHighlight(lineID, breakpointColor, this);
- hl.setMarker(ta.breakpointMarker, breakpointMarkerColor);
- breakpointedLines.add(hl);
- // repaint current line if it's on this line
- if (currentLine != null && currentLine.lineID().equals(lineID)) {
- currentLine.paint();
- }
- }
-
- /**
- * Add highlight for a breakpointed line on the current tab.
- *
- * @param lineIdx the line index on the current tab to highlight as
- * breakpointed
- */
- //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)}
- public void addBreakpointedLine(int lineIdx) {
- addBreakpointedLine(getLineIDInCurrentTab(lineIdx));
- }
-
- /**
- * Remove a highlight for a breakpointed line. Needs to be on the current
- * tab.
- *
- * @param lineIdx the line index on the current tab to remove a breakpoint
- * highlight from
- */
- public void removeBreakpointedLine(int lineIdx) {
- LineID line = getLineIDInCurrentTab(lineIdx);
- //System.out.println("line id: " + line.fileName() + " " + line.lineIdx());
- LineHighlight foundLine = null;
- for (LineHighlight hl : breakpointedLines) {
- if (hl.lineID.equals(line)) {
- foundLine = hl;
- break;
- }
- }
- if (foundLine != null) {
- foundLine.clear();
- breakpointedLines.remove(foundLine);
- foundLine.dispose();
- // repaint current line if it's on this line
- if (currentLine != null && currentLine.lineID().equals(line)) {
- currentLine.paint();
- }
- }
- }
-
- /**
- * Remove all highlights for breakpointed lines.
- */
- public void clearBreakpointedLines() {
- for (LineHighlight hl : breakpointedLines) {
- hl.clear();
- hl.dispose();
- }
- breakpointedLines.clear(); // remove all breakpoints
- // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor
- ta.clearLineBgColors(); // force clear all highlights
- ta.clearGutterText();
-
- // repaint current line
- if (currentLine != null) {
- currentLine.paint();
- }
- }
-
- /**
- * Retrieve a {@link LineID} object for a line on the current tab.
- *
- * @param lineIdx the line index on the current tab
- * @return the {@link LineID} object representing a line index on the
- * current tab
- */
- public LineID getLineIDInCurrentTab(int lineIdx) {
- return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx);
- }
-
- /**
- * Retrieve line of sketch where the cursor currently resides.
- *
- * @return the current {@link LineID}
- */
- protected LineID getCurrentLineID() {
- String tab = getSketch().getCurrentCode().getFileName();
- int lineNo = getTextArea().getCaretLine();
- return new LineID(tab, lineNo);
- }
-
- /**
- * Check whether a {@link LineID} is on the current tab.
- *
- * @param line the {@link LineID}
- * @return true, if the {@link LineID} is on the current tab.
- */
- public boolean isInCurrentTab(LineID line) {
- return line.fileName().equals(getSketch().getCurrentCode().getFileName());
- }
-
- /**
- * Event handler called when switching between tabs. Loads all line
- * background colors set for the tab.
- *
- * @param code tab to switch to
- */
- @Override
- protected void setCode(SketchCode code) {
- //System.out.println("tab switch: " + code.getFileName());
- super.setCode(code); // set the new document in the textarea, etc. need to do this first
-
- // set line background colors for tab
- if (ta != null) { // can be null when setCode is called the first time (in constructor)
- // clear all line backgrounds
- ta.clearLineBgColors();
- // clear all gutter text
- ta.clearGutterText();
- // load appropriate line backgrounds for tab
- // first paint breakpoints
- for (LineHighlight hl : breakpointedLines) {
- if (isInCurrentTab(hl.lineID())) {
- hl.paint();
- }
- }
- // now paint current line (if any)
- if (currentLine != null) {
- if (isInCurrentTab(currentLine.lineID())) {
- currentLine.paint();
- }
- }
- }
- if (dbg() != null && dbg().isStarted()) {
- dbg().startTrackingLineChanges();
- }
- }
-
- /**
- * Get a tab by its file name.
- *
- * @param fileName the filename to search for.
- * @return the {@link SketchCode} object representing the tab, or null if
- * not found
- */
- public SketchCode getTab(String fileName) {
- Sketch s = getSketch();
- for (SketchCode c : s.getCode()) {
- if (c.getFileName().equals(fileName)) {
- return c;
- }
- }
- return null;
- }
-
- /**
- * Retrieve the current tab.
- *
- * @return the {@link SketchCode} representing the current tab
- */
- public SketchCode getCurrentTab() {
- return getSketch().getCurrentCode();
- }
-
- /**
- * Access the currently edited document.
- *
- * @return the document object
- */
- public Document currentDocument() {
- //return ta.getDocument();
- return getCurrentTab().getDocument();
- }
-
- /**
- * Factory method for the editor toolbar. Instantiates the customized
- * toolbar.
- *
- * @return the toolbar
- */
- @Override
- public EditorToolbar createToolbar() {
- return new DebugToolbar(this, base);
- }
-
- /**
- * Event Handler for double clicking in the left hand gutter area.
- *
- * @param lineIdx the line (0-based) that was double clicked
- */
- public void gutterDblClicked(int lineIdx) {
- if (dbg != null) {
- dbg.toggleBreakpoint(lineIdx);
- }
- }
-
- public void statusBusy() {
- statusNotice("Debugger busy...");
- }
-
- public void statusHalted() {
- statusNotice("Debugger halted.");
- }
-
- ErrorCheckerService errorCheckerService;
-
- /**
- * Initializes and starts Error Checker Service
- */
- private void initializeErrorChecker() {
- Thread errorCheckerThread = null;
-
- if (errorCheckerThread == null) {
- errorCheckerService = new ErrorCheckerService(this);
- errorCheckerThread = new Thread(errorCheckerService);
- try {
- errorCheckerThread.start();
- } catch (Exception e) {
- System.err
- .println("Error Checker Service not initialized [XQEditor]: "
- + e);
- // e.printStackTrace();
- }
- // System.out.println("Error Checker Service initialized.");
- }
-
- }
-
- /**
- * Updates the error bar
- * @param problems
- */
- public void updateErrorBar(ArrayList problems) {
- errorBar.updateErrorPoints(problems);
- }
-
- /**
- * Toggle between Console and Errors List
- *
- * @param buttonName
- * - Button Label
- */
- public void toggleView(String buttonName) {
- CardLayout cl = (CardLayout) consoleProblemsPane.getLayout();
- cl.show(consoleProblemsPane, buttonName);
- }
-
- /**
- * Updates the error table
- * @param tableModel
- * @return
- */
- synchronized public boolean updateTable(final TableModel tableModel) {
- return errorTable.updateTable(tableModel);
- }
-
- /**
- * Checks if the sketch contains java tabs. If it does, XQMode ain't built
- * for it, yet. Also, user should really start looking at Eclipse. Disable
- * compilation check.
- */
- private void checkForJavaTabs() {
- for (int i = 0; i < this.getSketch().getCodeCount(); i++) {
- if (this.getSketch().getCode(i).getExtension().equals("java")) {
- compilationCheckEnabled = false;
- JOptionPane.showMessageDialog(new Frame(), this
- .getSketch().getName()
- + " contains .java tabs. Live compilation error checking isn't "
- + "supported for java tabs. Only "
- + "syntax errors will be reported for .pde tabs.");
- break;
- }
- }
- }
-}
diff --git a/experimental/src/processing/mode/experimental/DebugRunner.java b/experimental/src/processing/mode/experimental/DebugRunner.java
deleted file mode 100755
index 1f810d964..000000000
--- a/experimental/src/processing/mode/experimental/DebugRunner.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.VirtualMachine;
-import processing.app.RunnerListener;
-import processing.app.SketchException;
-import processing.app.exec.StreamRedirectThread;
-import processing.mode.java.JavaBuild;
-import processing.mode.java.runner.MessageSiphon;
-
-/**
- * Runs a {@link JavaBuild}. Launches the build in a new debuggee VM.
- *
- * @author Martin Leopold
- */
-public class DebugRunner extends processing.mode.java.runner.Runner {
-
- // important inherited fields
- // protected VirtualMachine vm;
- public DebugRunner(JavaBuild build, RunnerListener listener) throws SketchException {
- super(build, listener);
- }
-
- /**
- * Launch the virtual machine. Simple non-blocking launch. VM starts
- * suspended.
- *
- * @return debuggee VM or null on failure
- */
- public VirtualMachine launch() {
-// String[] machineParamList = getMachineParams();
-// String[] sketchParamList = getSketchParams(false);
-// /*
-// * System.out.println("vm launch sketch params:"); for (int i=0;
-// * i
- *
- * 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 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.mode.experimental;
-
-import java.awt.Image;
-import java.awt.event.MouseEvent;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import processing.app.Base;
-import processing.app.Editor;
-import processing.mode.java.JavaToolbar;
-
-/**
- * Custom toolbar for the editor window. Preserves original button numbers
- * ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW},
- * {@link JavaToolbar#OPEN}, {@link JavaToolbar#SAVE}, {@link JavaToolbar#EXPORT})
- * which can be used e.g. in {@link #activate} and
- * {@link #deactivate}.
- *
- * @author Martin Leopold
- */
-public class DebugToolbar extends JavaToolbar {
- // preserve original button id's, but re-define so they are accessible
- // (they are used by DebugEditor, so they want to be public)
-
- static protected final int RUN = 100; // change this, to be able to get it's name via getTitle()
- static protected final int DEBUG = JavaToolbar.RUN;
-
- static protected final int CONTINUE = 101;
- static protected final int STEP = 102;
- static protected final int TOGGLE_BREAKPOINT = 103;
- static protected final int TOGGLE_VAR_INSPECTOR = 104;
-
- static protected final int STOP = JavaToolbar.STOP;
-
- static protected final int NEW = JavaToolbar.NEW;
- static protected final int OPEN = JavaToolbar.OPEN;
- static protected final int SAVE = JavaToolbar.SAVE;
- static protected final int EXPORT = JavaToolbar.EXPORT;
-
-
- // the sequence of button ids. (this maps button position = index to button ids)
- static protected final int[] buttonSequence = {
- DEBUG, CONTINUE, STEP, STOP, TOGGLE_BREAKPOINT, TOGGLE_VAR_INSPECTOR,
- NEW, OPEN, SAVE, EXPORT
- };
-
-
- public DebugToolbar(Editor editor, Base base) {
- super(editor, base);
- }
-
-
- /**
- * Initialize buttons. Loads images and adds the buttons to the toolbar.
- */
- @Override
- public void init() {
- Image[][] images = loadImages();
- for (int idx = 0; idx < buttonSequence.length; idx++) {
- int id = buttonId(idx);
- addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT);
- }
- }
-
-
- /**
- * Get the title for a toolbar button. Displayed in the toolbar when
- * hovering over a button.
- * @param id id of the toolbar button
- * @param shift true if shift is pressed
- * @return the title
- */
- public static String getTitle(int id, boolean shift) {
- switch (id) {
- case DebugToolbar.RUN:
- return JavaToolbar.getTitle(JavaToolbar.RUN, shift);
- case STOP:
- return JavaToolbar.getTitle(JavaToolbar.STOP, shift);
- case NEW:
- return JavaToolbar.getTitle(JavaToolbar.NEW, shift);
- case OPEN:
- return JavaToolbar.getTitle(JavaToolbar.OPEN, shift);
- case SAVE:
- return JavaToolbar.getTitle(JavaToolbar.SAVE, shift);
- case EXPORT:
- return JavaToolbar.getTitle(JavaToolbar.EXPORT, shift);
- case DEBUG:
- if (shift) {
- return "Run";
- } else {
- return "Debug";
- }
- case CONTINUE:
- return "Continue";
- case TOGGLE_BREAKPOINT:
- return "Toggle Breakpoint";
- case STEP:
- if (shift) {
- return "Step Into";
- } else {
- return "Step";
- }
- case TOGGLE_VAR_INSPECTOR:
- return "Variable Inspector";
- }
- return null;
- }
-
-
- /**
- * Event handler called when a toolbar button is clicked.
- * @param e the mouse event
- * @param idx index (i.e. position) of the toolbar button clicked
- */
- @Override
- public void handlePressed(MouseEvent e, int idx) {
- boolean shift = e.isShiftDown();
- DebugEditor deditor = (DebugEditor) editor;
- int id = buttonId(idx); // convert index/position to button id
-
- switch (id) {
-// case DebugToolbar.RUN:
-// super.handlePressed(e, JavaToolbar.RUN);
-// break;
- case STOP:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Stop' toolbar button");
- super.handlePressed(e, JavaToolbar.STOP);
- break;
- case NEW:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'New' toolbar button");
- super.handlePressed(e, JavaToolbar.NEW);
- break;
- case OPEN:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Open' toolbar button");
- super.handlePressed(e, JavaToolbar.OPEN);
- break;
- case SAVE:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Save' toolbar button");
- super.handlePressed(e, JavaToolbar.SAVE);
- break;
- case EXPORT:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Export' toolbar button");
- super.handlePressed(e, JavaToolbar.EXPORT);
- break;
- case DEBUG:
- deditor.handleStop(); // Close any running sketches
- if (shift) {
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button");
- deditor.handleRun();
- } else {
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Debug' toolbar button");
- deditor.dbg.startDebug();
- }
- break;
- case CONTINUE:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Continue' toolbar button");
- deditor.dbg.continueDebug();
- break;
- case TOGGLE_BREAKPOINT:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' toolbar button");
- deditor.dbg.toggleBreakpoint();
- break;
- case STEP:
- if (shift) {
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step Into' toolbar button");
- deditor.dbg.stepInto();
- } else {
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step' toolbar button");
- deditor.dbg.stepOver();
- }
- break;
-// case STEP_INTO:
-// deditor.dbg.stepInto();
-// break;
-// case STEP_OUT:
-// deditor.dbg.stepOut();
-// break;
- case TOGGLE_VAR_INSPECTOR:
- Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Variable Inspector' toolbar button");
- deditor.toggleVariableInspector();
- break;
- }
- }
-
-
- /**
- * Activate (light up) a button.
- * @param id the button id
- */
- @Override
- public void activate(int id) {
- //System.out.println("activate button idx: " + buttonIndex(id));
- super.activate(buttonIndex(id));
- }
-
-
- /**
- * Set a button to be inactive.
- * @param id the button id
- */
- @Override
- public void deactivate(int id) {
- //System.out.println("deactivate button idx: " + buttonIndex(id));
- super.deactivate(buttonIndex(id));
- }
-
-
- /**
- * Get button position (index) from it's id.
- * @param buttonId the button id
- * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...)
- * @return the button index
- */
- protected int buttonIndex(int buttonId) {
- for (int i = 0; i < buttonSequence.length; i++) {
- if (buttonSequence[i] == buttonId) {
- return i;
- }
- }
- return -1;
- }
-
-
- /**
- * Get the button id from its position (index).
- * @param buttonIdx the button index
- * @return the button id
- * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...)
- */
- protected int buttonId(int buttonIdx) {
- return buttonSequence[buttonIdx];
- }
-}
diff --git a/experimental/src/processing/mode/experimental/Debugger.java b/experimental/src/processing/mode/experimental/Debugger.java
deleted file mode 100755
index 758f6cfae..000000000
--- a/experimental/src/processing/mode/experimental/Debugger.java
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.*;
-import com.sun.jdi.event.*;
-import com.sun.jdi.request.*;
-import java.io.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.swing.JTree; // needed for javadocs
-import javax.swing.tree.DefaultMutableTreeNode;
-import processing.app.Sketch;
-import processing.app.SketchCode;
-
-/**
- * Main controller class for debugging mode. Mainly works with DebugEditor as
- * the corresponding "view". Uses DebugRunner to launch a VM.
- *
- * @author Martin Leopold
- */
-public class Debugger implements VMEventListener {
-
- protected DebugEditor editor; // editor window, acting as main view
- protected DebugRunner runtime; // the runtime, contains debuggee VM
- protected boolean started = false; // debuggee vm has started, VMStartEvent received, main class loaded
- protected boolean paused = false; // currently paused at breakpoint or step
- protected ThreadReference currentThread; // thread the last breakpoint or step occured in
- protected String mainClassName; // name of the main class that's currently being debugged
- protected ReferenceType mainClass; // the debuggee's main class
- protected Set classes = new HashSet(); // holds all loaded classes in the debuggee VM
- protected List classLoadListeners = new ArrayList(); // listeners for class load events
- protected String srcPath; // path to the src folder of the current build
- protected List breakpoints = new ArrayList(); // list of current breakpoints
- protected StepRequest requestedStep; // the step request we are currently in, or null if not in a step
- protected Map runtimeLineChanges = new HashMap(); // maps line number changes at runtime (orig -> changed)
- protected Set runtimeTabsTracked = new HashSet(); // contains tab filenames which already have been tracked for runtime changes
-
- /**
- * Construct a Debugger object.
- *
- * @param editor The Editor that will act as primary view
- */
- public Debugger(DebugEditor editor) {
- this.editor = editor;
- }
-
- /**
- * Access the VM.
- *
- * @return the virtual machine object or null if not available.
- */
- public VirtualMachine vm() {
- if (runtime != null) {
- return runtime.vm();
- } else {
- return null;
- }
- }
-
- /**
- * Access the editor associated with this debugger.
- *
- * @return the editor object
- */
- public DebugEditor editor() {
- return editor;
- }
-
- /**
- * Retrieve the main class of the debuggee VM.
- *
- * @return the main classes {@link ReferenceType} or null if the debugger is
- * not started.
- */
- public ReferenceType getMainClass() {
- if (isStarted()) {
- return mainClass;
- } else {
- return null;
- }
-
- }
-
- /**
- * Get the {@link ReferenceType} for a class name.
- *
- * @param name the class name
- * @return the {@link ReferenceType} or null if not found (e.g. not yet
- * loaded)
- */
- public ReferenceType getClass(String name) {
- if (name == null) {
- return null;
- }
- if (name.equals(mainClassName)) {
- return mainClass;
- }
- for (ReferenceType rt : classes) {
- if (rt.name().equals(name)) {
- return rt;
- }
- }
- return null;
- }
-
- /**
- * Add a class load listener. Will be notified when a class is loaded in the
- * debuggee VM.
- *
- * @param listener the {@link ClassLoadListener}
- */
- public void addClassLoadListener(ClassLoadListener listener) {
- classLoadListeners.add(listener);
- }
-
- /**
- * Remove a class load listener. Cease to be notified when classes are
- * loaded in the debuggee VM.
- *
- * @param listener {@link ClassLoadListener}
- */
- public void removeClassLoadListener(ClassLoadListener listener) {
- classLoadListeners.remove(listener);
- }
-
- /**
- * Start a debugging session. Builds the sketch and launches a VM to run it.
- * VM starts suspended. Should produce a VMStartEvent.
- */
- public synchronized void startDebug() {
- //stopDebug(); // stop any running sessions
- if (isStarted()) {
- return; // do nothing
- }
-
- // we are busy now
- editor.statusBusy();
-
- // clear console
- editor.clearConsole();
-
- // clear variable inspector (also resets expanded states)
- editor.variableInspector().reset();
-
- // load edits into sketch obj, etc...
- editor.prepareRun();
-
- editor.toolbar().activate(DebugToolbar.DEBUG); // after prepareRun, since this removes highlights
-
- try {
- Sketch sketch = editor.getSketch();
- DebugBuild build = new DebugBuild(sketch);
-
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "building sketch: {0}", sketch.getName());
- //LineMapping.addLineNumbers(sketch); // annotate
- mainClassName = build.build(false);
- //LineMapping.removeLineNumbers(sketch); // annotate
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class: {0}", mainClassName);
-
- // folder with assembled/preprocessed src
- srcPath = build.getSrcFolder().getPath();
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build src: {0}", srcPath);
- // folder with compiled code (.class files)
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build bin: {0}", build.getBinFolder().getPath());
-
- if (mainClassName != null) {
- // generate the source line mapping
- //lineMap = LineMapping.generateMapping(srcPath + File.separator + mainClassName + ".java");
-
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "launching debuggee runtime");
- runtime = new DebugRunner(build, editor);
- VirtualMachine vm = runtime.launch(); // non-blocking
- if (vm == null) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "error 37: launch failed");
- }
-
- // start receiving vm events
- VMEventReader eventThread = new VMEventReader(vm.eventQueue(), this);
- eventThread.start();
-
- //return runtime;
-
- /*
- * // launch runner in new thread new Thread(new Runnable() {
- *
- * @Override public void run() { runtime.launch(false); // this
- * blocks until finished } }).start(); return runtime;
- */
-
- startTrackingLineChanges();
- editor.statusBusy();
- }
- } catch (Exception e) {
- editor.statusError(e);
- }
- }
-
- /**
- * End debugging session. Stops and disconnects VM. Should produce
- * VMDisconnectEvent.
- */
- public synchronized void stopDebug() {
- editor.variableInspector().lock();
- if (runtime != null) {
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "closing runtime");
- runtime.close();
- runtime = null;
- //build = null;
- classes.clear();
- // need to clear highlight here because, VMDisconnectedEvent seems to be unreliable. TODO: likely synchronization problem
- editor.clearCurrentLine();
- }
- stopTrackingLineChanges();
- started = false;
- editor.toolbar().deactivate(DebugToolbar.DEBUG);
- editor.toolbar().deactivate(DebugToolbar.CONTINUE);
- editor.toolbar().deactivate(DebugToolbar.STEP);
- editor.statusEmpty();
- }
-
- /**
- * Resume paused debugging session. Resumes VM.
- */
- public synchronized void continueDebug() {
- editor.toolbar().activate(DebugToolbar.CONTINUE);
- editor.variableInspector().lock();
- //editor.clearSelection();
- //clearHighlight();
- editor.clearCurrentLine();
- if (!isStarted()) {
- startDebug();
- } else if (isPaused()) {
- runtime.vm().resume();
- paused = false;
- editor.statusBusy();
- }
- }
-
- /**
- * Step through source code lines.
- *
- * @param stepDepth the step depth ({@link StepRequest#STEP_OVER},
- * {@link StepRequest#STEP_INTO} or {@link StepRequest#STEP_OUT})
- */
- protected void step(int stepDepth) {
- if (!isStarted()) {
- startDebug();
- } else if (isPaused()) {
- editor.variableInspector().lock();
- editor.toolbar().activate(DebugToolbar.STEP);
-
- // use global to mark that there is a step request pending
- requestedStep = runtime.vm().eventRequestManager().createStepRequest(currentThread, StepRequest.STEP_LINE, stepDepth);
- requestedStep.addCountFilter(1); // valid for one step only
- requestedStep.enable();
- paused = false;
- runtime.vm().resume();
- editor.statusBusy();
- }
- }
-
- /**
- * Step over current statement.
- */
- public synchronized void stepOver() {
- step(StepRequest.STEP_OVER);
- }
-
- /**
- * Step into current statement.
- */
- public synchronized void stepInto() {
- step(StepRequest.STEP_INTO);
- }
-
- /**
- * Step out of current function.
- */
- public synchronized void stepOut() {
- step(StepRequest.STEP_OUT);
- }
-
- /**
- * Print the current stack trace.
- */
- public synchronized void printStackTrace() {
- if (isStarted()) {
- printStackTrace(currentThread);
- }
- }
-
- /**
- * Print local variables. Outputs type, name and value of each variable.
- */
- public synchronized void printLocals() {
- if (isStarted()) {
- printLocalVariables(currentThread);
- }
- }
-
- /**
- * Print fields of current {@code this}-object. Outputs type, name and value
- * of each field.
- */
- public synchronized void printThis() {
- if (isStarted()) {
- printThis(currentThread);
- }
- }
-
- /**
- * Print a source code snippet of the current location.
- */
- public synchronized void printSource() {
- if (isStarted()) {
- printSourceLocation(currentThread);
- }
- }
-
- /**
- * Set a breakpoint on the current line.
- */
- public synchronized void setBreakpoint() {
- setBreakpoint(editor.getCurrentLineID());
- }
-
- /**
- * Set a breakpoint on a line in the current tab.
- *
- * @param lineIdx the line index (0-based) of the current tab to set the
- * breakpoint on
- */
- public synchronized void setBreakpoint(int lineIdx) {
- setBreakpoint(editor.getLineIDInCurrentTab(lineIdx));
- }
-
- /**
- * Set a breakpoint.
- *
- * @param line the line id to set the breakpoint on
- */
- public synchronized void setBreakpoint(LineID line) {
- // do nothing if we are kinda busy
- if (isStarted() && !isPaused()) {
- return;
- }
- // do nothing if there already is a breakpoint on this line
- if (hasBreakpoint(line)) {
- return;
- }
- breakpoints.add(new LineBreakpoint(line, this));
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "set breakpoint on line {0}", line);
- }
-
- /**
- * Remove a breakpoint from the current line (if set).
- */
- public synchronized void removeBreakpoint() {
- removeBreakpoint(editor.getCurrentLineID().lineIdx());
- }
-
- /**
- * Remove a breakpoint from a line in the current tab.
- *
- * @param lineIdx the line index (0-based) in the current tab to remove the
- * breakpoint from
- */
- protected void removeBreakpoint(int lineIdx) {
- // do nothing if we are kinda busy
- if (isBusy()) {
- return;
- }
-
- LineBreakpoint bp = breakpointOnLine(editor.getLineIDInCurrentTab(lineIdx));
- if (bp != null) {
- bp.remove();
- breakpoints.remove(bp);
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "removed breakpoint {0}", bp);
- }
- }
-
- /**
- * Remove all breakpoints.
- */
- public synchronized void clearBreakpoints() {
- //TODO: handle busy-ness correctly
- if (isBusy()) {
- Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy");
- return;
- }
-
- for (LineBreakpoint bp : breakpoints) {
- bp.remove();
- }
- breakpoints.clear();
- }
-
- /**
- * Clear breakpoints in a specific tab.
- *
- * @param tabFilename the tab's file name
- */
- public synchronized void clearBreakpoints(String tabFilename) {
- //TODO: handle busy-ness correctly
- if (isBusy()) {
- Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy");
- return;
- }
-
- Iterator i = breakpoints.iterator();
- while (i.hasNext()) {
- LineBreakpoint bp = i.next();
- if (bp.lineID().fileName().equals(tabFilename)) {
- bp.remove();
- i.remove();
- }
- }
- }
-
- /**
- * Get the breakpoint on a certain line, if set.
- *
- * @param line the line to get the breakpoint from
- * @return the breakpoint, or null if no breakpoint is set on the specified
- * line.
- */
- protected LineBreakpoint breakpointOnLine(LineID line) {
- for (LineBreakpoint bp : breakpoints) {
- if (bp.isOnLine(line)) {
- return bp;
- }
- }
- return null;
- }
-
- /**
- * Toggle a breakpoint on the current line.
- */
- public synchronized void toggleBreakpoint() {
- toggleBreakpoint(editor.getCurrentLineID().lineIdx());
- }
-
- /**
- * Toggle a breakpoint on a line in the current tab.
- *
- * @param lineIdx the line index (0-based) in the current tab
- */
- public synchronized void toggleBreakpoint(int lineIdx) {
- LineID line = editor.getLineIDInCurrentTab(lineIdx);
- if (!hasBreakpoint(line)) {
- setBreakpoint(line.lineIdx());
- } else {
- removeBreakpoint(line.lineIdx());
- }
- }
-
- /**
- * Check if there's a breakpoint on a particular line.
- *
- * @param line the line id
- * @return true if a breakpoint is set on the given line, otherwise false
- */
- protected boolean hasBreakpoint(LineID line) {
- LineBreakpoint bp = breakpointOnLine(line);
- return bp != null;
- }
-
- /**
- * Print a list of currently set breakpoints.
- */
- public synchronized void listBreakpoints() {
- if (breakpoints.isEmpty()) {
- System.out.println("no breakpoints");
- } else {
- System.out.println("line breakpoints:");
- for (LineBreakpoint bp : breakpoints) {
- System.out.println(bp);
- }
- }
- }
-
- /**
- * Retrieve a list of breakpoint in a particular tab.
- *
- * @param tabFilename the tab's file name
- * @return the list of breakpoints in the given tab
- */
- public synchronized List getBreakpoints(String tabFilename) {
- List list = new ArrayList();
- for (LineBreakpoint bp : breakpoints) {
- if (bp.lineID().fileName().equals(tabFilename)) {
- list.add(bp);
- }
- }
- return list;
- }
-
- /**
- * Callback for VM events. Will be called from another thread.
- * ({@link VMEventReader})
- *
- * @param es Incoming set of events from VM
- */
- @Override
- public synchronized void vmEvent(EventSet es) {
- for (Event e : es) {
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "*** VM Event: {0}", e.toString());
- if (e instanceof VMStartEvent) {
- //initialThread = ((VMStartEvent) e).thread();
-// ThreadReference t = ((VMStartEvent) e).thread();
- //printStackTrace(t);
-
- // break on main class load
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on main class load: {0}", mainClassName);
- ClassPrepareRequest mainClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest();
- mainClassPrepare.addClassFilter(mainClassName);
- mainClassPrepare.enable();
-
- // break on loading custom classes
- for (SketchCode tab : editor.getSketch().getCode()) {
- if (tab.isExtension("java")) {
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on class load: {0}", tab.getPrettyName());
- ClassPrepareRequest customClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest();
- customClassPrepare.addClassFilter(tab.getPrettyName());
- customClassPrepare.enable();
- }
- }
-
- runtime.vm().resume();
- } else if (e instanceof ClassPrepareEvent) {
- ClassPrepareEvent ce = (ClassPrepareEvent) e;
- ReferenceType rt = ce.referenceType();
- currentThread = ce.thread();
- paused = true; // for now we're paused
-
- if (rt.name().equals(mainClassName)) {
- //printType(rt);
- mainClass = rt;
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "main class load: {0}", rt.name());
- started = true; // now that main class is loaded, we're started
- } else {
- classes.add(rt); // save loaded classes
- Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class load: {0}", rt.name());
- }
-
- // notify listeners
- for (ClassLoadListener listener : classLoadListeners) {
- if (listener != null) {
- listener.classLoaded(rt);
- }
- }
-
- paused = false; // resuming now
- runtime.vm().resume();
- } else if (e instanceof BreakpointEvent) {
- BreakpointEvent be = (BreakpointEvent) e;
- currentThread = be.thread(); // save this thread
-// BreakpointRequest br = (BreakpointRequest) be.request();
-
- //printSourceLocation(currentThread);
- updateVariableInspector(currentThread); // this is already on the EDT
- final LineID newCurrentLine = locationToLineID(be.location());
- javax.swing.SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- editor.setCurrentLine(newCurrentLine);
- editor.toolbar().deactivate(DebugToolbar.STEP);
- editor.toolbar().deactivate(DebugToolbar.CONTINUE);
- }
- });
-
- // hit a breakpoint during a step, need to cancel the step.
- if (requestedStep != null) {
- runtime.vm().eventRequestManager().deleteEventRequest(requestedStep);
- requestedStep = null;
- }
-
- // fix canvas update issue
- // TODO: is this a good solution?
- resumeOtherThreads(currentThread);
-
- paused = true;
- editor.statusHalted();
- } else if (e instanceof StepEvent) {
- StepEvent se = (StepEvent) e;
- currentThread = se.thread();
-
- //printSourceLocation(currentThread);
- updateVariableInspector(currentThread); // this is already on the EDT
- final LineID newCurrentLine = locationToLineID(se.location());
- javax.swing.SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- editor.setCurrentLine(newCurrentLine);
- editor.toolbar().deactivate(DebugToolbar.STEP);
- editor.toolbar().deactivate(DebugToolbar.CONTINUE);
- }
- });
-
- // delete the steprequest that triggered this step so new ones can be placed (only one per thread)
- EventRequestManager mgr = runtime.vm().eventRequestManager();
- mgr.deleteEventRequest(se.request());
- requestedStep = null; // mark that there is no step request pending
- paused = true;
- editor.statusHalted();
-
- // disallow stepping into invisible lines
- if (!locationIsVisible(se.location())) {
- stepOutIntoViewOrContinue(); // TODO: this leads to stepping, should it run on the EDT?
- }
- } else if (e instanceof VMDisconnectEvent) {
-// started = false;
-// // clear line highlight
-// editor.clearCurrentLine();
- stopDebug();
- } else if (e instanceof VMDeathEvent) {
- started = false;
- editor.statusEmpty();
- }
- }
- }
-
- /**
- * Check whether a location corresponds to a code line in the editor.
- *
- * @param l the location
- * @return true if the location corresponds to a line in the editor
- */
- protected boolean locationIsVisible(Location l) {
- return locationToLineID(l) != null;
- }
-
- /**
- * Step out if this results in a visible location, otherwise continue.
- */
- protected void stepOutIntoViewOrContinue() {
- try {
- List frames = currentThread.frames();
- if (frames.size() > 1) {
- if (locationIsVisible(frames.get(1).location())) {
- //System.out.println("stepping out to: " + locationToString(frames.get(1).location()));
- stepOut();
- return;
- }
- }
- continueDebug();
-
-// //Step out to the next visible location on the stack frame
-// if (thread.frames(i, i1))
-// for (StackFrame f : thread.frames()) {
-// Location l = f.location();
-// if (locationIsVisible(l)) {
-// System.out.println("need to step out to: " + locationToString(l));
-// }
-// }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Check whether a debugging session is running. i.e. the debugger is
- * connected to a debuggee VM, VMStartEvent has been received and main class
- * is loaded.
- *
- * @return true if the debugger is started.
- */
- public synchronized boolean isStarted() {
- return started && runtime != null && runtime.vm() != null;
- }
-
- /**
- * Check whether the debugger is paused. i.e. it is currently suspended at a
- * breakpoint or step.
- *
- * @return true if the debugger is paused, false otherwise or if not started
- * ({@link #isStarted()})
- */
- public synchronized boolean isPaused() {
- return isStarted() && paused && currentThread != null && currentThread.isSuspended();
- }
-
- /**
- * Check whether the debugger is currently busy. i.e. running (not
- * suspended).
- *
- * @return true if the debugger is currently running and not suspended.
- */
- public synchronized boolean isBusy() {
- return isStarted() && !isPaused();
- }
-
- /**
- * Print call stack trace of a thread. Only works on suspended threads.
- *
- * @param t suspended thread to print stack trace of
- */
- protected void printStackTrace(ThreadReference t) {
- if (!t.isSuspended()) {
- return;
- }
- try {
- System.out.println("stack trace for thread " + t.name() + ":");
- int i = 0;
- for (StackFrame f : t.frames()) {
-// Location l = f.location();
- System.out.println(i++ + ": " + f.toString());
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Resume all other threads except the one given as parameter. Useful e.g.
- * to just keep the thread suspended a breakpoint occurred in.
- *
- * @param t the thread not to resume
- */
- protected void resumeOtherThreads(ThreadReference t) {
- if (!isStarted()) {
- return;
- }
- for (ThreadReference other : vm().allThreads()) {
- if (!other.equals(t) && other.isSuspended()) {
- other.resume();
- }
- }
- }
-
- /**
- * Print info about all current threads. Includes name, status, isSuspended,
- * isAtBreakpoint.
- */
- public synchronized void printThreads() {
- if (!isPaused()) {
- return;
- }
- System.out.println("threads:");
- for (ThreadReference t : vm().allThreads()) {
- printThread(t);
- }
- }
-
- /**
- * Print info about a thread. Includes name, status, isSuspended,
- * isAtBreakpoint.
- *
- * @param t the thread to print info about
- */
- protected void printThread(ThreadReference t) {
- System.out.println(t.name());
- System.out.println(" is suspended: " + t.isSuspended());
- System.out.println(" is at breakpoint: " + t.isAtBreakpoint());
- System.out.println(" status: " + threadStatusToString(t.status()));
- }
-
- /**
- * Convert a status code returned by {@link ThreadReference#status() } to a
- * human readable form.
- *
- * @param status {@link ThreadReference#THREAD_STATUS_MONITOR},
- * {@link ThreadReference#THREAD_STATUS_NOT_STARTED},
- * {@link ThreadReference#THREAD_STATUS_RUNNING},
- * {@link ThreadReference#THREAD_STATUS_SLEEPING},
- * {@link ThreadReference#THREAD_STATUS_UNKNOWN},
- * {@link ThreadReference#THREAD_STATUS_WAIT} or
- * {@link ThreadReference#THREAD_STATUS_ZOMBIE}
- * @return String containing readable status code.
- */
- protected String threadStatusToString(int status) {
- switch (status) {
- case ThreadReference.THREAD_STATUS_MONITOR:
- return "THREAD_STATUS_MONITOR";
- case ThreadReference.THREAD_STATUS_NOT_STARTED:
- return "THREAD_STATUS_NOT_STARTED";
- case ThreadReference.THREAD_STATUS_RUNNING:
- return "THREAD_STATUS_RUNNING";
- case ThreadReference.THREAD_STATUS_SLEEPING:
- return "THREAD_STATUS_SLEEPING";
- case ThreadReference.THREAD_STATUS_UNKNOWN:
- return "THREAD_STATUS_UNKNOWN";
- case ThreadReference.THREAD_STATUS_WAIT:
- return "THREAD_STATUS_WAIT";
- case ThreadReference.THREAD_STATUS_ZOMBIE:
- return "THREAD_STATUS_ZOMBIE";
- default:
- return "";
- }
- }
-
- /**
- * Print local variables on a suspended thread. Takes the topmost stack
- * frame and lists all local variables and their values.
- *
- * @param t suspended thread
- */
- protected void printLocalVariables(ThreadReference t) {
- if (!t.isSuspended()) {
- return;
- }
- try {
- if (t.frameCount() == 0) {
- System.out.println("call stack empty");
- } else {
- StackFrame sf = t.frame(0);
- List locals = sf.visibleVariables();
- if (locals.isEmpty()) {
- System.out.println("no local variables");
- return;
- }
- for (LocalVariable lv : locals) {
- System.out.println(lv.typeName() + " " + lv.name() + " = " + sf.getValue(lv));
- }
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- } catch (AbsentInformationException ex) {
- System.out.println("local variable information not available");
- }
- }
-
- /**
- * Update variable inspector window. Displays local variables and this
- * fields.
- *
- * @param t suspended thread to retrieve locals and this
- */
- protected void updateVariableInspector(ThreadReference t) {
- if (!t.isSuspended()) {
- return;
- }
- try {
- if (t.frameCount() == 0) {
- // TODO: needs to be handled in a better way:
- Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "call stack empty");
- } else {
- final VariableInspector vi = editor.variableInspector();
- // first get data
- final List stackTrace = getStackTrace(t);
- final List locals = getLocals(t, 0);
- final String currentLocation = currentLocation(t);
- final List thisFields = getThisFields(t, 0, true);
- final List declaredThisFields = getThisFields(t, 0, false);
- final String thisName = thisName(t);
- // now update asynchronously
- javax.swing.SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- //System.out.println("updating vi. from EDT: " + javax.swing.SwingUtilities.isEventDispatchThread());
- vi.updateCallStack(stackTrace, "Call Stack");
- vi.updateLocals(locals, "Locals at " + currentLocation);
- vi.updateThisFields(thisFields, "Class " + thisName);
- vi.updateDeclaredThisFields(declaredThisFields, "Class " + thisName);
- vi.unlock(); // need to do this before rebuilding, otherwise we get these ... dots in the labels
- vi.rebuild();
- }
- });
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Get the class name of the current this object in a suspended thread.
- *
- * @param t a suspended thread
- * @return the class name of this
- */
- protected String thisName(ThreadReference t) {
- try {
- if (!t.isSuspended() || t.frameCount() == 0) {
- return "";
- }
- return t.frame(0).thisObject().referenceType().name();
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- return "";
- }
- }
-
- /**
- * Get a description of the current location in a suspended thread. Format:
- * class.method:translated_line_number
- *
- * @param t a suspended thread
- * @return descriptive string for the given location
- */
- protected String currentLocation(ThreadReference t) {
- try {
- if (!t.isSuspended() || t.frameCount() == 0) {
- return "";
- }
- return locationToString(t.frame(0).location());
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- return "";
- }
- }
-
- /**
- * Get a string describing a location. Format:
- * class.method:translated_line_number
- *
- * @param l a location
- * @return descriptive string for the given location
- */
- protected String locationToString(Location l) {
- LineID line = locationToLineID(l);
- int lineNumber;
- if (line != null) {
- lineNumber = line.lineIdx() + 1;
- } else {
- lineNumber = l.lineNumber();
- }
- return l.declaringType().name() + "." + l.method().name() + ":" + lineNumber;
- }
-
- /**
- * Compile a list of current locals usable for insertion into a
- * {@link JTree}. Recursively resolves object references.
- *
- * @param t the suspended thread to get locals for
- * @param depth how deep to resolve nested object references. 0 will not
- * resolve nested objects.
- * @return the list of current locals
- */
- protected List getLocals(ThreadReference t, int depth) {
- //System.out.println("getting locals");
- List vars = new ArrayList();
- try {
- if (t.frameCount() > 0) {
- StackFrame sf = t.frame(0);
- for (LocalVariable lv : sf.visibleVariables()) {
- //System.out.println("local var: " + lv.name());
- Value val = sf.getValue(lv);
- VariableNode var = new LocalVariableNode(lv.name(), lv.typeName(), val, lv, sf);
- if (depth > 0) {
- var.addChildren(getFields(val, depth - 1, true));
- }
- vars.add(var);
- }
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- } catch (AbsentInformationException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "local variable information not available", ex);
- }
- return vars;
- }
-
- /**
- * Compile a list of fields in the current this object usable for insertion
- * into a {@link JTree}. Recursively resolves object references.
- *
- * @param t the suspended thread to get locals for
- * @param depth how deep to resolve nested object references. 0 will not
- * resolve nested objects.
- * @return the list of fields in the current this object
- */
- protected List getThisFields(ThreadReference t, int depth, boolean includeInherited) {
- //System.out.println("getting this");
- try {
- if (t.frameCount() > 0) {
- StackFrame sf = t.frame(0);
- ObjectReference thisObj = sf.thisObject();
- return getFields(thisObj, depth, includeInherited);
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- return new ArrayList();
- }
-
- /**
- * Recursively get the fields of a {@link Value} for insertion into a
- * {@link JTree}.
- *
- * @param value must be an instance of {@link ObjectReference}
- * @param depth the current depth
- * @param maxDepth the depth to stop at (inclusive)
- * @return list of child fields of the given value
- */
- protected List getFields(Value value, int depth, int maxDepth, boolean includeInherited) {
- // remember: Value <- ObjectReference, ArrayReference
- List vars = new ArrayList();
- if (depth <= maxDepth) {
- if (value instanceof ArrayReference) {
- return getArrayFields((ArrayReference) value);
- } else if (value instanceof ObjectReference) {
- ObjectReference obj = (ObjectReference) value;
- // get the fields of this object
- List fields = includeInherited ? obj.referenceType().visibleFields() : obj.referenceType().fields();
- for (Field field : fields) {
- Value val = obj.getValue(field); // get the value, may be null
- VariableNode var = new FieldNode(field.name(), field.typeName(), val, field, obj);
- // recursively add children
- if (val != null) {
- var.addChildren(getFields(val, depth + 1, maxDepth, includeInherited));
- }
- vars.add(var);
- }
- }
- }
- return vars;
- }
-
- /**
- * Recursively get the fields of a {@link Value} for insertion into a
- * {@link JTree}.
- *
- * @param value must be an instance of {@link ObjectReference}
- * @param maxDepth max recursion depth. 0 will give only direct children
- * @return list of child fields of the given value
- */
- protected List getFields(Value value, int maxDepth, boolean includeInherited) {
- return getFields(value, 0, maxDepth, includeInherited);
- }
-
- /**
- * Get the fields of an array for insertion into a {@link JTree}.
- *
- * @param array the array reference
- * @return list of array fields
- */
- protected List getArrayFields(ArrayReference array) {
- List fields = new ArrayList();
- if (array != null) {
- String arrayType = array.type().name();
- if (arrayType.endsWith("[]")) {
- arrayType = arrayType.substring(0, arrayType.length() - 2);
- }
- int i = 0;
- for (Value val : array.getValues()) {
- VariableNode var = new ArrayFieldNode("[" + i + "]", arrayType, val, array, i);
- fields.add(var);
- i++;
- }
- }
- return fields;
- }
-
- /**
- * Get the current call stack trace usable for insertion into a
- * {@link JTree}.
- *
- * @param t the suspended thread to retrieve the call stack from
- * @return call stack as list of {@link DefaultMutableTreeNode}s
- */
- protected List getStackTrace(ThreadReference t) {
- List stack = new ArrayList();
- try {
-// int i = 0;
- for (StackFrame f : t.frames()) {
- stack.add(new DefaultMutableTreeNode(locationToString(f.location())));
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- return stack;
- }
-
- /**
- * Print visible fields of current "this" object on a suspended thread.
- * Prints type, name and value.
- *
- * @param t suspended thread
- */
- protected void printThis(ThreadReference t) {
- if (!t.isSuspended()) {
- return;
- }
- try {
- if (t.frameCount() == 0) {
- // TODO: needs to be handled in a better way
- System.out.println("call stack empty");
- } else {
- StackFrame sf = t.frame(0);
- ObjectReference thisObject = sf.thisObject();
- if (this != null) {
- ReferenceType type = thisObject.referenceType();
- System.out.println("fields in this (" + type.name() + "):");
- for (Field f : type.visibleFields()) {
- System.out.println(f.typeName() + " " + f.name() + " = " + thisObject.getValue(f));
- }
- } else {
- System.out.println("can't get this (in native or static method)");
- }
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Print source code snippet of current location in a suspended thread.
- *
- * @param t suspended thread
- */
- protected void printSourceLocation(ThreadReference t) {
- try {
- if (t.frameCount() == 0) {
- // TODO: needs to be handled in a better way
- System.out.println("call stack empty");
- } else {
- Location l = t.frame(0).location(); // current stack frame location
- printSourceLocation(l);
- }
- } catch (IncompatibleThreadStateException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Print source code snippet.
- *
- * @param l {@link Location} object to print source code for
- */
- protected void printSourceLocation(Location l) {
- try {
- //System.out.println(l.sourceName() + ":" + l.lineNumber());
- System.out.println("in method " + l.method() + ":");
- System.out.println(getSourceLine(l.sourcePath(), l.lineNumber(), 2));
-
- } catch (AbsentInformationException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Read a line from the given file in the builds src folder. 1-based i.e.
- * first line has line no. 1
- *
- * @param filePath
- * @param lineNo
- * @return the requested source line
- */
- protected String getSourceLine(String filePath, int lineNo, int radius) {
- if (lineNo == -1) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "invalid line number: {0}", lineNo);
- return "";
- }
- //System.out.println("getting line: " + lineNo);
- File f = new File(srcPath + File.separator + filePath);
- String output = "";
- try {
- BufferedReader r = new BufferedReader(new FileReader(f));
- int i = 1;
- //String line = "";
- while (i <= lineNo + radius) {
- String line = r.readLine(); // line no. i
- if (line == null) {
- break; // end of file
- }
- if (i >= lineNo - radius) {
- if (i > lineNo - radius) {
- output += "\n"; // add newlines before all lines but the first
- }
- output += f.getName() + ":" + i + (i == lineNo ? " => " : " ") + line;
- }
- i++;
- }
- r.close();
- return output;
- } catch (FileNotFoundException ex) {
- //System.err.println(ex);
- return f.getName() + ":" + lineNo;
- } catch (IOException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- return "";
- }
- }
-
- /**
- * Print info about a ReferenceType. Prints class name, source file name,
- * lists methods.
- *
- * @param rt the reference type to print out
- */
- protected void printType(ReferenceType rt) {
- System.out.println("ref.type: " + rt);
- System.out.println("name: " + rt.name());
- try {
- System.out.println("sourceName: " + rt.sourceName());
- } catch (AbsentInformationException ex) {
- System.out.println("sourceName: unknown");
- }
- System.out.println("methods:");
- for (Method m : rt.methods()) {
- System.out.println(m.toString());
- }
- }
-
- /**
- * Translate a java source location to a sketch line id.
- *
- * @param l the location to translate
- * @return the corresponding line id, or null if not found
- */
- protected LineID locationToLineID(Location l) {
- try {
- //return lineMap.get(LineID.create(l.sourceName(), l.lineNumber() - 1));
- return javaToSketchLine(new LineID(l.sourceName(), l.lineNumber() - 1));
-
- } catch (AbsentInformationException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- return null;
- }
- }
-
- /**
- * Translate a line (index) from java space to sketch space.
- *
- * @param javaLine the java line id
- * @return the corresponding sketch line id or null if failed to translate
- */
- public LineID javaToSketchLine(LineID javaLine) {
- Sketch sketch = editor.getSketch();
-
- // it may belong to a pure java file created in the sketch
- // try to find an exact filename match and check the extension
- SketchCode tab = editor.getTab(javaLine.fileName());
- if (tab != null && tab.isExtension("java")) {
- // can translate 1:1
- return originalToRuntimeLine(javaLine);
- }
-
- // check if it is the preprocessed/assembled file for this sketch
- // java file name needs to match the sketches filename
- if (!javaLine.fileName().equals(sketch.getName() + ".java")) {
- return null;
- }
-
- // find the tab (.pde file) this line belongs to
- // get the last tab that has an offset not greater than the java line number
- for (int i = sketch.getCodeCount() - 1; i >= 0; i--) {
- tab = sketch.getCode(i);
- // ignore .java files
- // the tab's offset must not be greater than the java line number
- if (tab.isExtension("pde") && tab.getPreprocOffset() <= javaLine.lineIdx()) {
- return originalToRuntimeLine(new LineID(tab.getFileName(), javaLine.lineIdx() - tab.getPreprocOffset()));
- }
- }
-
- return null;
- }
-
- /**
- * Get the runtime-changed line id for an original sketch line. Used to
- * translate line numbers from the VM (which runs on the original line
- * numbers) to their current (possibly changed) counterparts.
- *
- * @param line the original line id (at compile time)
- * @return the changed version or the line given as parameter if not found
- */
- protected LineID originalToRuntimeLine(LineID line) {
- LineID transformed = runtimeLineChanges.get(line);
- if (transformed == null) {
- return line;
- }
- return transformed;
- }
-
- /**
- * Get the original line id for a sketch line that was changed at runtime.
- * Used to translate line numbers from the UI at runtime (which can differ
- * from the ones the VM runs on) to their original counterparts.
- *
- * @param line the (possibly) changed runtime line
- * @return the original line or the line given as parameter if not found
- */
- protected LineID runtimeToOriginalLine(LineID line) {
- for (Entry entry : runtimeLineChanges.entrySet()) {
- if (entry.getValue().equals(line)) {
- return entry.getKey();
- }
- }
- return line;
- }
-
- /**
- * Translate a line (index) from sketch space to java space.
- *
- * @param sketchLine the sketch line id
- * @return the corresponding java line id or null if failed to translate
- */
- public LineID sketchToJavaLine(LineID sketchLine) {
- sketchLine = runtimeToOriginalLine(sketchLine); // transform back to orig (before changes at runtime)
-
- // check if there is a tab for this line
- SketchCode tab = editor.getTab(sketchLine.fileName());
- if (tab == null) {
- return null;
- }
-
- // check if the tab is a pure java file anyway
- if (tab.isExtension("java")) {
- // 1:1 translation
- return sketchLine;
- }
-
- // the java file has a name sketchname.java
- // just add the tab's offset to get the java name
- LineID javaLine = new LineID(editor.getSketch().getName() + ".java", sketchLine.lineIdx() + tab.getPreprocOffset());
- return javaLine;
- }
-
- /**
- * Start tracking all line changes (due to edits) in the current tab.
- */
- // TODO: maybe move this to the editor?
- protected void startTrackingLineChanges() {
- SketchCode tab = editor.getSketch().getCurrentCode();
- if (runtimeTabsTracked.contains(tab.getFileName())) {
- return;
- }
-
- for (int i = 0; i < tab.getLineCount(); i++) {
- LineID old = new LineID(tab.getFileName(), i);
- LineID tracked = new LineID(tab.getFileName(), i);
- tracked.startTracking(editor.currentDocument());
- runtimeLineChanges.put(old, tracked);
- }
- runtimeTabsTracked.add(tab.getFileName());
- //System.out.println("tracking tab: " + tab.getFileName());
- }
-
- /**
- * Stop tracking line changes in all tabs.
- */
- protected void stopTrackingLineChanges() {
- //System.out.println("stop tracking line changes");
- for (LineID tracked : runtimeLineChanges.values()) {
- tracked.stopTracking();
- }
- runtimeLineChanges.clear();
- runtimeTabsTracked.clear();
- }
-}
diff --git a/experimental/src/processing/mode/experimental/ErrorBar.java b/experimental/src/processing/mode/experimental/ErrorBar.java
deleted file mode 100755
index f92232cc3..000000000
--- a/experimental/src/processing/mode/experimental/ErrorBar.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- Part of the XQMode project - https://github.com/Manindra29/XQMode
-
- Under Google Summer of Code 2012 -
- http://www.google-melange.com/gsoc/homepage/google/gsoc2012
-
- Copyright (C) 2012 Manindra Moharana
-
- 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.mode.experimental;
-
-import java.awt.Color;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseMotionListener;
-import java.util.ArrayList;
-
-import javax.swing.JPanel;
-import javax.swing.SwingWorker;
-
-import processing.app.Base;
-import processing.app.SketchCode;
-
-/**
- * The bar on the left of the text area which displays all errors as rectangles.
- *
- * All errors and warnings of a sketch are drawn on the bar, clicking on one,
- * scrolls to the tab and location. Error messages displayed on hover. Markers
- * are not in sync with the error line. Similar to eclipse's right error bar
- * which displays the overall errors in a document
- *
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- */
-public class ErrorBar extends JPanel {
- /**
- * Preferred height of the component
- */
- protected int preferredHeight;
-
- /**
- * Preferred height of the component
- */
- protected int preferredWidth = 12;
-
- /**
- * Height of marker
- */
- public static final int errorMarkerHeight = 4;
-
- /**
- * Color of Error Marker
- */
- public Color errorColor = new Color(0xED2630);
-
- /**
- * Color of Warning Marker
- */
- public Color warningColor = new Color(0xFFC30E);
-
- /**
- * Background color of the component
- */
- public Color backgroundColor = new Color(0x2C343D);
-
- /**
- * DebugEditor instance
- */
- protected DebugEditor editor;
-
- /**
- * ErrorCheckerService instance
- */
- protected ErrorCheckerService errorCheckerService;
-
- /**
- * Stores error markers displayed PER TAB along the error bar.
- */
- protected ArrayList errorPoints = new ArrayList();
-
- /**
- * Stores previous list of error markers.
- */
- protected ArrayList errorPointsOld = new ArrayList();
-
- public void paintComponent(Graphics g) {
- Graphics2D g2d = (Graphics2D) g;
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- g.setColor(backgroundColor);
- g.fillRect(0, 0, getWidth(), getHeight());
-
- for (ErrorMarker emarker : errorPoints) {
- if (emarker.type == ErrorMarker.Error) {
- g.setColor(errorColor);
- } else {
- g.setColor(warningColor);
- }
- g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight);
- }
- }
-
- public Dimension getPreferredSize() {
- return new Dimension(preferredWidth, preferredHeight);
- }
-
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
-
- public ErrorBar(DebugEditor editor, int height, ExperimentalMode mode) {
- this.editor = editor;
- this.preferredHeight = height;
- this.errorCheckerService = editor.errorCheckerService;
- errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor);
- warningColor = mode
- .getThemeColor("errorbar.warningcolor", warningColor);
- backgroundColor = mode.getThemeColor("errorbar.backgroundcolor",
- backgroundColor);
- addListeners();
- }
-
- /**
- * Update error markers in the error bar.
- *
- * @param problems
- * - List of problems.
- */
- synchronized public void updateErrorPoints(final ArrayList problems) {
-
- // NOTE TO SELF: ErrorMarkers are calculated for the present tab only
- // Error Marker index in the arraylist is LOCALIZED for current tab.
- // Also, need to do the update in the UI thread to prevent concurrency issues.
- final int fheight = this.getHeight();
- SwingWorker worker = new SwingWorker() {
-
- protected Object doInBackground() throws Exception {
- return null;
- }
-
- protected void done() {
- int totalLines = 0;
- int currentTab = 0;
- for (SketchCode sc : editor.getSketch().getCode()) {
- if (sc.isExtension("pde")) {
- try {
- if (editor.getSketch().getCurrentCode().equals(sc)) {
- // Adding + 1 to len because \n gets appended
- // for each
- // sketchcode extracted during processPDECode()
- totalLines = Base.countLines(sc.getDocument()
- .getText(0,
- sc.getDocument().getLength())) + 1;
- break;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- currentTab++;
- }
- // System.out.println("Total lines: " + totalLines);
-
- errorPointsOld.clear();
- for (ErrorMarker marker : errorPoints) {
- errorPointsOld.add(marker);
- }
- errorPoints.clear();
-
- // Each problem.getSourceLine() will have an extra line added
- // because of
- // class declaration in the beginning
- for (Problem problem : problems) {
- if (problem.tabIndex == currentTab) {
- // Ratio of error line to total lines
- float y = problem.lineNumber / ((float) totalLines);
- // Ratio multiplied by height of the error bar
- y *= fheight - 15; // -15 is just a vertical offset
- errorPoints.add(new ErrorMarker(problem, (int) y,
- problem.isError() ? ErrorMarker.Error
- : ErrorMarker.Warning));
- // System.out.println("Y: " + y);
- }
- }
-
- repaint();
- }
- };
-
- try {
- worker.execute(); // I eat concurrency bugs for breakfast.
- } catch (Exception exp) {
- System.out.println("Errorbar update markers is slacking."
- + exp.getMessage());
- // e.printStackTrace();
- }
- }
-
- /**
- * Check if new errors have popped up in the sketch since the last check
- *
- * @return true - if errors have changed
- */
- public boolean errorPointsChanged() {
- if (errorPointsOld.size() != errorPoints.size()) {
- editor.getTextArea().repaint();
- // System.out.println("2 Repaint " + System.currentTimeMillis());
- return true;
- }
-
- else {
- for (int i = 0; i < errorPoints.size(); i++) {
- if (errorPoints.get(i).y != errorPointsOld.get(i).y) {
- editor.getTextArea().repaint();
- // System.out.println("3 Repaint " +
- // System.currentTimeMillis());
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Add various mouse listeners.
- */
- protected void addListeners() {
-
- this.addMouseListener(new MouseAdapter() {
-
- // Find out which error/warning the user has clicked
- // and then scroll to that
- @SuppressWarnings("rawtypes")
- @Override
- public void mouseClicked(final MouseEvent e) {
- SwingWorker worker = new SwingWorker() {
-
- protected Object doInBackground() throws Exception {
- return null;
- }
-
- protected void done() {
- for (ErrorMarker eMarker : errorPoints) {
- // -2 and +2 are extra allowance, clicks in the
- // vicinity of the markers register that way
- if (e.getY() >= eMarker.y - 2
- && e.getY() <= eMarker.y + 2
- + errorMarkerHeight) {
- int currentTabErrorIndex = errorPoints
- .indexOf(eMarker);
- // System.out.println("Index: " +
- // currentTabErrorIndex);
- int currentTab = editor.getSketch()
- .getCodeIndex(
- editor.getSketch()
- .getCurrentCode());
-
- int totalErrorIndex = currentTabErrorIndex;
-
- for (int i = 0; i < errorCheckerService.problemsList
- .size(); i++) {
- Problem p = errorCheckerService.problemsList
- .get(i);
- if (p.tabIndex < currentTab) {
- totalErrorIndex++;
- }
- if (p.tabIndex == currentTab) {
- break;
- }
- }
- errorCheckerService
- .scrollToErrorLine(totalErrorIndex);
- }
- }
-
- }
- };
-
- try {
- worker.execute();
- } catch (Exception exp) {
- System.out.println("Errorbar mouseClicked is slacking."
- + exp.getMessage());
- // e.printStackTrace();
- }
-
- }
- });
-
- // Tooltip on hover
- this.addMouseMotionListener(new MouseMotionListener() {
-
- @SuppressWarnings("rawtypes")
- @Override
- public void mouseMoved(final MouseEvent e) {
- // System.out.println(e);
- SwingWorker worker = new SwingWorker() {
-
- protected Object doInBackground() throws Exception {
- return null;
- }
-
- protected void done() {
-
- for (ErrorMarker eMarker : errorPoints) {
- if (e.getY() >= eMarker.y - 2
- && e.getY() <= eMarker.y + 2
- + errorMarkerHeight) {
- // System.out.println("Index: " +
- // errorPoints.indexOf(y));
- int currentTab = editor.getSketch()
- .getCodeIndex(
- editor.getSketch()
- .getCurrentCode());
- int currentTabErrorCount = 0;
-
- for (int i = 0; i < errorPoints.size(); i++) {
- Problem p = errorPoints.get(i).problem;
- if (p.tabIndex == currentTab) {
- if (currentTabErrorCount == errorPoints
- .indexOf(eMarker)) {
- // System.out.println("Roger that.");
- String msg = (p.isError() ? "Error: "
- : "Warning: ")
- + p.message;
- setToolTipText(msg);
- setCursor(Cursor
- .getPredefinedCursor(Cursor.HAND_CURSOR));
- return;
- } else {
- currentTabErrorCount++;
- // System.out.println("Still looking..");
- }
- }
-
- }
- }
- // Reset cursor and tooltip
- else {
- setToolTipText("");
- setCursor(Cursor
- .getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- }
- }
-
- }
- };
- try {
- worker.execute();
- } catch (Exception exp) {
- System.out
- .println("Errorbar mousemoved Worker is slacking."
- + exp.getMessage());
- // e.printStackTrace();
- }
- }
-
- @Override
- public void mouseDragged(MouseEvent arg0) {
-
- }
- });
-
- }
-
-}
diff --git a/experimental/src/processing/mode/experimental/ErrorCheckerService.java b/experimental/src/processing/mode/experimental/ErrorCheckerService.java
deleted file mode 100755
index b196bbf26..000000000
--- a/experimental/src/processing/mode/experimental/ErrorCheckerService.java
+++ /dev/null
@@ -1,1113 +0,0 @@
-package processing.mode.experimental;
-
-import java.awt.EventQueue;
-import java.io.File;
-import java.io.FileFilter;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.swing.table.DefaultTableModel;
-
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTParser;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
-import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
-
-import processing.app.Base;
-import processing.app.Library;
-import processing.app.SketchCode;
-import processing.core.PApplet;
-
-public class ErrorCheckerService implements Runnable{
-
- private DebugEditor editor;
- /**
- * Error check happens every sleepTime milliseconds
- */
- public static final int sleepTime = 1000;
-
- /**
- * The amazing eclipse ast parser
- */
- private ASTParser parser;
-
- /**
- * Used to indirectly stop the Error Checker Thread
- */
- public boolean stopThread = false;
-
- /**
- * If true, Error Checking is paused. Calls to checkCode() become useless.
- */
- private boolean pauseThread = false;
-
- protected ErrorWindow errorWindow;
-
- /**
- * IProblem[] returned by parser stored in here
- */
- private IProblem[] problems;
-
- /**
- * Class name of current sketch
- */
- protected String className;
-
- /**
- * Source code of current sketch
- */
- protected String sourceCode;
-
- /**
- * URLs of extra imports jar files stored here.
- */
- protected URL[] classpath;
-
- /**
- * Stores all Problems in the sketch
- */
- public ArrayList problemsList;
-
- /**
- * How many lines are present till the initial class declaration? In static
- * mode, this would include imports, class declaration and setup
- * declaration. In nomral mode, this would include imports, class
- * declaration only. It's fate is decided inside preprocessCode()
- */
- public int mainClassOffset;
-
- /**
- * Is the sketch running in static mode or active mode?
- */
- public boolean staticMode = false;
-
- /**
- * Compilation Unit for current sketch
- */
- protected CompilationUnit cu;
-
- /**
- * If true, compilation checker will be reloaded with updated classpath
- * items.
- */
- private boolean loadCompClass = true;
-
- /**
- * Compiler Checker class. Note that methods for compilation checking are
- * called from the compilationChecker object, not from this
- */
- protected Class> checkerClass;
-
- /**
- * Compilation Checker object.
- */
- protected Object compilationChecker;
-
-
- /**
- * List of jar files to be present in compilation checker's classpath
- */
- protected ArrayList classpathJars;
-
- /**
- * Timestamp - for measuring total overhead
- */
- private long lastTimeStamp = System.currentTimeMillis();
-
- /**
- * Used for displaying the rotating slash on the Problem Window title bar
- */
- private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--",
- "\\" };
- private int slashAnimationIndex = 0;
-
- /**
- * Used to detect if the current tab index has changed and thus repaint the
- * textarea.
- */
- public int currentTab = 0, lastTab = 0;
-
- /**
- * Stores the current import statements in the program. Used to compare for
- * changed import statements and update classpath if needed.
- */
- protected ArrayList programImports;
-
- /**
- * List of imports when sketch was last checked. Used for checking for
- * changed imports
- */
- protected ArrayList previousImports = new ArrayList();
-
- /**
- * Teh Preprocessor
- */
- protected XQPreprocessor xqpreproc;
-
- /**
- * Regexp for import statements. (Used from Processing source)
- */
- final public String importRegexp = "(?:^|;)\\s*(import\\s+)((?:static\\s+)?\\S+)(\\s*;)";
-
- /**
- * Regexp for function declarations. (Used from Processing source)
- */
- final Pattern FUNCTION_DECL = Pattern
- .compile("(^|;)\\s*((public|private|protected|final|static)\\s+)*"
- + "(void|int|float|double|String|char|byte)"
- + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE);
-
- public ErrorCheckerService(DebugEditor debugEditor) {
- this.editor = debugEditor;
- initParser();
- initializeErrorWindow();
- xqpreproc = new XQPreprocessor();
- }
-
- /**
- * Initializes ASTParser
- */
- private void initParser() {
- try {
- parser = ASTParser.newParser(AST.JLS4);
- } catch (Exception e) {
- System.err.println("Experimental Mode initialization failed. "
- + "Are you running the right version of Processing? ");
- pauseThread();
- } catch (Error e) {
- System.err.println("Experimental Mode initialization failed. ");
- e.printStackTrace();
- pauseThread();
- }
- }
-
- /**
- * Initialiazes the Error Window
- */
- public void initializeErrorWindow() {
-
- if (editor == null) {
- return;
- }
-
- if (errorWindow != null) {
- return;
- }
-
- final ErrorCheckerService thisService = this;
- final DebugEditor thisEditor = editor;
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- try {
- errorWindow = new ErrorWindow(thisEditor, thisService);
- // errorWindow.setVisible(true);
- editor.toFront();
- errorWindow.errorTable.setFocusable(false);
- editor.setSelection(0, 0);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
-
- /**
- * checkCode() only on text area update
- */
- protected AtomicInteger textModified = new AtomicInteger(0);
-
- public void run() {
- stopThread = false;
-
- checkCode();
- while (!stopThread) {
- try {
- // Take a nap.
- Thread.sleep(sleepTime);
- } catch (Exception e) {
- System.out.println("Oops! [ErrorCheckerThreaded]: " + e);
- // e.printStackTrace();
- }
-
- if (pauseThread)
- continue;
-
- updatePaintedThingy();
-
- if(textModified.get() == 0)
- continue;
-
- // Check every x seconds
- checkCode();
-
- }
- }
-
-
-
-
- private boolean checkCode() {
-
- lastTimeStamp = System.currentTimeMillis();
- try {
- sourceCode = preprocessCode(editor.getSketch().getMainProgram());
-
- syntaxCheck();
-
- // No syntax errors, proceed for compilation check, Stage 2.
- if (problems.length == 0 && editor.compilationCheckEnabled) {
- sourceCode = xqpreproc.doYourThing(sourceCode, programImports);
- prepareCompilerClasspath();
- mainClassOffset = xqpreproc.mainClassOffset; // tiny, but
- // significant
- if (staticMode) {
- mainClassOffset++; // Extra line for setup() decl.
- }
- // System.out.println(sourceCode);
- // System.out.println("--------------------------");
- compileCheck();
- }
-
-
- updateErrorTable();
- editor.updateErrorBar(problemsList);
- updateEditorStatus();
- // updatePaintedThingy();
- int x = textModified.get();
- //System.out.println("TM " + x);
- if(x>=3){
- textModified.set(3);
- x = 3;
- }
-
- if(x>0)
- textModified.set(x - 1);
- else
- textModified.set(0);
- return true;
-
- } catch (Exception e) {
- System.out.println("Oops! [ErrorCheckerService.checkCode]: " + e);
- e.printStackTrace();
- }
- return false;
- }
-
- private void syntaxCheck() {
- parser.setSource(sourceCode.toCharArray());
- parser.setKind(ASTParser.K_COMPILATION_UNIT);
-
- @SuppressWarnings("unchecked")
- Map options = JavaCore.getOptions();
-
- JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options);
- options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
- parser.setCompilerOptions(options);
- cu = (CompilationUnit) parser.createAST(null);
-
- // Store errors returned by the ast parser
- problems = cu.getProblems();
- // System.out.println("Problem Count: " + problems.length);
- // Populate the probList
- problemsList = new ArrayList();
- for (int i = 0; i < problems.length; i++) {
- int a[] = calculateTabIndexAndLineNumber(problems[i]);
- Problem p = new Problem(problems[i], a[0], a[1]);
- problemsList.add(p);
- // System.out.println(p.toString());
- }
- }
-
- private void compileCheck() {
-
- // Currently (Sept, 2012) I'm using Java's reflection api to load the
- // CompilationChecker class(from CompilationChecker.jar) that houses the
- // Eclispe JDT compiler and call its getErrorsAsObj method to obtain
- // errors. This way, I'm able to add the paths of contributed libraries
- // to the classpath of CompilationChecker, dynamically.
-
- try {
-
- // NOTE TO SELF: If classpath contains null Strings
- // URLClassLoader gets angry. Drops NPE bombs.
-
- // If imports have changed, reload classes with new classpath.
- if (loadCompClass) {
-
- // if (classpathJars.size() > 0)
- // System.out
- // .println("Experimental Mode: Loading contributed libraries referenced by import statements.");
-
- File f = Base.getContentFile("modes" + File.separator + "experimental"
- + File.separator + "mode");
-
- if(!f.exists()) {
- System.err.println("Could not locate the files required for on-the-fly error checking. Bummer.");
- return;
- }
-
- FileFilter fileFilter = new FileFilter() {
- public boolean accept(File file) {
- return (file.getName().endsWith(".jar") && !file
- .getName().startsWith("experimental"));
- }
- };
-
- File[] jarFiles = f.listFiles(fileFilter);
- // System.out.println( "Jar files found? " + (jarFiles != null));
- for (File jarFile : jarFiles) {
- classpathJars.add(jarFile.toURI().toURL());
- }
-
- classpath = new URL[classpathJars.size()]; // + 1 for
- // Compilation
- // Checker class
- for (int i = 0; i < classpathJars.size(); i++) {
- classpath[i] = classpathJars.get(i);
- }
-
- // System.out.println("CP Len -- " + classpath.length);
- URLClassLoader classLoader = new URLClassLoader(classpath);
- // System.out.println("1.");
- checkerClass = Class.forName("CompilationChecker", true,
- classLoader);
- // System.out.println("2.");
- compilationChecker = checkerClass.newInstance();
- loadCompClass = false;
- }
-
- if (compilerSettings == null) {
- prepareCompilerSetting();
- }
- Method getErrors = checkerClass.getMethod("getErrorsAsObjArr",
- new Class[] { String.class, String.class, Map.class });
-
- Object[][] errorList = (Object[][]) getErrors
- .invoke(compilationChecker, className, sourceCode,
- compilerSettings);
-
- if (errorList == null) {
- return;
- }
-
- problems = new DefaultProblem[errorList.length];
-
- for (int i = 0; i < errorList.length; i++) {
-
- // for (int j = 0; j < errorList[i].length; j++)
- // System.out.print(errorList[i][j] + ", ");
-
- problems[i] = new DefaultProblem((char[]) errorList[i][0],
- (String) errorList[i][1],
- ((Integer) errorList[i][2]).intValue(),
- (String[]) errorList[i][3],
- ((Integer) errorList[i][4]).intValue(),
- ((Integer) errorList[i][5]).intValue(),
- ((Integer) errorList[i][6]).intValue(),
- ((Integer) errorList[i][7]).intValue(), 0);
-
- // System.out
- // .println("ECS: " + problems[i].getMessage() + ","
- // + problems[i].isError() + ","
- // + problems[i].isWarning());
-
- IProblem problem = problems[i];
-
- int a[] = calculateTabIndexAndLineNumber(problem);
- Problem p = new Problem(problem, a[0], a[1]);
- if ((Boolean) errorList[i][8]) {
- p.setType(Problem.ERROR);
- }
-
- if ((Boolean) errorList[i][9]) {
- p.setType(Problem.WARNING);
- }
-
- // If warnings are disabled, skip 'em
- if (p.isWarning() && !warningsEnabled) {
- continue;
- }
- problemsList.add(p);
- }
-
- } catch (ClassNotFoundException e) {
- System.err.println("Compiltation Checker files couldn't be found! "
- + e + " compileCheck() problem.");
- stopThread();
- } catch (MalformedURLException e) {
- System.err.println("Compiltation Checker files couldn't be found! "
- + e + " compileCheck() problem.");
- stopThread();
- } catch (Exception e) {
- System.err.println("compileCheck() problem." + e);
- e.printStackTrace();
- stopThread();
- } catch (NoClassDefFoundError e) {
- System.err
- .println(e
- + " compileCheck() problem. Somebody tried to mess with Experimental Mode files.");
- stopThread();
- }
- // System.out.println("Compilecheck, Done.");
- }
-
- /**
- * Processes import statements to obtain classpaths of contributed
- * libraries. This would be needed for compilation check. Also, adds
- * stuff(jar files, class files, candy) from the code folder. And it looks
- * messed up.
- *
- */
- private void prepareCompilerClasspath() {
- if (!loadCompClass) {
- return;
- }
-
- // System.out.println("1..");
- classpathJars = new ArrayList();
- String entry = "";
- boolean codeFolderChecked = false;
- for (ImportStatement impstat : programImports) {
- String item = impstat.importName;
- int dot = item.lastIndexOf('.');
- entry = (dot == -1) ? item : item.substring(0, dot);
-
- entry = entry.substring(6).trim();
- // System.out.println("Entry--" + entry);
- if (ignorableImport(entry)) {
- // System.out.println("Ignoring: " + entry);
- continue;
- }
- Library library = null;
-
- // Try to get the library classpath and add it to the list
- try {
- library = editor.getMode().getLibrary(entry);
- // System.out.println("lib->" + library.getClassPath() + "<-");
- String libraryPath[] = PApplet.split(library.getClassPath()
- .substring(1).trim(), File.pathSeparatorChar);
- for (int i = 0; i < libraryPath.length; i++) {
- // System.out.println(entry + " ::"
- // + new File(libraryPath[i]).toURI().toURL());
- classpathJars.add(new File(libraryPath[i]).toURI().toURL());
- }
- // System.out.println("-- ");
- // classpath[count] = (new File(library.getClassPath()
- // .substring(1))).toURI().toURL();
- // System.out.println(" found ");
- // System.out.println(library.getClassPath().substring(1));
- } catch (Exception e) {
- if (library == null && !codeFolderChecked) {
- // System.out.println(1);
- // Look around in the code folder for jar files
- if (editor.getSketch().hasCodeFolder()) {
- File codeFolder = editor.getSketch().getCodeFolder();
-
- // get a list of .jar files in the "code" folder
- // (class files in subfolders should also be picked up)
- String codeFolderClassPath = Base
- .contentsToClassPath(codeFolder);
- codeFolderChecked = true;
- if (codeFolderClassPath.equalsIgnoreCase("")) {
- System.err.println("Experimental Mode: Yikes! Can't find \""
- + entry
- + "\" library! Line: "
- + impstat.lineNumber
- + " in tab: "
- + editor.getSketch().getCode(impstat.tab)
- .getPrettyName());
- System.out
- .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch");
-
- }
- String codeFolderPath[] = PApplet.split(
- codeFolderClassPath.substring(1).trim(),
- File.pathSeparatorChar);
- try {
- for (int i = 0; i < codeFolderPath.length; i++) {
- classpathJars.add(new File(codeFolderPath[i])
- .toURI().toURL());
- }
-
- } catch (Exception e2) {
- System.out
- .println("Yikes! codefolder, prepareImports(): "
- + e2);
- }
- } else {
- System.err.println("Experimental Mode: Yikes! Can't find \""
- + entry
- + "\" library! Line: "
- + impstat.lineNumber
- + " in tab: "
- + editor.getSketch().getCode(impstat.tab)
- .getPrettyName());
- System.out
- .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch");
- }
-
- } else {
- System.err
- .println("Yikes! There was some problem in prepareImports(): "
- + e);
- System.err.println("I was processing: " + entry);
-
- // e.printStackTrace();
- }
- }
-
- }
-
- }
-
- /**
- * Ignore processing packages, java.*.*. etc.
- *
- * @param packageName
- * @return boolean
- */
- protected boolean ignorableImport(String packageName) {
- // packageName.startsWith("processing.")
- // ||
- if (packageName.startsWith("java.") || packageName.startsWith("javax.")) {
- return true;
- }
- return false;
- }
-
- /**
- * Various option for JDT Compiler
- */
- @SuppressWarnings("rawtypes")
- protected Map compilerSettings;
-
- /**
- * Enable/Disable warnings from being shown
- */
- public boolean warningsEnabled = true;
-
- /**
- * Sets compiler options for JDT Compiler
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected void prepareCompilerSetting() {
- compilerSettings = new HashMap();
-
- compilerSettings.put(CompilerOptions.OPTION_LineNumberAttribute,
- CompilerOptions.GENERATE);
- compilerSettings.put(CompilerOptions.OPTION_SourceFileAttribute,
- CompilerOptions.GENERATE);
- compilerSettings.put(CompilerOptions.OPTION_Source,
- CompilerOptions.VERSION_1_6);
- compilerSettings.put(CompilerOptions.OPTION_ReportUnusedImport,
- CompilerOptions.IGNORE);
- compilerSettings.put(CompilerOptions.OPTION_ReportMissingSerialVersion,
- CompilerOptions.IGNORE);
- compilerSettings.put(CompilerOptions.OPTION_ReportRawTypeReference,
- CompilerOptions.IGNORE);
- compilerSettings.put(
- CompilerOptions.OPTION_ReportUncheckedTypeOperation,
- CompilerOptions.IGNORE);
- }
-
-
- /**
- * Updates the error table in the Error Window.
- */
- synchronized public void updateErrorTable() {
-
- try {
- String[][] errorData = new String[problemsList.size()][3];
- for (int i = 0; i < problemsList.size(); i++) {
- errorData[i][0] = problemsList.get(i).message;
- errorData[i][1] = editor.getSketch()
- .getCode(problemsList.get(i).tabIndex).getPrettyName();
- errorData[i][2] = problemsList.get(i).lineNumber + "";
- }
-
- if (errorWindow != null) {
- DefaultTableModel tm = new DefaultTableModel(errorData,
- XQErrorTable.columnNames);
- if (errorWindow.isVisible()) {
- errorWindow.updateTable(tm);
- }
-
- // Update error table in the editor
- editor.updateTable(tm);
-
- // A rotating slash animation on the title bar to show
- // that error checker thread is running
-
- slashAnimationIndex++;
- if (slashAnimationIndex == slashAnimation.length) {
- slashAnimationIndex = 0;
- }
- if (editor != null) {
- String info = slashAnimation[slashAnimationIndex] + " T:"
- + (System.currentTimeMillis() - lastTimeStamp)
- + "ms";
- errorWindow.setTitle("Problems - "
- + editor.getSketch().getName() + " " + info);
- }
- }
-
- } catch (Exception e) {
- System.out.println("Exception at updateErrorTable() " + e);
- e.printStackTrace();
- stopThread();
- }
-
- }
-
- /**
- * Repaints the textarea if required
- */
- public void updatePaintedThingy() {
- editor.getTextArea().repaint();
- updateEditorStatus();
- currentTab = editor.getSketch().getCodeIndex(
- editor.getSketch().getCurrentCode());
- if (currentTab != lastTab) {
- lastTab = currentTab;
- editor.updateErrorBar(problemsList);
- return;
- }
-
- }
-
- /**
- * Updates editor status bar, depending on whether the caret is on an error
- * line or not
- */
- public void updateEditorStatus() {
- // editor.statusNotice("Position: " +
- // editor.getTextArea().getCaretLine());
- boolean notFound = true;
- for (ErrorMarker emarker : editor.errorBar.errorPoints) {
- if (emarker.problem.lineNumber == editor.getTextArea()
- .getCaretLine() + 1) {
- if (emarker.type == ErrorMarker.Warning) {
- editor.statusNotice(emarker.problem.message);
- }
- else {
- editor.statusError(emarker.problem.message);
- }
- return;
- }
- }
- if (notFound) {
- editor.statusEmpty();
- }
- }
-
- /**
- * Calculates the tab number and line number of the error in that particular
- * tab. Provides mapping between pure java and pde code.
- *
- * @param problem
- * - IProblem
- * @return int[0] - tab number, int[1] - line number
- */
- public int[] calculateTabIndexAndLineNumber(IProblem problem) {
- // String[] lines = {};// = PApplet.split(sourceString, '\n');
- int codeIndex = 0;
-
- int x = problem.getSourceLineNumber() - mainClassOffset;
- if (x < 0) {
- // System.out.println("Negative line number "
- // + problem.getSourceLineNumber() + " , offset "
- // + mainClassOffset);
- x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index
- if (x < programImports.size() && x >= 0) {
- ImportStatement is = programImports.get(x);
- // System.out.println(is.importName + ", " + is.tab + ", "
- // + is.lineNumber);
- return new int[] { is.tab, is.lineNumber };
- } else {
-
- // Some seriously ugly stray error, just can't find the source
- // line! Simply return first line for first tab.
- return new int[] { 0, 1 };
- }
-
- }
-
- try {
- for (SketchCode sc : editor.getSketch().getCode()) {
- if (sc.isExtension("pde")) {
- int len = 0;
- if (editor.getSketch().getCurrentCode().equals(sc)) {
- len = Base.countLines(sc.getDocument().getText(0,
- sc.getDocument().getLength())) + 1;
- } else {
- len = Base.countLines(sc.getProgram()) + 1;
- }
-
- // System.out.println("x,len, CI: " + x + "," + len + ","
- // + codeIndex);
-
- if (x >= len) {
-
- // We're in the last tab and the line count is greater
- // than the no.
- // of lines in the tab,
- if (codeIndex >= editor.getSketch().getCodeCount() - 1) {
- // System.out.println("Exceeds lc " + x + "," + len
- // + problem.toString());
- // x = len
- x = editor.getSketch().getCode(codeIndex)
- .getLineCount();
- // TODO: Obtain line having last non-white space
- // character in the code.
- break;
- } else {
- x -= len;
- codeIndex++;
- }
- } else {
-
- if (codeIndex >= editor.getSketch().getCodeCount()) {
- codeIndex = editor.getSketch().getCodeCount() - 1;
- }
- break;
- }
-
- }
- }
- } catch (Exception e) {
- System.err
- .println("Things got messed up in ErrorCheckerService.calculateTabIndexAndLineNumber()");
- }
-
- return new int[] { codeIndex, x };
- }
-
- /**
- * Fetches code from the editor tabs and pre-processes it into parsable pure
- * java source. And there's a difference between parsable and compilable.
- * XQPrerocessor.java makes this code compilable.
- * Handles:
Removal of import statements
Conversion of int(),
- * char(), etc to (int)(), (char)(), etc.
Replacing '#' with 0xff for
- * color representation
Converts all 'color' datatypes to int
- * (experimental)
Appends class declaration statement after determining
- * the mode the sketch is in - ACTIVE or STATIC
- *
- * @return String - Pure java representation of PDE code. Note that this
- * code is not yet compile ready.
- */
-
- private String preprocessCode(String pdeCode) {
-
- programImports = new ArrayList();
-
- StringBuffer rawCode = new StringBuffer();
-
- try {
-
- for (SketchCode sc : editor.getSketch().getCode()) {
- if (sc.isExtension("pde")) {
-
- try {
-
- if (editor.getSketch().getCurrentCode().equals(sc)) {
-
- rawCode.append(scrapImportStatements(sc.getDocument()
- .getText(0,
- sc.getDocument()
- .getLength()),
- editor.getSketch()
- .getCodeIndex(sc)));
- } else {
-
- rawCode.append(scrapImportStatements(sc.getProgram(), editor
- .getSketch().getCodeIndex(sc)));
-
- }
- rawCode.append('\n');
- } catch (Exception e) {
- System.err.println("Exception in preprocessCode() - bigCode "
- + e.toString());
- }
- rawCode.append('\n');
- }
- }
-
- } catch (Exception e) {
- System.out.println("Exception in preprocessCode()");
- }
- String sourceAlt = rawCode.toString();
- // Replace comments with whitespaces
- // sourceAlt = scrubComments(sourceAlt);
-
- // Find all int(*), replace with PApplet.parseInt(*)
-
- // \bint\s*\(\s*\b , i.e all exclusive "int("
-
- String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" };
-
- for (String dataType : dataTypeFunc) {
- String dataTypeRegexp = "\\b" + dataType + "\\s*\\(";
- Pattern pattern = Pattern.compile(dataTypeRegexp);
- Matcher matcher = pattern.matcher(sourceAlt);
-
- // while (matcher.find()) {
- // System.out.print("Start index: " + matcher.start());
- // System.out.println(" End index: " + matcher.end() + " ");
- // System.out.println("-->" + matcher.group() + "<--");
- // }
- sourceAlt = matcher.replaceAll("PApplet.parse"
- + Character.toUpperCase(dataType.charAt(0))
- + dataType.substring(1) + "(");
-
- }
-
- // Find all #[web color] and replace with 0xff[webcolor]
- // Should be 6 digits only.
- final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W";
- Pattern webPattern = Pattern.compile(webColorRegexp);
- Matcher webMatcher = webPattern.matcher(sourceAlt);
- while (webMatcher.find()) {
- // System.out.println("Found at: " + webMatcher.start());
- String found = sourceAlt.substring(webMatcher.start(),
- webMatcher.end());
- // System.out.println("-> " + found);
- sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1));
- webMatcher = webPattern.matcher(sourceAlt);
- }
-
- // Replace all color data types with int
- // Regex, Y U SO powerful?
- final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())";
- Pattern colorPattern = Pattern.compile(colorTypeRegex);
- Matcher colorMatcher = colorPattern.matcher(sourceAlt);
- sourceAlt = colorMatcher.replaceAll("int");
-
- checkForChangedImports();
-
- className = (editor == null) ? "DefaultClass" : editor.getSketch()
- .getName();
-
- // Check whether the code is being written in STATIC mode(no function
- // declarations) - append class declaration and void setup() declaration
- Matcher matcher = FUNCTION_DECL.matcher(sourceAlt);
- if (!matcher.find()) {
- sourceAlt = "public class " + className + " extends PApplet {\n"
- + "public void setup() {\n" + sourceAlt
- + "\nnoLoop();\n}\n" + "\n}\n";
- staticMode = true;
- mainClassOffset = 2;
-
- } else {
- sourceAlt = "public class " + className + " extends PApplet {\n"
- + sourceAlt + "\n}";
- staticMode = false;
- mainClassOffset = 1;
- }
-
- // Handle unicode characters
- sourceAlt = substituteUnicode(sourceAlt);
-
-// System.out.println("-->\n" + sourceAlt + "\n<--");
-// System.out.println("PDE code processed - "
-// + editor.getSketch().getName());
- sourceCode = sourceAlt;
- return sourceAlt;
-
- }
-
- /**
- * Scrolls to the error source in code. And selects the line text. Used by
- * XQErrorTable and ErrorBar
- *
- * @param errorIndex
- * - index of error
- */
- public void scrollToErrorLine(int errorIndex) {
- if (editor == null) {
- return;
- }
-
- if (errorIndex < problemsList.size() && errorIndex >= 0) {
- Problem p = problemsList.get(errorIndex);
- try {
- editor.toFront();
- editor.getSketch().setCurrentCode(p.tabIndex);
- editor.getTextArea().scrollTo(p.lineNumber - 1, 0);
- editor.setSelection(editor.getTextArea()
- .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)
- + editor.getTextArea().getLineText(p.lineNumber - 1)
- .trim().length(), editor.getTextArea()
- .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1));
- editor.repaint();
- } catch (Exception e) {
- System.err
- .println(e
- + " : Error while selecting text in scrollToErrorLine()");
- // e.printStackTrace();
- }
- // System.out.println("---");
-
- }
- }
-
- /**
- * Checks if import statements in the sketch have changed. If they have,
- * compiler classpath needs to be updated.
- */
- private void checkForChangedImports() {
- // System.out.println("Imports: " + programImports.size() +
- // " Prev Imp: "
- // + previousImports.size());
- if (programImports.size() != previousImports.size()) {
- // System.out.println(1);
- loadCompClass = true;
- previousImports = programImports;
- } else {
- for (int i = 0; i < programImports.size(); i++) {
- if (!programImports.get(i).importName.equals(previousImports
- .get(i).importName)) {
- // System.out.println(2);
- loadCompClass = true;
- previousImports = programImports;
- break;
- }
- }
- }
- // System.out.println("load..? " + loadCompClass);
- }
-
- /**
- * Removes import statements from tabSource, replaces each with white spaces
- * and adds the import to the list of program imports
- *
- * @param tabProgram
- * - Code in a tab
- * @param tabNumber
- * - index of the tab
- * @return String - Tab code with imports replaced with white spaces
- */
- private String scrapImportStatements(String tabProgram, int tabNumber) {
-
- String tabSource = new String(tabProgram);
- do {
- // System.out.println("-->\n" + sourceAlt + "\n<--");
- String[] pieces = PApplet.match(tabSource, importRegexp);
-
- // Stop the loop if we've removed all the import lines
- if (pieces == null) {
- break;
- }
-
- String piece = pieces[1] + pieces[2] + pieces[3];
- int len = piece.length(); // how much to trim out
-
- // programImports.add(piece); // the package name
-
- // find index of this import in the program
- int idx = tabSource.indexOf(piece);
- // System.out.print("Import -> " + piece);
- // System.out.println(" - "
- // + Base.countLines(tabSource.substring(0, idx)) + " tab "
- // + tabNumber);
- programImports.add(new ImportStatement(piece, tabNumber, Base
- .countLines(tabSource.substring(0, idx))));
- // Remove the import from the main program
- // Substitue with white spaces
- String whiteSpace = "";
- for (int j = 0; j < piece.length(); j++) {
- whiteSpace += " ";
- }
- tabSource = tabSource.substring(0, idx) + whiteSpace
- + tabSource.substring(idx + len);
-
- } while (true);
- // System.out.println(tabSource);
- return tabSource;
- }
-
- /**
- * Replaces non-ascii characters with their unicode escape sequences and
- * stuff. Used as it is from
- * processing.src.processing.mode.java.preproc.PdePreprocessor
- *
- * @param program
- * - Input String containing non ascii characters
- * @return String - Converted String
- */
- public static String substituteUnicode(String program) {
- // check for non-ascii chars (these will be/must be in unicode format)
- char p[] = program.toCharArray();
- int unicodeCount = 0;
- for (int i = 0; i < p.length; i++) {
- if (p[i] > 127) {
- unicodeCount++;
- }
- }
- if (unicodeCount == 0) {
- return program;
- }
- // if non-ascii chars are in there, convert to unicode escapes
- // add unicodeCount * 5.. replacing each unicode char
- // with six digit uXXXX sequence (xxxx is in hex)
- // (except for nbsp chars which will be a replaced with a space)
- int index = 0;
- char p2[] = new char[p.length + unicodeCount * 5];
- for (int i = 0; i < p.length; i++) {
- if (p[i] < 128) {
- p2[index++] = p[i];
- } else if (p[i] == 160) { // unicode for non-breaking space
- p2[index++] = ' ';
- } else {
- int c = p[i];
- p2[index++] = '\\';
- p2[index++] = 'u';
- char str[] = Integer.toHexString(c).toCharArray();
- // add leading zeros, so that the length is 4
- // for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
- for (int m = 0; m < 4 - str.length; m++)
- p2[index++] = '0';
- System.arraycopy(str, 0, p2, index, str.length);
- index += str.length;
- }
- }
- return new String(p2, 0, index);
- }
-
- /**
- * Stops the Error Checker Service thread
- */
- public void stopThread() {
- stopThread = true;
- }
-
- /**
- * Pauses the Error Checker Service thread
- */
- public void pauseThread() {
- pauseThread = true;
- }
-
- /**
- * Resumes the Error Checker Service thread
- */
- public void resumeThread() {
- pauseThread = false;
- }
-
- public DebugEditor getEditor() {
- return editor;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/ErrorMarker.java b/experimental/src/processing/mode/experimental/ErrorMarker.java
deleted file mode 100755
index bc244f7a1..000000000
--- a/experimental/src/processing/mode/experimental/ErrorMarker.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package processing.mode.experimental;
-/**
- * Error markers displayed on the Error Bar.
- *
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- */
- public class ErrorMarker {
- /**
- * y co-ordinate of the marker
- */
- public int y;
- /**
- * Type of marker: Error or Warning?
- */
- public int type = -1;
- /**
- * Error Type constant
- */
- public static final int Error = 1;
- /**
- * Warning Type constant
- */
- public static final int Warning = 2;
- /**
- * Problem that the error marker represents
- * @see Problem
- */
- public Problem problem;
-
- public ErrorMarker(Problem problem, int y, int type) {
- this.problem = problem;
- this.y = y;
- this.type = type;
- }
- }
\ No newline at end of file
diff --git a/experimental/src/processing/mode/experimental/ErrorWindow.java b/experimental/src/processing/mode/experimental/ErrorWindow.java
deleted file mode 100755
index db4e2a8c8..000000000
--- a/experimental/src/processing/mode/experimental/ErrorWindow.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- Part of the XQMode project - https://github.com/Manindra29/XQMode
-
- Under Google Summer of Code 2012 -
- http://www.google-melange.com/gsoc/homepage/google/gsoc2012
-
- Copyright (C) 2012 Manindra Moharana
-
- 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.mode.experimental;
-
-import java.awt.BorderLayout;
-import java.awt.Frame;
-import java.awt.Point;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.WindowConstants;
-import javax.swing.border.EmptyBorder;
-import javax.swing.table.TableModel;
-
-import processing.app.Editor;
-import processing.app.Toolkit;
-
-/**
- * Error Window that displays a tablular list of errors. Clicking on an error
- * scrolls to its location in the code.
- *
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- */
-public class ErrorWindow extends JFrame {
-
- private JPanel contentPane;
- /**
- * The table displaying the errors
- */
- protected XQErrorTable errorTable;
- /**
- * Scroll pane that contains the Error Table
- */
- protected JScrollPane scrollPane;
-
- protected DebugEditor thisEditor;
- private JFrame thisErrorWindow;
-
- /**
- * Handles the sticky Problem window
- */
- private DockTool2Base Docker;
-
- protected ErrorCheckerService errorCheckerService;
-
- /**
- * Preps up ErrorWindow
- *
- * @param editor
- * - Editor
- * @param ecs - ErrorCheckerService
- */
- public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) {
- thisErrorWindow = this;
- errorCheckerService = ecs;
- thisEditor = editor;
- setTitle("Problems");
- prepareFrame();
- }
-
- /**
- * Sets up ErrorWindow
- */
- protected void prepareFrame() {
- Toolkit.setIcon(this);
- setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
- // Default size: setBounds(100, 100, 458, 160);
- setBounds(100, 100, 458, 160); // Yeah, I hardcode such things sometimes. Hate me.
-
- contentPane = new JPanel();
- contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
- setContentPane(contentPane);
- contentPane.setLayout(new BorderLayout(0, 0));
-
- scrollPane = new JScrollPane();
- contentPane.add(scrollPane);
-
- errorTable = new XQErrorTable(errorCheckerService);
- scrollPane.setViewportView(errorTable);
-
- try {
- Docker = new DockTool2Base();
- addListeners();
- } catch (Exception e) {
- System.out.println("addListeners() acted silly.");
- e.printStackTrace();
- }
-
- if (thisEditor != null) {
- setLocation(new Point(thisEditor.getLocation().x
- + thisEditor.getWidth(), thisEditor.getLocation().y));
- }
-
- }
-
- /**
- * Updates the error table with new data(Table Model). Called from Error
- * Checker Service.
- *
- * @param tableModel
- * - Table Model
- * @return True - If error table was updated successfully.
- */
- synchronized public boolean updateTable(final TableModel tableModel) {
- // XQErrorTable handles evrything now
- return errorTable.updateTable(tableModel);
- }
-
- /**
- * Adds various listeners to components of EditorWindow and to the Editor
- * window
- */
- protected void addListeners() {
-
- if (thisErrorWindow == null)
- System.out.println("ERW null");
-
- thisErrorWindow.addComponentListener(new ComponentListener() {
-
- @Override
- public void componentShown(ComponentEvent e) {
-
- }
-
- @Override
- public void componentResized(ComponentEvent e) {
- Docker.tryDocking();
- }
-
- @Override
- public void componentMoved(ComponentEvent e) {
- Docker.tryDocking();
- }
-
- @Override
- public void componentHidden(ComponentEvent e) {
-
- }
- });
-
- thisErrorWindow.addWindowListener(new WindowAdapter() {
-
- @Override
- public void windowClosing(WindowEvent e) {
- thisEditor.problemWindowMenuCB.setSelected(false);
- }
-
- @Override
- public void windowDeiconified(WindowEvent e) {
- thisEditor.setExtendedState(Frame.NORMAL);
- }
-
- });
-
- if (thisEditor == null) {
- System.out.println("Editor null");
- return;
- }
-
- thisEditor.addWindowListener(new WindowAdapter() {
-
- @Override
- public void windowClosing(WindowEvent e) {
-
- }
-
- @Override
- public void windowClosed(WindowEvent e) {
- errorCheckerService.pauseThread();
- errorCheckerService.stopThread(); // Bye bye thread.
- thisErrorWindow.dispose();
- }
-
- @Override
- public void windowIconified(WindowEvent e) {
- thisErrorWindow.setExtendedState(Frame.ICONIFIED);
- }
-
- @Override
- public void windowDeiconified(WindowEvent e) {
- thisErrorWindow.setExtendedState(Frame.NORMAL);
- }
-
- });
-
- thisEditor.addComponentListener(new ComponentListener() {
-
- @Override
- public void componentShown(ComponentEvent e) {
-
- }
-
- @Override
- public void componentResized(ComponentEvent e) {
- if (Docker.isDocked()) {
- Docker.dock();
- } else {
- Docker.tryDocking();
- }
- }
-
- @Override
- public void componentMoved(ComponentEvent e) {
-
- if (Docker.isDocked()) {
- Docker.dock();
- } else {
- Docker.tryDocking();
- }
-
- }
-
- @Override
- public void componentHidden(ComponentEvent e) {
- // System.out.println("ed hidden");
- }
- });
-
- }
-
-
- /**
- * Implements the docking feature of the tool - The frame sticks to the
- * editor and once docked, moves along with it as the editor is resized,
- * moved, or closed.
- *
- * This class has been borrowed from Tab Manager tool by Thomas Diewald. It
- * has been slightly modified and used here.
- *
- * @author Thomas Diewald , http://thomasdiewald.com
- */
- private class DockTool2Base {
-
- private int docking_border = 0;
- private int dock_on_editor_y_offset_ = 0;
- private int dock_on_editor_x_offset_ = 0;
-
- // ///////////////////////////////
- // ____2____
- // | |
- // | |
- // 0 | editor | 1
- // | |
- // |_________|
- // 3
- // ///////////////////////////////
-
- // public void reset() {
- // dock_on_editor_y_offset_ = 0;
- // dock_on_editor_x_offset_ = 0;
- // docking_border = 0;
- // }
-
- public boolean isDocked() {
- return (docking_border >= 0);
- }
-
- private final int MAX_GAP_ = 20;
-
- //
- public void tryDocking() {
- if (thisEditor == null)
- return;
- Editor editor = thisEditor;
- Frame frame = thisErrorWindow;
-
- int ex = editor.getX();
- int ey = editor.getY();
- int ew = editor.getWidth();
- int eh = editor.getHeight();
-
- int fx = frame.getX();
- int fy = frame.getY();
- int fw = frame.getWidth();
- int fh = frame.getHeight();
-
- if (((fy > ey) && (fy < ey + eh))
- || ((fy + fh > ey) && (fy + fh < ey + eh))) {
- int dis_border_left = Math.abs(ex - (fx + fw));
- int dis_border_right = Math.abs((ex + ew) - (fx));
-
- if (dis_border_left < MAX_GAP_ || dis_border_right < MAX_GAP_) {
- docking_border = (dis_border_left < dis_border_right) ? 0
- : 1;
- dock_on_editor_y_offset_ = fy - ey;
- dock();
- return;
- }
- }
-
- if (((fx > ex) && (fx < ex + ew))
- || ((fx + fw > ey) && (fx + fw < ex + ew))) {
- int dis_border_top = Math.abs(ey - (fy + fh));
- int dis_border_bot = Math.abs((ey + eh) - (fy));
-
- if (dis_border_top < MAX_GAP_ || dis_border_bot < MAX_GAP_) {
- docking_border = (dis_border_top < dis_border_bot) ? 2 : 3;
- dock_on_editor_x_offset_ = fx - ex;
- dock();
- return;
- }
- }
- docking_border = -1;
- }
-
- public void dock() {
- if (thisEditor == null)
- return;
- Editor editor = thisEditor;
- Frame frame = thisErrorWindow;
-
- int ex = editor.getX();
- int ey = editor.getY();
- int ew = editor.getWidth();
- int eh = editor.getHeight();
-
- // int fx = frame.getX();
- // int fy = frame.getY();
- int fw = frame.getWidth();
- int fh = frame.getHeight();
-
- int x = 0, y = 0;
- if (docking_border == -1) {
- return;
- }
-
- if (docking_border == 0) {
- x = ex - fw;
- y = ey + dock_on_editor_y_offset_;
- }
- if (docking_border == 1) {
- x = ex + ew;
- y = ey + dock_on_editor_y_offset_;
- }
-
- if (docking_border == 2) {
- x = ex + dock_on_editor_x_offset_;
- y = ey - fh;
- }
- if (docking_border == 3) {
- x = ex + dock_on_editor_x_offset_;
- y = ey + eh;
- }
- frame.setLocation(x, y);
- }
-
- }
-}
diff --git a/experimental/src/processing/mode/experimental/ExperimentalMode.java b/experimental/src/processing/mode/experimental/ExperimentalMode.java
deleted file mode 100755
index 50d7ce4b3..000000000
--- a/experimental/src/processing/mode/experimental/ExperimentalMode.java
+++ /dev/null
@@ -1,171 +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 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.mode.experimental;
-
-import java.awt.Color;
-import java.io.File;
-import java.io.IOException;
-import java.util.logging.FileHandler;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import processing.app.Base;
-import processing.app.Editor;
-import processing.app.EditorState;
-import processing.app.Mode;
-import processing.mode.java.JavaMode;
-
-
-/**
- * Experimental Mode for Processing, combines Debug Mode and XQMode and
- * starts us working toward our next generation editor/debugger setup.
- */
-public class ExperimentalMode extends JavaMode {
- public static final boolean VERBOSE_LOGGING = true;
- //public static final boolean VERBOSE_LOGGING = false;
- public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes)
-
-
- public ExperimentalMode(Base base, File folder) {
- super(base, folder);
-
- // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus
- for (Mode m : base.getModeList()) {
- if (m.getClass() == JavaMode.class) {
- JavaMode jMode = (JavaMode) m;
- librariesFolder = jMode.getLibrariesFolder();
- rebuildLibraryList();
- break;
- }
- }
-
- // Fetch examples and reference from java mode
- // thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4)
- examplesFolder = Base.getContentFile("modes/java/examples");
- // https://github.com/martinleopold/DebugMode/issues/6
- referenceFolder = Base.getContentFile("modes/java/reference");
-
- // set logging level
- Logger globalLogger = Logger.getLogger("");
- //Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x
- if (VERBOSE_LOGGING) {
- globalLogger.setLevel(Level.INFO);
- } else {
- globalLogger.setLevel(Level.WARNING);
- }
-
- // enable logging to file
- try {
- // settings is writable for built-in modes, mode folder is not writable
- File logFolder = Base.getSettingsFile("debug");
- if (!logFolder.exists()) {
- logFolder.mkdir();
- }
- File logFile = new File(logFolder, "DebugMode.%g.log");
- Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false);
- globalLogger.addHandler(handler);
-
- } catch (IOException ex) {
- Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex);
- } catch (SecurityException ex) {
- Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex);
- }
-
- // disable initial chattiness for now
-// // output version from manifest file
-// Package p = ExperimentalMode.class.getPackage();
-// String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")";
-// //System.out.println(titleAndVersion);
-// Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion);
- }
-
-
- @Override
- public String getTitle() {
- return "Experimental";
- }
-
-
- public File[] getKeywordFiles() {
- return new File[] {
- Base.getContentFile("modes/java/keywords.txt")
- };
- }
-
-
- /**
- * Create a new editor associated with this mode.
- */
- @Override
- public Editor createEditor(Base base, String path, EditorState state) {
- return new DebugEditor(base, path, state, this);
- }
-
-
- /**
- * Load a String value from theme.txt
- *
- * @param attribute the attribute key to load
- * @param defaultValue the default value
- * @return the attributes value, or the default value if the attribute
- * couldn't be loaded
- */
- public String loadThemeString(String attribute, String defaultValue) {
- String newString = theme.get(attribute);
- if (newString != null) {
- return newString;
- }
- Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error loading String: {0}", attribute);
- return defaultValue;
- }
-
-
- /**
- * Load a Color value from theme.txt
- *
- * @param attribute the attribute key to load
- * @param defaultValue the default value
- * @return the attributes value, or the default value if the attribute
- * couldn't be loaded
- */
- public Color getThemeColor(String attribute, Color defaultValue) {
- Color newColor = theme.getColor(attribute);
- if (newColor != null) {
- return newColor;
- }
- System.out.println("error loading color: " + attribute);
- Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute);
- return defaultValue;
- }
-
-
- public ClassLoader getJavaModeClassLoader() {
- for (Mode m : base.getModeList()) {
- if (m.getClass() == JavaMode.class) {
- JavaMode jMode = (JavaMode) m;
- return jMode.getClassLoader();
- }
- }
- // badness
- return null;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/FieldNode.java b/experimental/src/processing/mode/experimental/FieldNode.java
deleted file mode 100755
index dbe9d4fd9..000000000
--- a/experimental/src/processing/mode/experimental/FieldNode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.ClassNotLoadedException;
-import com.sun.jdi.Field;
-import com.sun.jdi.InvalidTypeException;
-import com.sun.jdi.ObjectReference;
-import com.sun.jdi.Value;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Specialized {@link VariableNode} for representing fields. Overrides
- * {@link #setValue} to properly change the value of the encapsulated field.
- *
- * @author Martin Leopold
- */
-public class FieldNode extends VariableNode {
-
- protected Field field;
- protected ObjectReference obj;
-
- /**
- * Construct a {@link FieldNode}.
- *
- * @param name the name
- * @param type the type
- * @param value the value
- * @param field the field
- * @param obj a reference to the object containing the field
- */
- public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) {
- super(name, type, value);
- this.field = field;
- this.obj = obj;
- }
-
- @Override
- public void setValue(Value value) {
- try {
- obj.setValue(field, value);
- } catch (InvalidTypeException ex) {
- Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex);
- } catch (ClassNotLoadedException ex) {
- Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex);
- }
- this.value = value;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/ImportStatement.java b/experimental/src/processing/mode/experimental/ImportStatement.java
deleted file mode 100755
index 03f323a54..000000000
--- a/experimental/src/processing/mode/experimental/ImportStatement.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- Part of the XQMode project - https://github.com/Manindra29/XQMode
-
- Under Google Summer of Code 2012 -
- http://www.google-melange.com/gsoc/homepage/google/gsoc2012
-
- Copyright (C) 2012 Manindra Moharana
-
- 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.mode.experimental;
-
-/**
- * Wrapper for import statements
- *
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- */
-public class ImportStatement {
- /**
- * Ex: processing.opengl.*, java.util.*
- */
- String importName;
- /**
- * Which tab does it belong to?
- */
- int tab;
-
- /**
- * Line number(pde code) of the import
- */
- int lineNumber;
-
- /**
- *
- * @param importName - Ex: processing.opengl.*, java.util.*
- * @param tab - Which tab does it belong to?
- * @param lineNumber - Line number(pde code) of the import
- */
- public ImportStatement(String importName, int tab, int lineNumber) {
- this.importName = importName;
- this.tab = tab;
- this.lineNumber = lineNumber;
- }
-}
\ No newline at end of file
diff --git a/experimental/src/processing/mode/experimental/LineBreakpoint.java b/experimental/src/processing/mode/experimental/LineBreakpoint.java
deleted file mode 100755
index 8d006fd9d..000000000
--- a/experimental/src/processing/mode/experimental/LineBreakpoint.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.AbsentInformationException;
-import com.sun.jdi.Location;
-import com.sun.jdi.ReferenceType;
-import com.sun.jdi.request.BreakpointRequest;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Model/Controller of a line breakpoint. Can be set before or while debugging.
- * Adds a highlight using the debuggers view ({@link DebugEditor}).
- *
- * @author Martin Leopold
- */
-public class LineBreakpoint implements ClassLoadListener {
-
- protected Debugger dbg; // the debugger
- protected LineID line; // the line this breakpoint is set on
- protected BreakpointRequest bpr; // the request on the VM's event request manager
- protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded
-
- /**
- * Create a {@link LineBreakpoint}. If in a debug session, will try to
- * immediately set the breakpoint. If not in a debug session or the
- * corresponding class is not yet loaded the breakpoint will activate on
- * class load.
- *
- * @param line the line id to create the breakpoint on
- * @param dbg the {@link Debugger}
- */
- public LineBreakpoint(LineID line, Debugger dbg) {
- this.line = line;
- line.startTracking(dbg.editor().getTab(line.fileName()).getDocument());
- this.dbg = dbg;
- theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded
- set(); // activate the breakpoint (show highlight, attach if debugger is running)
- }
-
- /**
- * Create a {@link LineBreakpoint} on a line in the current tab.
- *
- * @param lineIdx the line index of the current tab to create the breakpoint
- * on
- * @param dbg the {@link Debugger}
- */
- // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)}
- public LineBreakpoint(int lineIdx, Debugger dbg) {
- this(dbg.editor().getLineIDInCurrentTab(lineIdx), dbg);
- }
-
- /**
- * Get the line id this breakpoint is on.
- *
- * @return the line id
- */
- public LineID lineID() {
- return line;
- }
-
- /**
- * Test if this breakpoint is on a certain line.
- *
- * @param testLine the line id to test
- * @return true if this breakpoint is on the given line
- */
- public boolean isOnLine(LineID testLine) {
- return line.equals(testLine);
- }
-
- /**
- * Attach this breakpoint to the VM. Creates and enables a
- * {@link BreakpointRequest}. VM needs to be paused.
- */
- protected void attach() {
- if (!dbg.isPaused()) {
- Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused");
- return;
- }
-
- if (theClass == null) {
- Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className());
- return;
- }
-
- // find line in java space
- LineID javaLine = dbg.sketchToJavaLine(line);
- if (javaLine == null) {
- Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line);
- return;
- }
- try {
- List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1);
- if (locations.isEmpty()) {
- Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine});
- return;
- }
- // use first found location
- bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0));
- bpr.enable();
- Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine});
- } catch (AbsentInformationException ex) {
- Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Detach this breakpoint from the VM. Deletes the
- * {@link BreakpointRequest}.
- */
- protected void detach() {
- if (bpr != null) {
- dbg.vm().eventRequestManager().deleteEventRequest(bpr);
- bpr = null;
- }
- }
-
- /**
- * Set this breakpoint. Adds the line highlight. If Debugger is paused also
- * attaches the breakpoint by calling {@link #attach()}.
- */
- protected void set() {
- dbg.addClassLoadListener(this); // class may not yet be loaded
- dbg.editor().addBreakpointedLine(line);
- if (theClass != null && dbg.isPaused()) { // class is loaded
- // immediately activate the breakpoint
- attach();
- }
- if (dbg.editor().isInCurrentTab(line)) {
- dbg.editor().getSketch().setModified(true);
- }
- }
-
- /**
- * Remove this breakpoint. Clears the highlight and detaches the breakpoint
- * if the debugger is paused.
- */
- public void remove() {
- dbg.removeClassLoadListener(this);
- //System.out.println("removing " + line.lineIdx());
- dbg.editor().removeBreakpointedLine(line.lineIdx());
- if (dbg.isPaused()) {
- // immediately remove the breakpoint
- detach();
- }
- line.stopTracking();
- if (dbg.editor().isInCurrentTab(line)) {
- dbg.editor().getSketch().setModified(true);
- }
- }
-
-// public void enable() {
-// }
-//
-// public void disable() {
-// }
- @Override
- public String toString() {
- return line.toString();
- }
-
- /**
- * Get the name of the class this breakpoint belongs to. Needed for fetching
- * the right location to create a breakpoint request.
- *
- * @return the class name
- */
- protected String className() {
- if (line.fileName().endsWith(".pde")) {
- // standard tab
- ReferenceType mainClass = dbg.getMainClass();
- if (mainClass == null) {
- return null;
- }
- return dbg.getMainClass().name();
- }
-
- if (line.fileName().endsWith(".java")) {
- // pure java tab
- return line.fileName().substring(0, line.fileName().lastIndexOf(".java"));
- }
-
- return null;
- }
-
- /**
- * Event handler called when a class is loaded in the debugger. Causes the
- * breakpoint to be attached, if its class was loaded.
- *
- * @param theClass the class that was just loaded.
- */
- @Override
- public void classLoaded(ReferenceType theClass) {
- // check if our class is being loaded
- if (theClass.name().equals(className())) {
- this.theClass = theClass;
- attach();
- }
- }
-}
diff --git a/experimental/src/processing/mode/experimental/LineHighlight.java b/experimental/src/processing/mode/experimental/LineHighlight.java
deleted file mode 100755
index c1789cf24..000000000
--- a/experimental/src/processing/mode/experimental/LineHighlight.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.awt.Color;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Model/Controller for a highlighted source code line. Implements a custom
- * background color and a text based marker placed in the left-hand gutter area.
- *
- * @author Martin Leopold
- */
-public class LineHighlight implements LineListener {
-
- protected DebugEditor editor; // the view, used for highlighting lines by setting a background color
- protected Color bgColor; // the background color for highlighting lines
- protected LineID lineID; // the id of the line
- protected String marker; //
- protected Color markerColor;
- protected int priority = 0;
- protected static Set allHighlights = new HashSet();
-
- protected static boolean isHighestPriority(LineHighlight hl) {
- for (LineHighlight check : allHighlights) {
- if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Create a {@link LineHighlight}.
- *
- * @param lineID the line id to highlight
- * @param bgColor the background color used for highlighting
- * @param editor the {@link DebugEditor}
- */
- public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) {
- this.lineID = lineID;
- this.bgColor = bgColor;
- this.editor = editor;
- lineID.addListener(this);
- lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc?
- paint(); // already checks if on current tab
- allHighlights.add(this);
- }
-
- public void setPriority(int p) {
- this.priority = p;
- }
-
- public int priority() {
- return priority;
- }
-
- /**
- * Create a {@link LineHighlight} on the current tab.
- *
- * @param lineIdx the line index on the current tab to highlight
- * @param bgColor the background color used for highlighting
- * @param editor the {@link DebugEditor}
- */
- // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)}
- public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) {
- this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor);
- }
-
- /**
- * Set a text based marker displayed in the left hand gutter area of this
- * highlighted line.
- *
- * @param marker the marker text
- */
- public void setMarker(String marker) {
- this.marker = marker;
- paint();
- }
-
- /**
- * Set a text based marker displayed in the left hand gutter area of this
- * highlighted line. Also use a custom text color.
- *
- * @param marker the marker text
- * @param markerColor the text color
- */
- public void setMarker(String marker, Color markerColor) {
- this.markerColor = markerColor;
- setMarker(marker);
- }
-
- /**
- * Retrieve the line id of this {@link LineHighlight}.
- *
- * @return the line id
- */
- public LineID lineID() {
- return lineID;
- }
-
- /**
- * Retrieve the color for highlighting this line.
- *
- * @return the highlight color.
- */
- public Color getColor() {
- return bgColor;
- }
-
- /**
- * Test if this highlight is on a certain line.
- *
- * @param testLine the line to test
- * @return true if this highlight is on the given line
- */
- public boolean isOnLine(LineID testLine) {
- return lineID.equals(testLine);
- }
-
- /**
- * Event handler for line number changes (due to editing). Will remove the
- * highlight from the old line number and repaint it at the new location.
- *
- * @param line the line that has changed
- * @param oldLineIdx the old line index (0-based)
- * @param newLineIdx the new line index (0-based)
- */
- @Override
- public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) {
- // clear old line
- if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) {
- editor.textArea().clearLineBgColor(oldLineIdx);
- editor.textArea().clearGutterText(oldLineIdx);
- }
-
- // paint new line
- // but only if it's on top -> fixes current line being hidden by breakpoint moving it down.
- // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...)
- if (LineHighlight.isHighestPriority(this)) {
- paint();
- }
- }
-
- /**
- * Notify this line highlight that it is no longer used. Call this for
- * cleanup before the {@link LineHighlight} is discarded.
- */
- public void dispose() {
- lineID.removeListener(this);
- lineID.stopTracking();
- allHighlights.remove(this);
- }
-
- /**
- * (Re-)paint this line highlight.
- */
- public void paint() {
- if (editor.isInCurrentTab(lineID)) {
- editor.textArea().setLineBgColor(lineID.lineIdx(), bgColor);
- if (marker != null) {
- if (markerColor != null) {
- editor.textArea().setGutterText(lineID.lineIdx(), marker, markerColor);
- } else {
- editor.textArea().setGutterText(lineID.lineIdx(), marker);
- }
- }
- }
- }
-
- /**
- * Clear this line highlight.
- */
- public void clear() {
- if (editor.isInCurrentTab(lineID)) {
- editor.textArea().clearLineBgColor(lineID.lineIdx());
- editor.textArea().clearGutterText(lineID.lineIdx());
- }
- }
-}
diff --git a/experimental/src/processing/mode/experimental/LineID.java b/experimental/src/processing/mode/experimental/LineID.java
deleted file mode 100755
index a08d21296..000000000
--- a/experimental/src/processing/mode/experimental/LineID.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.Element;
-import javax.swing.text.Position;
-
-/**
- * Describes an ID for a code line. Comprised of a file name and a (0-based)
- * line number. Can track changes to the line number due to text editing by
- * attaching a {@link Document}. Registered {@link LineListener}s are notified
- * of changes to the line number.
- *
- * @author Martin Leopold
- */
-public class LineID implements DocumentListener {
-
- protected String fileName; // the filename
- protected int lineIdx; // the line number, 0-based
- protected Document doc; // the Document to use for line number tracking
- protected Position pos; // the Position acquired during line number tracking
- protected Set listeners = new HashSet(); // listeners for line number changes
-
- public LineID(String fileName, int lineIdx) {
- this.fileName = fileName;
- this.lineIdx = lineIdx;
- }
-
- /**
- * Get the file name of this line.
- *
- * @return the file name
- */
- public String fileName() {
- return fileName;
- }
-
- /**
- * Get the (0-based) line number of this line.
- *
- * @return the line index (i.e. line number, starting at 0)
- */
- public synchronized int lineIdx() {
- return lineIdx;
- }
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
-
- /**
- * Test whether this {@link LineID} is equal to another object. Two
- * {@link LineID}'s are equal when both their fileName and lineNo are equal.
- *
- * @param obj the object to test for equality
- * @return {@code true} if equal
- */
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final LineID other = (LineID) obj;
- if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) {
- return false;
- }
- if (this.lineIdx != other.lineIdx) {
- return false;
- }
- return true;
- }
-
- /**
- * Output a string representation in the form fileName:lineIdx+1. Note this
- * uses a 1-based line number as is customary for human-readable line
- * numbers.
- *
- * @return the string representation of this line ID
- */
- @Override
- public String toString() {
- return fileName + ":" + (lineIdx + 1);
- }
-
-// /**
-// * Retrieve a copy of this line ID.
-// *
-// * @return the copy
-// */
-// @Override
-// public LineID clone() {
-// return new LineID(fileName, lineIdx);
-// }
-
- /**
- * Attach a {@link Document} to enable line number tracking when editing.
- * The position to track is before the first non-whitespace character on the
- * line. Edits happening before that position will cause the line number to
- * update accordingly. Multiple {@link #startTracking} calls will replace
- * the tracked document. Whoever wants a tracked line should track it and
- * add itself as listener if necessary.
- * ({@link LineHighlight}, {@link LineBreakpoint})
- *
- * @param doc the {@link Document} to use for line number tracking
- */
- public synchronized void startTracking(Document doc) {
- //System.out.println("tracking: " + this);
- if (doc == null) {
- return; // null arg
- }
- if (doc == this.doc) {
- return; // already tracking that doc
- }
- try {
- Element line = doc.getDefaultRootElement().getElement(lineIdx);
- if (line == null) {
- return; // line doesn't exist
- }
- String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset());
- // set tracking position at (=before) first non-white space character on line
- pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText));
- this.doc = doc;
- doc.addDocumentListener(this);
- } catch (BadLocationException ex) {
- Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex);
- pos = null;
- this.doc = null;
- }
- }
-
- /**
- * Notify this {@link LineID} that it is no longer in use. Will stop
- * position tracking. Call this when this {@link LineID} is no longer
- * needed.
- */
- public synchronized void stopTracking() {
- if (doc != null) {
- doc.removeDocumentListener(this);
- doc = null;
- }
- }
-
- /**
- * Update the tracked position. Will notify listeners if line number has
- * changed.
- */
- protected synchronized void updatePosition() {
- if (doc != null && pos != null) {
- // track position
- int offset = pos.getOffset();
- int oldLineIdx = lineIdx;
- lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo
- if (lineIdx != oldLineIdx) {
- for (LineListener l : listeners) {
- if (l != null) {
- l.lineChanged(this, oldLineIdx, lineIdx);
- } else {
- listeners.remove(l); // remove null listener
- }
- }
- }
- }
- }
-
- /**
- * Add listener to be notified when the line number changes.
- *
- * @param l the listener to add
- */
- public void addListener(LineListener l) {
- listeners.add(l);
- }
-
- /**
- * Remove a listener for line number changes.
- *
- * @param l the listener to remove
- */
- public void removeListener(LineListener l) {
- listeners.remove(l);
- }
-
- /**
- * Calculate the offset of the first non-whitespace character in a string.
- *
- * @param str the string to examine
- * @return offset of first non-whitespace character in str
- */
- protected static int nonWhiteSpaceOffset(String str) {
- for (int i = 0; i < str.length(); i++) {
- if (!Character.isWhitespace(str.charAt(i))) {
- return i;
- }
- }
- return str.length();
- }
-
- /**
- * Called when the {@link Document} registered using {@link #startTracking}
- * is edited. This happens when text is inserted or removed.
- *
- * @param de
- */
- protected void editEvent(DocumentEvent de) {
- //System.out.println("document edit @ " + de.getOffset());
- if (de.getOffset() <= pos.getOffset()) {
- updatePosition();
- //System.out.println("updating, new line no: " + lineNo);
- }
- }
-
- /**
- * {@link DocumentListener} callback. Called when text is inserted.
- *
- * @param de
- */
- @Override
- public void insertUpdate(DocumentEvent de) {
- editEvent(de);
- }
-
- /**
- * {@link DocumentListener} callback. Called when text is removed.
- *
- * @param de
- */
- @Override
- public void removeUpdate(DocumentEvent de) {
- editEvent(de);
- }
-
- /**
- * {@link DocumentListener} callback. Called when attributes are changed.
- * Not used.
- *
- * @param de
- */
- @Override
- public void changedUpdate(DocumentEvent de) {
- // not needed.
- }
-}
diff --git a/experimental/src/processing/mode/experimental/LineListener.java b/experimental/src/processing/mode/experimental/LineListener.java
deleted file mode 100755
index c6c3ae1b0..000000000
--- a/experimental/src/processing/mode/experimental/LineListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-/**
- * A Listener for line number changes.
- *
- * @author Martin Leopold
- */
-public interface LineListener {
-
- /**
- * Event handler for line number changes (due to editing).
- *
- * @param line the line that has changed
- * @param oldLineIdx the old line index (0-based)
- * @param newLineIdx the new line index (0-based)
- */
- void lineChanged(LineID line, int oldLineIdx, int newLineIdx);
-}
diff --git a/experimental/src/processing/mode/experimental/LocalVariableNode.java b/experimental/src/processing/mode/experimental/LocalVariableNode.java
deleted file mode 100755
index d1bdb2092..000000000
--- a/experimental/src/processing/mode/experimental/LocalVariableNode.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.ClassNotLoadedException;
-import com.sun.jdi.InvalidTypeException;
-import com.sun.jdi.LocalVariable;
-import com.sun.jdi.StackFrame;
-import com.sun.jdi.Value;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Specialized {@link VariableNode} for representing local variables. Overrides
- * {@link #setValue} to properly change the value of the encapsulated local
- * variable.
- *
- * @author Martin Leopold
- */
-public class LocalVariableNode extends VariableNode {
-
- protected LocalVariable var;
- protected StackFrame frame;
-
- /**
- * Construct a {@link LocalVariableNode}.
- *
- * @param name the name
- * @param type the type
- * @param value the value
- * @param var the local variable
- * @param frame the stack frame containing the local variable
- */
- public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) {
- super(name, type, value);
- this.var = var;
- this.frame = frame;
- }
-
- @Override
- public void setValue(Value value) {
- try {
- frame.setValue(var, value);
- } catch (InvalidTypeException ex) {
- Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex);
- } catch (ClassNotLoadedException ex) {
- Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex);
- }
- this.value = value;
- }
-}
diff --git a/experimental/src/processing/mode/experimental/Problem.java b/experimental/src/processing/mode/experimental/Problem.java
deleted file mode 100755
index 2d206b606..000000000
--- a/experimental/src/processing/mode/experimental/Problem.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- Part of the XQMode project - https://github.com/Manindra29/XQMode
-
- Under Google Summer of Code 2012 -
- http://www.google-melange.com/gsoc/homepage/google/gsoc2012
-
- Copyright (C) 2012 Manindra Moharana
-
- 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.mode.experimental;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.jdt.core.compiler.IProblem;
-
-/**
- * Wrapper class for IProblem.
- *
- * Stores the tabIndex and line number according to its tab, including the
- * original IProblem object
- *
- * @author Manindra Moharana <me@mkmoharana.com>
- *
- */
-public class Problem {
- /**
- * The IProblem which is being wrapped
- */
- private IProblem iProblem;
- /**
- * The tab number to which the error belongs to
- */
- public int tabIndex;
- /**
- * Line number(pde code) of the error
- */
- public int lineNumber;
-
- /**
- * Error Message. Processed form of IProblem.getMessage()
- */
- public String message;
-
- /**
- * The type of error - WARNING or ERROR.
- */
- public int type;
-
- public static final int ERROR = 1, WARNING = 2;
-
- /**
- *
- * @param iProblem - The IProblem which is being wrapped
- * @param tabIndex - The tab number to which the error belongs to
- * @param lineNumber - Line number(pde code) of the error
- */
- public Problem(IProblem iProblem, int tabIndex, int lineNumber) {
- this.iProblem = iProblem;
- if(iProblem.isError()) {
- type = ERROR;
- }
- else if(iProblem.isWarning()) {
- type = WARNING;
- }
- this.tabIndex = tabIndex;
- this.lineNumber = lineNumber;
- this.message = process(iProblem);
- }
-
- public String toString() {
- return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: "
- + message);
- }
-
- public boolean isError(){
- return type == ERROR;
- }
-
- public boolean isWarning(){
- return type == WARNING;
- }
-
- public String getMessage(){
- return message;
- }
-
- public IProblem getIProblem(){
- return iProblem;
- }
-
- public void setType(int ProblemType){
- if(ProblemType == ERROR)
- type = ERROR;
- else if(ProblemType == WARNING)
- type = WARNING;
- else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)");
- }
-
- private static Pattern pattern;
- private static Matcher matcher;
-
- private static final String tokenRegExp = "\\b token\\b";
-
- public static String process(IProblem problem) {
- return process(problem.getMessage());
- }
-
- /**
- * Processes error messages and attempts to make them a bit more english like.
- * Currently performs:
- *
Remove all instances of token. "Syntax error on token 'blah', delete this token"
- * becomes "Syntax error on 'blah', delete this"
- * @param message - The message to be processed
- * @return String - The processed message
- */
- public static String process(String message) {
- // Remove all instances of token
- // "Syntax error on token 'blah', delete this token"
-
- pattern = Pattern.compile(tokenRegExp);
- matcher = pattern.matcher(message);
- message = matcher.replaceAll("");
-
- return message;
- }
-
- // Split camel case words into separate words.
- // "VaraibleDeclaration" becomes "Variable Declaration"
- // But sadly "PApplet" become "P Applet" and so on.
- public static String splitCamelCaseWord(String word) {
- String newWord = "";
- for (int i = 1; i < word.length(); i++) {
- if (Character.isUpperCase(word.charAt(i))) {
- // System.out.println(word.substring(0, i) + " "
- // + word.substring(i));
- newWord += word.substring(0, i) + " ";
- word = word.substring(i);
- i = 1;
- }
- }
- newWord += word;
- // System.out.println(newWord);
- return newWord.trim();
- }
-
-}
diff --git a/experimental/src/processing/mode/experimental/TextArea.java b/experimental/src/processing/mode/experimental/TextArea.java
deleted file mode 100755
index 87722498a..000000000
--- a/experimental/src/processing/mode/experimental/TextArea.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.awt.Color;
-import java.awt.Cursor;
-import java.awt.FontMetrics;
-import java.awt.event.ComponentListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
-import java.util.HashMap;
-import java.util.Map;
-
-import processing.app.syntax.JEditTextArea;
-import processing.app.syntax.TextAreaDefaults;
-
-/**
- * Customized text area. Adds support for line background colors.
- *
- * @author Martin Leopold
- */
-public class TextArea extends JEditTextArea {
-
- protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler
- protected DebugEditor editor; // the editor
- // line properties
- protected Map lineColors = new HashMap(); // contains line background colors
- // left-hand gutter properties
- protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars
- protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color
- protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line
- protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter
- protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter
- protected Map gutterText = new HashMap(); // maps line index to gutter text
- protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color
- protected TextAreaPainter customPainter;
- protected ErrorCheckerService errorCheckerService;
-
- public TextArea(TextAreaDefaults defaults, DebugEditor editor) {
- super(defaults);
- this.editor = editor;
-
- // replace the painter:
- // first save listeners, these are package-private in JEditTextArea, so not accessible
- ComponentListener[] componentListeners = painter.getComponentListeners();
- mouseListeners = painter.getMouseListeners();
- MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners();
-
- remove(painter);
-
- // set new painter
- customPainter = new TextAreaPainter(this, defaults);
- painter = customPainter;
-
- // set listeners
- for (ComponentListener cl : componentListeners) {
- painter.addComponentListener(cl);
- }
-
- for (MouseMotionListener mml : mouseMotionListeners) {
- painter.addMouseMotionListener(mml);
- }
-
- // use a custom mouse handler instead of directly using mouseListeners
- MouseHandler mouseHandler = new MouseHandler();
- painter.addMouseListener(mouseHandler);
- painter.addMouseMotionListener(mouseHandler);
-
- add(CENTER, painter);
-
- // load settings from theme.txt
- ExperimentalMode theme = (ExperimentalMode) editor.getMode();
- gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor);
- gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor);
- gutterPadding = theme.getInteger("gutter.padding");
- breakpointMarker = theme.loadThemeString("breakpoint.marker", breakpointMarker);
- currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker);
- }
-
- /**
- * Sets ErrorCheckerService and loads theme for TextArea(XQMode)
- * @param ecs
- * @param mode
- */
- public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode)
- {
- errorCheckerService = ecs;
- customPainter.setECSandTheme(ecs, mode);
- }
-
- public void processKeyEvent(KeyEvent evt) {
- super.processKeyEvent(evt);
- if(evt.getID() == KeyEvent.KEY_TYPED){
- errorCheckerService.textModified.incrementAndGet();
- }
- }
-
- /**
- * Retrieve the total width of the gutter area.
- *
- * @return gutter width in pixels
- */
- protected int getGutterWidth() {
- FontMetrics fm = painter.getFontMetrics();
-// System.out.println("fm: " + (fm == null));
-// System.out.println("editor: " + (editor == null));
- //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null));
-
- int textWidth = Math.max(fm.stringWidth(breakpointMarker), fm.stringWidth(currentLineMarker));
- return textWidth + 2 * gutterPadding;
- }
-
- /**
- * Retrieve the width of margins applied to the left and right of the gutter
- * text.
- *
- * @return margins in pixels
- */
- protected int getGutterMargins() {
- return gutterPadding;
- }
-
- /**
- * Set the gutter text of a specific line.
- *
- * @param lineIdx the line index (0-based)
- * @param text the text
- */
- public void setGutterText(int lineIdx, String text) {
- gutterText.put(lineIdx, text);
- painter.invalidateLine(lineIdx);
- }
-
- /**
- * Set the gutter text and color of a specific line.
- *
- * @param lineIdx the line index (0-based)
- * @param text the text
- * @param textColor the text color
- */
- public void setGutterText(int lineIdx, String text, Color textColor) {
- gutterTextColors.put(lineIdx, textColor);
- setGutterText(lineIdx, text);
- }
-
- /**
- * Clear the gutter text of a specific line.
- *
- * @param lineIdx the line index (0-based)
- */
- public void clearGutterText(int lineIdx) {
- gutterText.remove(lineIdx);
- painter.invalidateLine(lineIdx);
- }
-
- /**
- * Clear all gutter text.
- */
- public void clearGutterText() {
- for (int lineIdx : gutterText.keySet()) {
- painter.invalidateLine(lineIdx);
- }
- gutterText.clear();
- }
-
- /**
- * Retrieve the gutter text of a specific line.
- *
- * @param lineIdx the line index (0-based)
- * @return the gutter text
- */
- public String getGutterText(int lineIdx) {
- return gutterText.get(lineIdx);
- }
-
- /**
- * Retrieve the gutter text color for a specific line.
- *
- * @param lineIdx the line index
- * @return the gutter text color
- */
- public Color getGutterTextColor(int lineIdx) {
- return gutterTextColors.get(lineIdx);
- }
-
- /**
- * Set the background color of a line.
- *
- * @param lineIdx 0-based line number
- * @param col the background color to set
- */
- public void setLineBgColor(int lineIdx, Color col) {
- lineColors.put(lineIdx, col);
- painter.invalidateLine(lineIdx);
- }
-
- /**
- * Clear the background color of a line.
- *
- * @param lineIdx 0-based line number
- */
- public void clearLineBgColor(int lineIdx) {
- lineColors.remove(lineIdx);
- painter.invalidateLine(lineIdx);
- }
-
- /**
- * Clear all line background colors.
- */
- public void clearLineBgColors() {
- for (int lineIdx : lineColors.keySet()) {
- painter.invalidateLine(lineIdx);
- }
- lineColors.clear();
- }
-
- /**
- * Get a lines background color.
- *
- * @param lineIdx 0-based line number
- * @return the color or null if no color was set for the specified line
- */
- public Color getLineBgColor(int lineIdx) {
- return lineColors.get(lineIdx);
- }
-
- /**
- * Convert a character offset to a horizontal pixel position inside the text
- * area. Overridden to take gutter width into account.
- *
- * @param line the 0-based line number
- * @param offset the character offset (0 is the first character on a line)
- * @return the horizontal position
- */
- @Override
- public int _offsetToX(int line, int offset) {
- return super._offsetToX(line, offset) + getGutterWidth();
- }
-
- /**
- * Convert a horizontal pixel position to a character offset. Overridden to
- * take gutter width into account.
- *
- * @param line the 0-based line number
- * @param x the horizontal pixel position
- * @return he character offset (0 is the first character on a line)
- */
- @Override
- public int xToOffset(int line, int x) {
- return super.xToOffset(line, x - getGutterWidth());
- }
-
- /**
- * Custom mouse handler. Implements double clicking in the gutter area to
- * toggle breakpoints, sets default cursor (instead of text cursor) in the
- * gutter area.
- */
- protected class MouseHandler implements MouseListener, MouseMotionListener {
-
- protected int lastX; // previous horizontal positon of the mouse cursor
-
- @Override
- public void mouseClicked(MouseEvent me) {
- // forward to standard listeners
- for (MouseListener ml : mouseListeners) {
- ml.mouseClicked(me);
- }
- }
-
- @Override
- public void mousePressed(MouseEvent me) {
- // check if this happened in the gutter area
- if (me.getX() < getGutterWidth()) {
- if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) {
- int line = me.getY() / painter.getFontMetrics().getHeight() + firstLine;
- if (line >= 0 && line <= getLineCount() - 1) {
- editor.gutterDblClicked(line);
- }
- }
- } else {
- // forward to standard listeners
- for (MouseListener ml : mouseListeners) {
- ml.mousePressed(me);
- }
- }
- }
-
- @Override
- public void mouseReleased(MouseEvent me) {
- // forward to standard listeners
- for (MouseListener ml : mouseListeners) {
- ml.mouseReleased(me);
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent me) {
- // forward to standard listeners
- for (MouseListener ml : mouseListeners) {
- ml.mouseEntered(me);
- }
- }
-
- @Override
- public void mouseExited(MouseEvent me) {
- // forward to standard listeners
- for (MouseListener ml : mouseListeners) {
- ml.mouseExited(me);
- }
- }
-
- @Override
- public void mouseDragged(MouseEvent me) {
- // No need to forward since the standard MouseMotionListeners are called anyway
- // nop
- }
-
- @Override
- public void mouseMoved(MouseEvent me) {
- // No need to forward since the standard MouseMotionListeners are called anyway
- if (me.getX() < getGutterWidth()) {
- if (lastX >= getGutterWidth()) {
- painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- }
- } else {
- if (lastX < getGutterWidth()) {
- painter.setCursor(new Cursor(Cursor.TEXT_CURSOR));
- }
- }
- lastX = me.getX();
- }
- }
-}
diff --git a/experimental/src/processing/mode/experimental/TextAreaPainter.java b/experimental/src/processing/mode/experimental/TextAreaPainter.java
deleted file mode 100755
index 8c93978f2..000000000
--- a/experimental/src/processing/mode/experimental/TextAreaPainter.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import java.awt.Color;
-import java.awt.Graphics;
-
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Segment;
-import javax.swing.text.Utilities;
-
-import processing.app.syntax.TextAreaDefaults;
-import processing.app.syntax.TokenMarker;
-
-/**
- * Customized line painter. Adds support for background colors, left hand gutter
- * area with background color and text.
- *
- * @author Martin Leopold
- */
-public class TextAreaPainter extends processing.app.syntax.TextAreaPainter {
-
- protected TextArea ta; // we need the subclassed textarea
- protected ErrorCheckerService errorCheckerService;
-
- /**
- * Error line underline color
- */
- public Color errorColor = new Color(0xED2630);
-
- /**
- * Warning line underline color
- */
-
- public Color warningColor = new Color(0xFFC30E);
-
- /**
- * Color of Error Marker
- */
- public Color errorMarkerColor = new Color(0xED2630);
-
- /**
- * Color of Warning Marker
- */
- public Color warningMarkerColor = new Color(0xFFC30E);
-
- public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) {
- super(textArea, defaults);
- ta = textArea;
- }
-
- private void loadTheme(ExperimentalMode mode){
- errorColor = mode.getThemeColor("editor.errorcolor", errorColor);
- warningColor = mode.getThemeColor("editor.warningcolor",
- warningColor);
- errorMarkerColor = mode.getThemeColor("editor.errormarkercolor",
- errorMarkerColor);
- warningMarkerColor = mode.getThemeColor(
- "editor.warningmarkercolor", warningMarkerColor);
- }
-
- /**
- * Paint a line. Paints the gutter (with background color and text) then the
- * line (background color and text).
- *
- * @param gfx the graphics context
- * @param tokenMarker
- * @param line 0-based line number
- * @param x horizontal position
- */
- @Override
- protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
- int line, int x) {
-
- // paint gutter
- paintGutterBg(gfx, line, x);
-
- paintLineBgColor(gfx, line, x + ta.getGutterWidth());
-
- paintGutterLine(gfx, line, x);
-
- // paint gutter symbol
- paintGutterText(gfx, line, x);
-
- paintErrorLine(gfx, line, x);
-
- super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth());
- }
-
- /**
- * Paint the gutter background (solid color).
- *
- * @param gfx the graphics context
- * @param line 0-based line number
- * @param x horizontal position
- */
- protected void paintGutterBg(Graphics gfx, int line, int x) {
- gfx.setColor(ta.gutterBgColor);
- int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
- gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight());
- }
-
- /**
- * Paint the vertical gutter separator line.
- *
- * @param gfx the graphics context
- * @param line 0-based line number
- * @param x horizontal position
- */
- protected void paintGutterLine(Graphics gfx, int line, int x) {
- int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
- gfx.setColor(ta.gutterLineColor);
- gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), y + fm.getHeight());
- }
-
- /**
- * Paint the gutter text.
- *
- * @param gfx the graphics context
- * @param line 0-based line number
- * @param x horizontal position
- */
- protected void paintGutterText(Graphics gfx, int line, int x) {
- String text = ta.getGutterText(line);
- if (text == null) {
- return;
- }
-
- gfx.setFont(getFont());
- Color textColor = ta.getGutterTextColor(line);
- if (textColor == null) {
- gfx.setColor(getForeground());
- } else {
- gfx.setColor(textColor);
- }
- int y = ta.lineToY(line) + fm.getHeight();
-
- // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right.
- //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length();
- Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y, gfx, this, 0);
- Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y, gfx, this, 0);
- Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y + 1, gfx, this, 0);
- Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y + 1, gfx, this, 0);
- }
-
- /**
- * Paint the background color of a line.
- *
- * @param gfx the graphics context
- * @param line 0-based line number
- * @param x
- */
- protected void paintLineBgColor(Graphics gfx, int line, int x) {
- int y = ta.lineToY(line);
- y += fm.getLeading() + fm.getMaxDescent();
- int height = fm.getHeight();
-
- // get the color
- Color col = ta.getLineBgColor(line);
- //System.out.print("bg line " + line + ": ");
- // no need to paint anything
- if (col == null) {
- //System.out.println("none");
- return;
- }
- // paint line background
- gfx.setColor(col);
- gfx.fillRect(0, y, getWidth(), height);
- }
-
- /**
- * Paints the underline for an error/warning line
- *
- * @param gfx
- * the graphics context
- * @param tokenMarker
- * @param line
- * 0-based line number: NOTE
- * @param x
- */
- protected void paintErrorLine(Graphics gfx, int line, int x) {
-
- if (errorCheckerService == null) {
- return;
- }
-
- if (errorCheckerService.problemsList== null) {
- return;
- }
-
- boolean notFound = true;
- boolean isWarning = false;
-
- // Check if current line contains an error. If it does, find if it's an
- // error or warning
- for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) {
- if (emarker.problem.lineNumber == line + 1) {
- notFound = false;
- if (emarker.type == ErrorMarker.Warning) {
- isWarning = true;
- }
- break;
- }
- }
-
- if (notFound) {
- return;
- }
-
- // Determine co-ordinates
- // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " +
- // horizontalAdjustment);
- int y = ta.lineToY(line);
- y += fm.getLeading() + fm.getMaxDescent();
- int height = fm.getHeight();
- int start = ta.getLineStartOffset(line);
-
- try {
- String linetext = null;
-
- try {
- linetext = ta.getDocument().getText(start,
- ta.getLineStopOffset(line) - start - 1);
- } catch (BadLocationException bl) {
- // Error in the import statements or end of code.
- // System.out.print("BL caught. " + ta.getLineCount() + " ,"
- // + line + " ,");
- // System.out.println((ta.getLineStopOffset(line) - start - 1));
- return;
- }
-
- // Take care of offsets
- int aw = fm.stringWidth(trimRight(linetext))
- + ta.getHorizontalOffset(); // apparent width. Whitespaces
- // to the left of line + text
- // width
- int rw = fm.stringWidth(linetext.trim()); // real width
- int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw;
- // Adding offsets for the gutter
- x1 += 20;
- x2 += 20;
-
- // gfx.fillRect(x1, y, rw, height);
-
- // Let the painting begin!
- gfx.setColor(errorMarkerColor);
- if (isWarning) {
- gfx.setColor(warningMarkerColor);
- }
- gfx.fillRect(1, y + 2, 3, height - 2);
-
- gfx.setColor(errorColor);
- if (isWarning) {
- gfx.setColor(warningColor);
- }
- int xx = x1;
-
- // Draw the jagged lines
- while (xx < x2) {
- gfx.drawLine(xx, y1, xx + 2, y1 + 1);
- xx += 2;
- gfx.drawLine(xx, y1 + 1, xx + 2, y1);
- xx += 2;
- }
- } catch (Exception e) {
- System.out
- .println("Looks like I messed up! XQTextAreaPainter.paintLine() : "
- + e);
- //e.printStackTrace();
- }
-
- // Won't highlight the line. Select the text instead.
- // gfx.setColor(Color.RED);
- // gfx.fillRect(2, y, 3, height);
- }
-
- /**
- * Trims out trailing whitespaces (to the right)
- *
- * @param string
- * @return - String
- */
- private String trimRight(String string) {
- String newString = "";
- for (int i = 0; i < string.length(); i++) {
- if (string.charAt(i) != ' ') {
- newString = string.substring(0, i) + string.trim();
- break;
- }
- }
- return newString;
- }
-
- /**
- * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode)
- * @param ecs
- * @param mode
- */
- public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode){
- this.errorCheckerService = ecs;
- loadTheme(mode);
- }
-}
diff --git a/experimental/src/processing/mode/experimental/VMEventListener.java b/experimental/src/processing/mode/experimental/VMEventListener.java
deleted file mode 100755
index 4cc648802..000000000
--- a/experimental/src/processing/mode/experimental/VMEventListener.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.event.EventSet;
-
-/**
- * Interface for VM callbacks.
- *
- * @author Martin Leopold
- */
-public interface VMEventListener {
-
- /**
- * Receive an event from the VM. Events are sent in batches. See
- * documentation of EventSet for more information.
- *
- * @param es Set of events
- */
- void vmEvent(EventSet es);
-}
diff --git a/experimental/src/processing/mode/experimental/VMEventReader.java b/experimental/src/processing/mode/experimental/VMEventReader.java
deleted file mode 100755
index c4d05ddf9..000000000
--- a/experimental/src/processing/mode/experimental/VMEventReader.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.VMDisconnectedException;
-import com.sun.jdi.event.EventQueue;
-import com.sun.jdi.event.EventSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Reader Thread for VM Events. Constantly monitors a VMs EventQueue for new
- * events and forwards them to an VMEventListener.
- *
- * @author Martin Leopold
- */
-public class VMEventReader extends Thread {
-
- EventQueue eventQueue;
- VMEventListener listener;
-
- /**
- * Construct a VMEventReader. Needs to be kicked off with start() once
- * constructed.
- *
- * @param eventQueue The queue to read events from. Can be obtained from a
- * VirtualMachine via eventQueue().
- * @param listener the listener to forward events to.
- */
- public VMEventReader(EventQueue eventQueue, VMEventListener listener) {
- super("VM Event Thread");
- this.eventQueue = eventQueue;
- this.listener = listener;
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- EventSet eventSet = eventQueue.remove();
- listener.vmEvent(eventSet);
- /*
- * for (Event e : eventSet) { System.out.println("VM Event: " +
- * e.toString()); }
- */
- }
- } catch (VMDisconnectedException e) {
- Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect");
- } catch (Exception e) {
- Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e);
- }
- }
-}
diff --git a/experimental/src/processing/mode/experimental/VariableInspector.java b/experimental/src/processing/mode/experimental/VariableInspector.java
deleted file mode 100755
index a38c19a8f..000000000
--- a/experimental/src/processing/mode/experimental/VariableInspector.java
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * Copyright (C) 2012 Martin Leopold
- *
- * 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 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.mode.experimental;
-
-import com.sun.jdi.Value;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.swing.DefaultCellEditor;
-import javax.swing.GrayFilter;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.UIDefaults;
-import javax.swing.UIManager;
-import javax.swing.event.TreeExpansionEvent;
-import javax.swing.event.TreeExpansionListener;
-import javax.swing.table.TableColumn;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.ExpandVetoException;
-import javax.swing.tree.MutableTreeNode;
-import javax.swing.tree.TreeNode;
-import javax.swing.tree.TreePath;
-import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
-import org.netbeans.swing.outline.DefaultOutlineModel;
-import org.netbeans.swing.outline.ExtTreeWillExpandListener;
-import org.netbeans.swing.outline.OutlineModel;
-import org.netbeans.swing.outline.RenderDataProvider;
-import org.netbeans.swing.outline.RowModel;
-
-/**
- * Variable Inspector window.
- *
- * @author Martin Leopold
- */
-public class VariableInspector extends javax.swing.JFrame {
-
- protected DefaultMutableTreeNode rootNode; // the root node (invisible)
- protected DefaultMutableTreeNode builtins; // node for Processing built-in variables
- protected DefaultTreeModel treeModel; // data model for the tree column
- protected OutlineModel model; // data model for the whole Outline (tree and other columns)
- protected List callStack; // the call stack
- protected List locals; // current local variables
- protected List thisFields; // all fields of the current this-object
- protected List declaredThisFields; // declared i.e. non-inherited fields of this
- protected DebugEditor editor; // the editor
- protected Debugger dbg; // the debugger
- protected List expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion)
- protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used
-
- /**
- * Creates new form VariableInspector
- */
- public VariableInspector(DebugEditor editor) {
- this.editor = editor;
- this.dbg = editor.dbg();
-
- initComponents();
-
- // setup Outline
- rootNode = new DefaultMutableTreeNode("root");
- builtins = new DefaultMutableTreeNode("Processing");
- treeModel = new DefaultTreeModel(rootNode); // model for the tree column
- model = DefaultOutlineModel.createOutlineModel(treeModel, new VariableRowModel(), true, "Name"); // model for all columns
-
- ExpansionHandler expansionHandler = new ExpansionHandler();
- model.getTreePathSupport().addTreeWillExpandListener(expansionHandler);
- model.getTreePathSupport().addTreeExpansionListener(expansionHandler);
- tree.setModel(model);
- tree.setRootVisible(false);
- tree.setRenderDataProvider(new OutlineRenderer());
- tree.setColumnHidingAllowed(false); // disable visible columns button (shows by default when right scroll bar is visible)
- tree.setAutoscrolls(false);
-
- // set custom renderer and editor for value column, since we are using a custom class for values (VariableNode)
- TableColumn valueColumn = tree.getColumnModel().getColumn(1);
- valueColumn.setCellRenderer(new ValueCellRenderer());
- valueColumn.setCellEditor(new ValueCellEditor());
-
- //System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass());
- //System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass());
-
- callStack = new ArrayList();
- locals = new ArrayList();
- thisFields = new ArrayList();
- declaredThisFields = new ArrayList();
-
- this.setTitle(editor.getSketch().getName());
-
-// for (Entry