Skip to content

Commit 450c669

Browse files
author
Jonathan Feinberg
committed
All unit tests pass.
1 parent 7871d36 commit 450c669

File tree

3 files changed

+78
-6
lines changed

3 files changed

+78
-6
lines changed

runtime/src/jycessing/PAppletJythonDriver.java

+35
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public PAppletJythonDriver(final InteractiveConsole interp, final String sketchP
114114
this.builtins = (PyStringMap)interp.getSystemState().getBuiltins();
115115
this.interp = interp;
116116
initializeStatics(builtins);
117+
setMap();
117118
setSet();
118119
builtins.__setitem__("g", Py.java2py(g));
119120
builtins.__setitem__("exit", new PyObject() {
@@ -380,6 +381,40 @@ public PyObject __call__(final PyObject[] args, final String[] kws) {
380381
});
381382
}
382383

384+
/**
385+
* Permit the punning use of set() by mucking with the builtin "set" Type.
386+
* If you call it with 3 arguments, it acts like the Processing set(x, y,
387+
* whatever) method. If you call it with 0 or 1 args, it constructs a Python
388+
* set.
389+
*/
390+
private void setMap() {
391+
final PyObject builtinMap = builtins.__getitem__("map");
392+
builtins.__setitem__("map", new PyObject() {
393+
394+
@Override
395+
public PyObject __call__(final PyObject[] args, final String[] kws) {
396+
switch (args.length) {
397+
default:
398+
return builtinMap.__call__(args, kws);
399+
case 5: {
400+
final PyObject value = args[0];
401+
final PyObject start1 = args[1];
402+
final PyObject stop1 = args[2];
403+
final PyObject start2 = args[3];
404+
final PyObject stop2 = args[4];
405+
if (value.isNumberType() && start1.isNumberType() && stop1.isNumberType()
406+
&& start2.isNumberType() && stop2.isNumberType()) {
407+
return Py.newFloat(map((float)value.asDouble(), (float)start1.asDouble(),
408+
(float)stop1.asDouble(), (float)start2.asDouble(), (float)stop2.asDouble()));
409+
} else {
410+
return builtinMap.__call__(args, kws);
411+
}
412+
}
413+
}
414+
}
415+
});
416+
}
417+
383418
/**
384419
* Populate the Python builtins namespace with PConstants.
385420
*/

runtime/src/jycessing/Runner.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,24 @@ public static void runSketch(final String[] args, final String sketchPath,
382382
interp.set("__file__", sketchPath);
383383

384384
interp.exec(read(LaunchHelper.class.getResourceAsStream("launcher.py")));
385+
386+
/*
387+
* Here's what core.py does:
388+
* Bring all of the core Processing classes into the python builtins namespace,
389+
* so they'll be available, without qualification, from all modules.
390+
* Construct a PAppletJythonDriver (which is a PApplet), then expose all of its
391+
* bound methods (such as loadImage(), noSmooth(), noise(), etc.) in the builtins
392+
* namespace.
393+
*
394+
* We provide the Jython interpreter and sketch source code to the environment
395+
* so that core.py can construct the PAppletJythonDriver with all the stuff it
396+
* needs.
397+
*/
385398
interp.set("__interp__", interp);
386399
interp.set("__path__", sketchPath);
387400
interp.set("__source__", sketchSource);
388401
interp.exec(read(Runner.class.getResourceAsStream("core.py")));
389402

390-
// Bind the sketch to a PApplet
391403
final PAppletJythonDriver applet =
392404
(PAppletJythonDriver)interp.get("__papplet__").__tojava__(PAppletJythonDriver.class);
393405
applet.findSketchMethods();
@@ -399,9 +411,11 @@ public static void runSketch(final String[] args, final String sketchPath,
399411
}
400412

401413
try {
414+
log("Running " + args[0]);
402415
PApplet.runSketch(args, applet);
403416
applet.await();
404-
log("Applet is finished. Disposing window.");
417+
log("Applet terminated.");
418+
log("Disposing window.");
405419
((Window)SwingUtilities.getRoot(applet)).dispose();
406420
} catch (final Throwable t) {
407421
Py.printException(t);

runtime/src/jycessing/core.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
# We expose many Processing-related names as builtins, so that no imports
2+
# are necessary, even in auxilliary modules.
13
import __builtin__
24

5+
# PAppletJythonDriver is a PApplet that knows how to interpret a Python
6+
# Processing sketch, and which delegates Processing callbacks (such as
7+
# setup(), draw(), keyPressed(), etc.) to the appropriate Python code.
38
from jycessing import PAppletJythonDriver
49

10+
# Bring all of the core Processing classes by name into the builtin namespace.
511
from processing.core import PApplet
612
from processing.core import PConstants
713
from processing.core import PFont
@@ -33,6 +39,8 @@
3339
__builtin__.PApplet = PShapeSVG
3440
__builtin__.PApplet = PStyle
3541

42+
# PVector requires special handling, because it exposes the same method names
43+
# as static methods and instance methods.
3644
class PVector(object):
3745
@classmethod
3846
def __new__(cls, *args):
@@ -92,11 +100,20 @@ def __mul__(a, b):
92100
raise TypeError("The * operator can only be used to multiply a PVector by a scalar")
93101
return PVector(a.x * b, a.y * b, a.z * b)
94102

103+
# Now expose the funky PVector class as a builtin.
95104
__builtin__.PVector = PVector
96105

106+
# Construct the PApplet.
97107
__papplet__ = PAppletJythonDriver(__interp__, __path__, __source__)
108+
# Make it available to sketches by the name "this", to better match existing
109+
# Java-based documentation for third-party libraries, and such.
98110
__builtin__.this = __papplet__
99111

112+
113+
# Expose all of the builtin Processing methods. Credit is due to
114+
# https://github.com/kazimuth/python-mode-processing for the
115+
# technique of exploiting Jython's bound methods, which is tidy
116+
# and simple.
100117
__builtin__.alpha = __papplet__.alpha
101118
__builtin__.ambient = __papplet__.ambient
102119
__builtin__.ambientLight = __papplet__.ambientLight
@@ -138,6 +155,7 @@ def __mul__(a, b):
138155
__builtin__.curveTangent = __papplet__.curveTangent
139156
__builtin__.curveTightness = __papplet__.curveTightness
140157
__builtin__.curveVertex = __papplet__.curveVertex
158+
__builtin__.delay = __papplet__.delay
141159
__builtin__.directionalLight = __papplet__.directionalLight
142160
__builtin__.ellipse = __papplet__.ellipse
143161
__builtin__.ellipseMode = __papplet__.ellipseMode
@@ -147,9 +165,12 @@ def __mul__(a, b):
147165
__builtin__.endRaw = __papplet__.endRaw
148166
__builtin__.endRecord = __papplet__.endRecord
149167
__builtin__.endShape = __papplet__.endShape
150-
__builtin__.exit = __papplet__.exit
168+
# We provide a special exit() method.
169+
#__builtin__.exit = __papplet__.exit
151170
__builtin__.fill = __papplet__.fill
152-
__builtin__.filter = __papplet__.filter
171+
172+
# TODO: fix filter() !
173+
#__builtin__.filter = __papplet__.filter
153174
__builtin__.frameRate = __papplet__.frameRate
154175
__builtin__.frustum = __papplet__.frustum
155176
__builtin__.get = __papplet__.get
@@ -266,6 +287,8 @@ def __mul__(a, b):
266287
__builtin__.updatePixels = __papplet__.updatePixels
267288
__builtin__.vertex = __papplet__.vertex
268289

290+
# And these are PApplet static methods. Some are commented out to indicate
291+
# that we prefer or require Jython's implementation.
269292
__builtin__.abs = PApplet.abs
270293
__builtin__.acos = PApplet.acos
271294
__builtin__.append = PApplet.append
@@ -300,7 +323,7 @@ def __mul__(a, b):
300323
__builtin__.loadStrings = PApplet.loadStrings
301324
__builtin__.log = PApplet.log
302325
__builtin__.mag = PApplet.mag
303-
__builtin__.map = PApplet.map
326+
#__builtin__.map = PApplet.map
304327
__builtin__.match = PApplet.match
305328
__builtin__.matchAll = PApplet.matchAll
306329
#__builtin__.max = PApplet.max
@@ -317,7 +340,7 @@ def __mul__(a, b):
317340
__builtin__.println = PApplet.println
318341
__builtin__.radians = PApplet.radians
319342
__builtin__.reverse = PApplet.reverse
320-
__builtin__.round = PApplet.round
343+
#__builtin__.round = PApplet.round
321344
__builtin__.saveBytes = PApplet.saveBytes
322345
__builtin__.saveStream = PApplet.saveStream
323346
__builtin__.saveStrings = PApplet.saveStrings

0 commit comments

Comments
 (0)