aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/renderer/queue/RenderQueue.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/renderer/queue/RenderQueue.java')
-rw-r--r--engine/src/core/com/jme3/renderer/queue/RenderQueue.java377
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();
+ }
+}