diff options
Diffstat (limited to 'engine/src/core/com/jme3/renderer/queue/RenderQueue.java')
-rw-r--r-- | engine/src/core/com/jme3/renderer/queue/RenderQueue.java | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/renderer/queue/RenderQueue.java b/engine/src/core/com/jme3/renderer/queue/RenderQueue.java new file mode 100644 index 0000000..dba604e --- /dev/null +++ b/engine/src/core/com/jme3/renderer/queue/RenderQueue.java @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.renderer.queue; + +import com.jme3.post.SceneProcessor; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; + +/** + * <code>RenderQueue</code> is used to queue up and sort + * {@link Geometry geometries} for rendering. + * + * @author Kirill Vainer + */ +public class RenderQueue { + + private GeometryList opaqueList; + private GeometryList guiList; + private GeometryList transparentList; + private GeometryList translucentList; + private GeometryList skyList; + private GeometryList shadowRecv; + private GeometryList shadowCast; + + /** + * Creates a new RenderQueue, the default {@link GeometryComparator comparators} + * are used for all {@link GeometryList geometry lists}. + */ + public RenderQueue() { + this.opaqueList = new GeometryList(new OpaqueComparator()); + this.guiList = new GeometryList(new GuiComparator()); + this.transparentList = new GeometryList(new TransparentComparator()); + this.translucentList = new GeometryList(new TransparentComparator()); + this.skyList = new GeometryList(new NullComparator()); + this.shadowRecv = new GeometryList(new OpaqueComparator()); + this.shadowCast = new GeometryList(new OpaqueComparator()); + } + + /** + * The render queue <code>Bucket</code> specifies the bucket + * to which the spatial will be placed when rendered. + * <p> + * The behavior of the rendering will differ depending on which + * bucket the spatial is placed. A spatial's queue bucket can be set + * via {@link Spatial#setQueueBucket(com.jme3.renderer.queue.RenderQueue.Bucket) }. + */ + public enum Bucket { + /** + * The renderer will try to find the optimal order for rendering all + * objects using this mode. + * You should use this mode for most normal objects, except transparent + * ones, as it could give a nice performance boost to your application. + */ + Opaque, + + /** + * This is the mode you should use for object with + * transparency in them. It will ensure the objects furthest away are + * rendered first. That ensures when another transparent object is drawn on + * top of previously drawn objects, you can see those (and the object drawn + * using Opaque) through the transparent parts of the newly drawn + * object. + */ + Transparent, + + /** + * A special mode used for rendering really far away, flat objects - + * e.g. skies. In this mode, the depth is set to infinity so + * spatials in this bucket will appear behind everything, the downside + * to this bucket is that 3D objects will not be rendered correctly + * due to lack of depth testing. + */ + Sky, + + /** + * A special mode used for rendering transparent objects that + * should not be effected by {@link SceneProcessor}. + * Generally this would contain translucent objects, and + * also objects that do not write to the depth buffer such as + * particle emitters. + */ + Translucent, + + /** + * This is a special mode, for drawing 2D object + * without perspective (such as GUI or HUD parts). + * The spatial's world coordinate system has the range + * of [0, 0, -1] to [Width, Height, 1] where Width/Height is + * the resolution of the screen rendered to. Any spatials + * outside of that range are culled. + */ + Gui, + + /** + * A special mode, that will ensure that this spatial uses the same + * mode as the parent Node does. + */ + Inherit, + } + + /** + * <code>ShadowMode</code> is a marker used to specify how shadow + * effects should treat the spatial. + */ + public enum ShadowMode { + /** + * Disable both shadow casting and shadow receiving for this spatial. + * Generally used for special effects like particle emitters. + */ + Off, + + /** + * Enable casting of shadows but not receiving them. + */ + Cast, + + /** + * Enable receiving of shadows but not casting them. + */ + Receive, + + /** + * Enable both receiving and casting of shadows. + */ + CastAndReceive, + + /** + * Inherit the <code>ShadowMode</code> from the parent node. + */ + Inherit + } + + /** + * Sets a different geometry comparator for the specified bucket, one + * of Gui, Opaque, Sky, or Transparent. The GeometryComparators are + * used to sort the accumulated list of geometries before actual rendering + * occurs. + * + * <p>The most significant comparator is the one for the transparent + * bucket since there is no correct way to sort the transparent bucket + * that will handle all geometry all the time. In certain cases, the + * application may know the best way to sort and now has the option of + * configuring a specific implementation.</p> + * + * <p>The default comparators are:</p> + * <ul> + * <li>Bucket.Opaque: {@link com.jme3.renderer.queue.OpaqueComparator} which sorts + * by material first and front to back within the same material. + * <li>Bucket.Transparent: {@link com.jme3.renderer.queue.TransparentComparator} which + * sorts purely back to front by leading bounding edge with no material sort. + * <li>Bucket.Translucent: {@link com.jme3.renderer.queue.TransparentComparator} which + * sorts purely back to front by leading bounding edge with no material sort. this bucket is rendered after post processors. + * <li>Bucket.Sky: {@link com.jme3.renderer.queue.NullComparator} which does no sorting + * at all. + * <li>Bucket.Gui: {@link com.jme3.renderer.queue.GuiComparator} sorts geometries back to + * front based on their Z values. + */ + public void setGeometryComparator(Bucket bucket, GeometryComparator c) { + switch (bucket) { + case Gui: + guiList = new GeometryList(c); + break; + case Opaque: + opaqueList = new GeometryList(c); + break; + case Sky: + skyList = new GeometryList(c); + break; + case Transparent: + transparentList = new GeometryList(c); + break; + case Translucent: + translucentList = new GeometryList(c); + break; + default: + throw new UnsupportedOperationException("Unknown bucket type: " + bucket); + } + } + + /** + * Adds a geometry to a shadow bucket. + * Note that this operation is done automatically by the + * {@link RenderManager}. {@link SceneProcessor}s that handle + * shadow rendering should fetch the queue by using + * {@link #getShadowQueueContent(com.jme3.renderer.queue.RenderQueue.ShadowMode) }, + * by default no action is taken on the shadow queues. + * + * @param g The geometry to add + * @param shadBucket The shadow bucket type, if it is + * {@link ShadowMode#CastAndReceive}, it is added to both the cast + * and the receive buckets. + */ + public void addToShadowQueue(Geometry g, ShadowMode shadBucket) { + switch (shadBucket) { + case Inherit: + break; + case Off: + break; + case Cast: + shadowCast.add(g); + break; + case Receive: + shadowRecv.add(g); + break; + case CastAndReceive: + shadowCast.add(g); + shadowRecv.add(g); + break; + default: + throw new UnsupportedOperationException("Unrecognized shadow bucket type: " + shadBucket); + } + } + + /** + * Adds a geometry to the given bucket. + * The {@link RenderManager} automatically handles this task + * when flattening the scene graph. The bucket to add + * the geometry is determined by {@link Geometry#getQueueBucket() }. + * + * @param g The geometry to add + * @param bucket The bucket to add to, usually + * {@link Geometry#getQueueBucket() }. + */ + public void addToQueue(Geometry g, Bucket bucket) { + switch (bucket) { + case Gui: + guiList.add(g); + break; + case Opaque: + opaqueList.add(g); + break; + case Sky: + skyList.add(g); + break; + case Transparent: + transparentList.add(g); + break; + case Translucent: + translucentList.add(g); + break; + default: + throw new UnsupportedOperationException("Unknown bucket type: " + bucket); + } + } + + /** + * + * @param shadBucket + * @return + */ + public GeometryList getShadowQueueContent(ShadowMode shadBucket) { + switch (shadBucket) { + case Cast: + return shadowCast; + case Receive: + return shadowRecv; + default: + throw new IllegalArgumentException("Only Cast or Receive are allowed"); + } + } + + private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear) { + list.setCamera(cam); // select camera for sorting + list.sort(); + for (int i = 0; i < list.size(); i++) { + Geometry obj = list.get(i); + assert obj != null; + rm.renderGeometry(obj); + obj.queueDistance = Float.NEGATIVE_INFINITY; + } + if (clear) { + list.clear(); + } + } + + public void renderShadowQueue(GeometryList list, RenderManager rm, Camera cam, boolean clear) { + renderGeometryList(list, rm, cam, clear); + } + + public void renderShadowQueue(ShadowMode shadBucket, RenderManager rm, Camera cam, boolean clear) { + switch (shadBucket) { + case Cast: + renderGeometryList(shadowCast, rm, cam, clear); + break; + case Receive: + renderGeometryList(shadowRecv, rm, cam, clear); + break; + default: + throw new IllegalArgumentException("Unexpected shadow bucket: " + shadBucket); + } + } + + public boolean isQueueEmpty(Bucket bucket) { + switch (bucket) { + case Gui: + return guiList.size() == 0; + case Opaque: + return opaqueList.size() == 0; + case Sky: + return skyList.size() == 0; + case Transparent: + return transparentList.size() == 0; + case Translucent: + return translucentList.size() == 0; + default: + throw new UnsupportedOperationException("Unsupported bucket type: " + bucket); + } + } + + public void renderQueue(Bucket bucket, RenderManager rm, Camera cam) { + renderQueue(bucket, rm, cam, true); + } + + public void renderQueue(Bucket bucket, RenderManager rm, Camera cam, boolean clear) { + switch (bucket) { + case Gui: + renderGeometryList(guiList, rm, cam, clear); + break; + case Opaque: + renderGeometryList(opaqueList, rm, cam, clear); + break; + case Sky: + renderGeometryList(skyList, rm, cam, clear); + break; + case Transparent: + renderGeometryList(transparentList, rm, cam, clear); + break; + case Translucent: + renderGeometryList(translucentList, rm, cam, clear); + break; + + default: + throw new UnsupportedOperationException("Unsupported bucket type: " + bucket); + } + } + + public void clear() { + opaqueList.clear(); + guiList.clear(); + transparentList.clear(); + translucentList.clear(); + skyList.clear(); + shadowCast.clear(); + shadowRecv.clear(); + } +} |