Skip to content
Browse files

All unit tests pass.

  • Loading branch information...
1 parent 7871d36 commit 450c6690f2209b1a22ac7274a3bf8e4d98ef3bcb @jdf committed Dec 23, 2013
Showing with 78 additions and 6 deletions.
  1. +35 −0 runtime/src/jycessing/PAppletJythonDriver.java
  2. +16 −2 runtime/src/jycessing/Runner.java
  3. +27 −4 runtime/src/jycessing/core.py
View
35 runtime/src/jycessing/PAppletJythonDriver.java
@@ -114,6 +114,7 @@ public PAppletJythonDriver(final InteractiveConsole interp, final String sketchP
this.builtins = (PyStringMap)interp.getSystemState().getBuiltins();
this.interp = interp;
initializeStatics(builtins);
+ setMap();
setSet();
builtins.__setitem__("g", Py.java2py(g));
builtins.__setitem__("exit", new PyObject() {
@@ -381,6 +382,40 @@ public PyObject __call__(final PyObject[] args, final String[] kws) {
}
/**
+ * Permit the punning use of set() by mucking with the builtin "set" Type.
+ * If you call it with 3 arguments, it acts like the Processing set(x, y,
+ * whatever) method. If you call it with 0 or 1 args, it constructs a Python
+ * set.
+ */
+ private void setMap() {
+ final PyObject builtinMap = builtins.__getitem__("map");
+ builtins.__setitem__("map", new PyObject() {
+
+ @Override
+ public PyObject __call__(final PyObject[] args, final String[] kws) {
+ switch (args.length) {
+ default:
+ return builtinMap.__call__(args, kws);
+ case 5: {
+ final PyObject value = args[0];
+ final PyObject start1 = args[1];
+ final PyObject stop1 = args[2];
+ final PyObject start2 = args[3];
+ final PyObject stop2 = args[4];
+ if (value.isNumberType() && start1.isNumberType() && stop1.isNumberType()
+ && start2.isNumberType() && stop2.isNumberType()) {
+ return Py.newFloat(map((float)value.asDouble(), (float)start1.asDouble(),
+ (float)stop1.asDouble(), (float)start2.asDouble(), (float)stop2.asDouble()));
+ } else {
+ return builtinMap.__call__(args, kws);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
* Populate the Python builtins namespace with PConstants.
*/
public static void initializeStatics(final PyStringMap builtins) {
View
18 runtime/src/jycessing/Runner.java
@@ -382,12 +382,24 @@ public static void runSketch(final String[] args, final String sketchPath,
interp.set("__file__", sketchPath);
interp.exec(read(LaunchHelper.class.getResourceAsStream("launcher.py")));
+
+ /*
+ * Here's what core.py does:
+ * Bring all of the core Processing classes into the python builtins namespace,
+ * so they'll be available, without qualification, from all modules.
+ * Construct a PAppletJythonDriver (which is a PApplet), then expose all of its
+ * bound methods (such as loadImage(), noSmooth(), noise(), etc.) in the builtins
+ * namespace.
+ *
+ * We provide the Jython interpreter and sketch source code to the environment
+ * so that core.py can construct the PAppletJythonDriver with all the stuff it
+ * needs.
+ */
interp.set("__interp__", interp);
interp.set("__path__", sketchPath);
interp.set("__source__", sketchSource);
interp.exec(read(Runner.class.getResourceAsStream("core.py")));
- // Bind the sketch to a PApplet
final PAppletJythonDriver applet =
(PAppletJythonDriver)interp.get("__papplet__").__tojava__(PAppletJythonDriver.class);
applet.findSketchMethods();
@@ -399,9 +411,11 @@ public static void runSketch(final String[] args, final String sketchPath,
}
try {
+ log("Running " + args[0]);
PApplet.runSketch(args, applet);
applet.await();
- log("Applet is finished. Disposing window.");
+ log("Applet terminated.");
+ log("Disposing window.");
((Window)SwingUtilities.getRoot(applet)).dispose();
} catch (final Throwable t) {
Py.printException(t);
View
31 runtime/src/jycessing/core.py
@@ -1,7 +1,13 @@
+# We expose many Processing-related names as builtins, so that no imports
+# are necessary, even in auxilliary modules.
import __builtin__
+# PAppletJythonDriver is a PApplet that knows how to interpret a Python
+# Processing sketch, and which delegates Processing callbacks (such as
+# setup(), draw(), keyPressed(), etc.) to the appropriate Python code.
from jycessing import PAppletJythonDriver
+# Bring all of the core Processing classes by name into the builtin namespace.
from processing.core import PApplet
from processing.core import PConstants
from processing.core import PFont
@@ -33,6 +39,8 @@
__builtin__.PApplet = PShapeSVG
__builtin__.PApplet = PStyle
+# PVector requires special handling, because it exposes the same method names
+# as static methods and instance methods.
class PVector(object):
@classmethod
def __new__(cls, *args):
@@ -92,11 +100,20 @@ def __mul__(a, b):
raise TypeError("The * operator can only be used to multiply a PVector by a scalar")
return PVector(a.x * b, a.y * b, a.z * b)
+# Now expose the funky PVector class as a builtin.
__builtin__.PVector = PVector
+# Construct the PApplet.
__papplet__ = PAppletJythonDriver(__interp__, __path__, __source__)
+# Make it available to sketches by the name "this", to better match existing
+# Java-based documentation for third-party libraries, and such.
__builtin__.this = __papplet__
+
+# Expose all of the builtin Processing methods. Credit is due to
+# https://github.com/kazimuth/python-mode-processing for the
+# technique of exploiting Jython's bound methods, which is tidy
+# and simple.
__builtin__.alpha = __papplet__.alpha
__builtin__.ambient = __papplet__.ambient
__builtin__.ambientLight = __papplet__.ambientLight
@@ -138,6 +155,7 @@ def __mul__(a, b):
__builtin__.curveTangent = __papplet__.curveTangent
__builtin__.curveTightness = __papplet__.curveTightness
__builtin__.curveVertex = __papplet__.curveVertex
+__builtin__.delay = __papplet__.delay
__builtin__.directionalLight = __papplet__.directionalLight
__builtin__.ellipse = __papplet__.ellipse
__builtin__.ellipseMode = __papplet__.ellipseMode
@@ -147,9 +165,12 @@ def __mul__(a, b):
__builtin__.endRaw = __papplet__.endRaw
__builtin__.endRecord = __papplet__.endRecord
__builtin__.endShape = __papplet__.endShape
-__builtin__.exit = __papplet__.exit
+# We provide a special exit() method.
+#__builtin__.exit = __papplet__.exit
__builtin__.fill = __papplet__.fill
-__builtin__.filter = __papplet__.filter
+
+# TODO: fix filter() !
+#__builtin__.filter = __papplet__.filter
__builtin__.frameRate = __papplet__.frameRate
__builtin__.frustum = __papplet__.frustum
__builtin__.get = __papplet__.get
@@ -266,6 +287,8 @@ def __mul__(a, b):
__builtin__.updatePixels = __papplet__.updatePixels
__builtin__.vertex = __papplet__.vertex
+# And these are PApplet static methods. Some are commented out to indicate
+# that we prefer or require Jython's implementation.
__builtin__.abs = PApplet.abs
__builtin__.acos = PApplet.acos
__builtin__.append = PApplet.append
@@ -300,7 +323,7 @@ def __mul__(a, b):
__builtin__.loadStrings = PApplet.loadStrings
__builtin__.log = PApplet.log
__builtin__.mag = PApplet.mag
-__builtin__.map = PApplet.map
+#__builtin__.map = PApplet.map
__builtin__.match = PApplet.match
__builtin__.matchAll = PApplet.matchAll
#__builtin__.max = PApplet.max
@@ -317,7 +340,7 @@ def __mul__(a, b):
__builtin__.println = PApplet.println
__builtin__.radians = PApplet.radians
__builtin__.reverse = PApplet.reverse
-__builtin__.round = PApplet.round
+#__builtin__.round = PApplet.round
__builtin__.saveBytes = PApplet.saveBytes
__builtin__.saveStream = PApplet.saveStream
__builtin__.saveStrings = PApplet.saveStrings

0 comments on commit 450c669

Please sign in to comment.
Something went wrong with that request. Please try again.