diff --git a/app/Base.java b/app/Base.java index 48693fe93..b97e87062 100644 --- a/app/Base.java +++ b/app/Base.java @@ -43,15 +43,15 @@ import processing.core.*; /** - * The base class for the main processing application + * The base class for the main processing application. *
* Primary role of this class is for platform identification and * general interaction with the system (launching URLs, loading * files and images, etc) that comes from that. */ public class Base { - static final int VERSION = 86; - static final String VERSION_NAME = "0086 Beta"; + static final int VERSION = 87; + static final String VERSION_NAME = "0087 Beta"; /** * Path of filename opened on the command line, diff --git a/app/MessageConsumer.java b/app/MessageConsumer.java index 7485999b7..fc0e0a3a8 100644 --- a/app/MessageConsumer.java +++ b/app/MessageConsumer.java @@ -25,7 +25,7 @@ package processing.app; /** - * Interface for dealing with parser/compiler output + * Interface for dealing with parser/compiler output. *
* Different instances of MessageStream need to do different things with * messages. In particular, a stream instance used for parsing output from diff --git a/core/PGraphics3.java b/core/PGraphics3.java index ce2016618..d0672d3a0 100644 --- a/core/PGraphics3.java +++ b/core/PGraphics3.java @@ -2798,6 +2798,40 @@ public class PGraphics3 extends PGraphics { * Note that the camera matrix is *not* the perspective matrix, * it is in front of the modelview matrix (hence the name "model" * and "view" for that matrix). + *
+ * beginCamera() specifies that all coordinate transforms until endCamera() + * should be pre-applied in inverse to the camera transform matrix. + * Note that this is only challenging when a user specifies an arbitrary + * matrix with applyMatrix(). Then that matrix will need to be inverted, + * which may not be possible. But take heart, if a user is applying a + * non-invertible matrix to the camera transform, then he is clearly + * up to no good, and we can wash our hands of those bad intentions. + *
+ * begin/endCamera clauses do not automatically reset the camera transform + * matrix. That's because we set up a nice default camera transform int + * setup(), and we expect it to hold through draw(). So we don't reset + * the camera transform matrix at the top of draw(). That means that an + * innocuous-looking clause like + *
+ * beginCamera(); + * translate(0, 0, 10); + * endCamera(); + *+ * at the top of draw(), will result in a runaway camera that shoots + * infinitely out of the screen over time. In order to prevent this, + * it is necessary to call some function that does a hard reset of the + * camera transform matrix inside of begin/endCamera. Two options are + *
+ * camera(); // sets up the nice default camera transform + * resetMatrix(); // sets up the identity camera transform + *+ * So to rotate a camera a constant amount, you might try + *
+ * beginCamera(); + * camera(); + * rotateY(PI/8); + * endCamera(); + **/ public void beginCamera() { if (manipulatingCamera) { @@ -2838,37 +2872,6 @@ public class PGraphics3 extends PGraphics { } - /** - * Calls ortho() for Processing's standard orthographic projection. - */ - public void ortho() { - ortho(0, width, 0, height, -10, 10); - } - - - /** - * Similar to gluOrtho(), but wipes out the current projection matrix. - *
- * Implementation partially based on Mesa's matrix.c. - */ - public void ortho(float left, float right, - float bottom, float top, - float near, float far) { - float x = 2.0f / (right - left); - float y = 2.0f / (top - bottom); - float z = -2.0f / (far - near); - - float tx = -(right + left) / (right - left); - float ty = -(top + bottom) / (top - bottom); - float tz = -(far + near) / (far - near); - - projection.set(x, 0, 0, tx, - 0, y, 0, ty, - 0, 0, z, tz, - 0, 0, 0, 1); - } - - /** * Calls camera() with Processing's standard camera setup. */ @@ -2880,53 +2883,57 @@ public class PGraphics3 extends PGraphics { /** - * Calls perspective() with Processing's standard coordinate setup. - */ - public void perspective() { - perspective(cameraFOV, cameraAspect, cameraNear, cameraFar); - } - - - /** - * Same as gluPerspective(). Implementation based on Mesa's glu.c - */ - public void perspective(float fov, float aspect, float zNear, float zFar) { - //float ymax = zNear * tan(fovy * PI / 360.0f); - float ymax = zNear * tan(fov / 2.0f); - float ymin = -ymax; - - float xmin = ymin * aspect; - float xmax = ymax * aspect; - - frustum(xmin, xmax, ymin, ymax, zNear, zFar); - } - - - /** - * Same as glFrustum(), except that it wipes out (rather than - * multiplies against) the current perspective matrix. + * Set camera to the default settings. *
- * Implementation based on the explanation in the OpenGL blue book. - */ - public void frustum(float left, float right, float bottom, - float top, float znear, float zfar) { - //System.out.println(projection); - projection.set((2*znear)/(right-left), 0, (right+left)/(right-left), 0, - 0, (2*znear)/(top-bottom), (top+bottom)/(top-bottom), 0, - 0, 0, -(zfar+znear)/(zfar-znear),-(2*zfar*znear)/(zfar-znear), - 0, 0, -1, 0); - } - - - /** - * Same as gluLookat(). + * Processing camera behavior: *
- * This should only be called inside of a beginCamera/endCamera pair. + * Camera behavior can be split into two separate components, camera + * transformation, and projection. The transformation corresponds to the + * physical location, orientation, and scale of the camera. In a physical + * camera metaphor, this is what can manipulated by handling the camera + * body (with the exception of scale, which doesn't really have a physcial + * analog). The projection corresponds to what can be changed by + * manipulating the lens. *
- * Implementation based on Mesa's glu.c + * We maintain separate matrices to represent the camera transform and + * projection. An important distinction between the two is that the camera + * transform should be invertible, where the projection matrix should not, + * since it serves to map three dimensions to two. It is possible to bake + * the two matrices into a single one just by multiplying them together, + * but it isn't a good idea, since lighting, z-ordering, and z-buffering + * all demand a true camera z coordinate after modelview and camera + * transforms have been applied but before projection. If the camera + * transform and projection are combined there is no way to recover a + * good camera-space z-coordinate from a model coordinate. + *
+ * Fortunately, there are no functions that manipulate both camera + * transformation and projection. + *
+ * camera() sets the camera position, orientation, and center of the scene. + * It replaces the camera transform with a new one. This is different from + * gluLookAt(), but I think the only reason that GLU's lookat doesn't fully + * replace the camera matrix with the new one, but instead multiplies it, + * is that GL doesn't enforce the separation of camera transform and + * projection, so it wouldn't be safe (you'd probably stomp your projection). + *
+ * The transformation functions are the same ones used to manipulate the + * modelview matrix (scale, translate, rotate, etc.). But they are bracketed + * with beginCamera(), endCamera() to indicate that they should apply + * (in inverse), to the camera transformation matrix. + *
+ * This differs considerably from camera transformation in OpenGL. + * OpenGL only lets you say, apply everything from here out to the + * projection or modelview matrix. This makes it very hard to treat camera + * manipulation as if it were a physical camera. Imagine that you want to + * move your camera 100 units forward. In OpenGL, you need to apply the + * inverse of that transformation or else you'll move your scene 100 units + * forward--whether or not you've specified modelview or projection matrix. + * Remember they're just multiplied by model coods one after another. + * So in order to treat a camera like a physical camera, it is necessary + * to pre-apply inverse transforms to a matrix that will be applied to model + * coordinates. OpenGL provides nothing of this sort, but Processing does! + * This is the camera transform matrix. */ - // TODO: deal with this. Lookat must ALWAYS apply to the modelview - // regardless of the camera manipulation mode. public void camera(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { @@ -2995,6 +3002,93 @@ public class PGraphics3 extends PGraphics { } + /** + * Calls ortho() with the proper parameters for Processing's + * standard orthographic projection. + */ + public void ortho() { + ortho(0, width, 0, height, -10, 10); + } + + + /** + * Similar to gluOrtho(), but wipes out the current projection matrix. + *
+ * Implementation partially based on Mesa's matrix.c. + */ + public void ortho(float left, float right, + float bottom, float top, + float near, float far) { + float x = 2.0f / (right - left); + float y = 2.0f / (top - bottom); + float z = -2.0f / (far - near); + + float tx = -(right + left) / (right - left); + float ty = -(top + bottom) / (top - bottom); + float tz = -(far + near) / (far - near); + + projection.set(x, 0, 0, tx, + 0, y, 0, ty, + 0, 0, z, tz, + 0, 0, 0, 1); + } + + + /** + * Calls perspective() with Processing's standard coordinate projection. + *
+ * Projection functions: + *
+ * This behavior is pretty much familiar from OpenGL. + *
+ */ + public void perspective() { + perspective(cameraFOV, cameraAspect, cameraNear, cameraFar); + } + + + /** + * Similar to gluPerspective(). Implementation based on Mesa's glu.c + */ + public void perspective(float fov, float aspect, float zNear, float zFar) { + //float ymax = zNear * tan(fovy * PI / 360.0f); + float ymax = zNear * tan(fov / 2.0f); + float ymin = -ymax; + + float xmin = ymin * aspect; + float xmax = ymax * aspect; + + frustum(xmin, xmax, ymin, ymax, zNear, zFar); + } + + + /** + * Same as glFrustum(), except that it wipes out (rather than + * multiplies against) the current perspective matrix. + *
+ * Implementation based on the explanation in the OpenGL blue book. + */ + public void frustum(float left, float right, float bottom, + float top, float znear, float zfar) { + //System.out.println(projection); + projection.set((2*znear)/(right-left), 0, (right+left)/(right-left), 0, + 0, (2*znear)/(top-bottom), (top+bottom)/(top-bottom), 0, + 0, 0, -(zfar+znear)/(zfar-znear),-(2*zfar*znear)/(zfar-znear), + 0, 0, -1, 0); + } + + /** * Print the current projection matrix. */