Currently there is no way to clip vobs independent of the GraphicsAPI used. In OpenGL, clipping is handled through the gzz.gfx.gl.Stencil class, which uses OpenGL state: Being passed a Runnable object, the class sets up OpenGL state so that a given area is clipped, calls the Runnable which places vobs into the vobscene that are rendered with the given clip, then removes the clipping state and returns. In AWT, clipping is currently unhandled.
Add the following methods to VobScene:
/** Intersect the clipping area with the given cs's "unit square". * This changes the current clipping area to the intersection * of the old clipping area with the "unit square" of the given * coordinate system, and pushes the old clipping area onto * a stack of clipping areas. * All vobs placed into this VobScene will be rendered * with the new clipping area, until ``unclip()`` is called, * restoring the old area. * <p> * The clipping area is the area where graphics are drawn. * Note that the stack of clipping areas is a way to * specify the semantics of this method, and is not required * to be implemented through a stack data structure. */ void clip(int cs); /** Pop the topmost clipping area off the stack. * The last pushed clipping area is popped off the stack and * made current. * @throws IndexOutOfBoundsException if the stack is empty. */ void unclip();
Non-rectangular clips need to be handled in a GraphicsAPI-specific manner, because our least common denominator is rectangluarly shaped clipping. (Of course, rectangularity is defined by the coordinate system: if the coordinate system is not orthogonal, the clipped area may not be a rectangle.) The unclip() method is needed so that several clips can be applied hierarchically without difficulty.
In OpenGL, these methods can be implemented using OpenGL state, as in the Stencil class. (The two methods here are less powerful than what the Stencil class provides, because they are least-common-denominator. OpenGL specific methods can provide more powerful clipping functionality, should it be needed.)
In AWT, these methods can be implement using java.awt.Graphics state combined with a stack of java.awt.Shape objects representing the different clipping areas (java.util.ArrayList contains convenience methods for being used as a stack).
How are the new VobScene methods implemented? Will there be GraphicsAPI-specific subclasses, or will the calls be passed to VobCoorder, which has GraphicsAPI-dependent implementations currently?
RESOLVED: They will be directed to VobCoorder, since this results in less changes to the architecture. There will be clipRect() and unclip() methods with the same signature in VobCoorder.
VobCoorder doesn't know which VobScene it is in, or which VobMap it's using. This makes it impossible to implement this functionality for OpenGL changing only GLVobCoorder, since the OpenGL state is altered by placing a new Vob in the VobMap.
RESOLVED: The VobCoorder methods will be passed the VobMap. (This is slightly ugly, but having API-specific VobScenes seems uglier.)
How deep a stack is allowed / required? This makes a lot of difference for the OpenGL implementation which has native stacks of fixed depth.
RESOLVED: Ultimately, stacks should be arbitrarily deep, with GL switching to a different implementation method when the native stack depth is exceeded. For now, it's acceptable to throw an exception if the native stack depth is exceeded. If we run into real-life problems with this, that'll be a good time to switch to a more advanced system.
Should clipping with this method work with nonlinear coordinate systems? This is a very fundamental issue for OpenGL, since if the answer is no, we can use clip planes and get rid of much unwanted geometry, getting better performance; otherwise, we need to use stencil and draw everything.
RESOLVED: This method should work with nonlinear coordinate systems. This ensures that we can use nonlinear coordinate systems for all things we draw in OpenGL. For example, we can put a window into a fisheye view without getting problems with clipping used on that window.
This method should be safe to use as the general case; it is optimizations that should be the special case, used if necessary.