Home | History | Annotate | Download | only in queue
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.renderer.queue;
     33 
     34 import com.jme3.post.SceneProcessor;
     35 import com.jme3.renderer.Camera;
     36 import com.jme3.renderer.RenderManager;
     37 import com.jme3.scene.Geometry;
     38 import com.jme3.scene.Spatial;
     39 
     40 /**
     41  * <code>RenderQueue</code> is used to queue up and sort
     42  * {@link Geometry geometries} for rendering.
     43  *
     44  * @author Kirill Vainer
     45  */
     46 public class RenderQueue {
     47 
     48     private GeometryList opaqueList;
     49     private GeometryList guiList;
     50     private GeometryList transparentList;
     51     private GeometryList translucentList;
     52     private GeometryList skyList;
     53     private GeometryList shadowRecv;
     54     private GeometryList shadowCast;
     55 
     56     /**
     57      * Creates a new RenderQueue, the default {@link GeometryComparator comparators}
     58      * are used for all {@link GeometryList geometry lists}.
     59      */
     60     public RenderQueue() {
     61         this.opaqueList = new GeometryList(new OpaqueComparator());
     62         this.guiList = new GeometryList(new GuiComparator());
     63         this.transparentList = new GeometryList(new TransparentComparator());
     64         this.translucentList = new GeometryList(new TransparentComparator());
     65         this.skyList = new GeometryList(new NullComparator());
     66         this.shadowRecv = new GeometryList(new OpaqueComparator());
     67         this.shadowCast = new GeometryList(new OpaqueComparator());
     68     }
     69 
     70     /**
     71      * The render queue <code>Bucket</code> specifies the bucket
     72      * to which the spatial will be placed when rendered.
     73      * <p>
     74      * The behavior of the rendering will differ depending on which
     75      * bucket the spatial is placed. A spatial's queue bucket can be set
     76      * via {@link Spatial#setQueueBucket(com.jme3.renderer.queue.RenderQueue.Bucket) }.
     77      */
     78     public enum Bucket {
     79         /**
     80          * The renderer will try to find the optimal order for rendering all
     81          * objects using this mode.
     82          * You should use this mode for most normal objects, except transparent
     83          * ones, as it could give a nice performance boost to your application.
     84          */
     85         Opaque,
     86 
     87         /**
     88          * This is the mode you should use for object with
     89          * transparency in them. It will ensure the objects furthest away are
     90          * rendered first. That ensures when another transparent object is drawn on
     91          * top of previously drawn objects, you can see those (and the object drawn
     92          * using Opaque) through the transparent parts of the newly drawn
     93          * object.
     94          */
     95         Transparent,
     96 
     97         /**
     98          * A special mode used for rendering really far away, flat objects -
     99          * e.g. skies. In this mode, the depth is set to infinity so
    100          * spatials in this bucket will appear behind everything, the downside
    101          * to this bucket is that 3D objects will not be rendered correctly
    102          * due to lack of depth testing.
    103          */
    104         Sky,
    105 
    106         /**
    107          * A special mode used for rendering transparent objects that
    108          * should not be effected by {@link SceneProcessor}.
    109          * Generally this would contain translucent objects, and
    110          * also objects that do not write to the depth buffer such as
    111          * particle emitters.
    112          */
    113         Translucent,
    114 
    115         /**
    116          * This is a special mode, for drawing 2D object
    117          * without perspective (such as GUI or HUD parts).
    118          * The spatial's world coordinate system has the range
    119          * of [0, 0, -1] to [Width, Height, 1] where Width/Height is
    120          * the resolution of the screen rendered to. Any spatials
    121          * outside of that range are culled.
    122          */
    123         Gui,
    124 
    125         /**
    126          * A special mode, that will ensure that this spatial uses the same
    127          * mode as the parent Node does.
    128          */
    129         Inherit,
    130     }
    131 
    132     /**
    133      * <code>ShadowMode</code> is a marker used to specify how shadow
    134      * effects should treat the spatial.
    135      */
    136     public enum ShadowMode {
    137         /**
    138          * Disable both shadow casting and shadow receiving for this spatial.
    139          * Generally used for special effects like particle emitters.
    140          */
    141         Off,
    142 
    143         /**
    144          * Enable casting of shadows but not receiving them.
    145          */
    146         Cast,
    147 
    148         /**
    149          * Enable receiving of shadows but not casting them.
    150          */
    151         Receive,
    152 
    153         /**
    154          * Enable both receiving and casting of shadows.
    155          */
    156         CastAndReceive,
    157 
    158         /**
    159          * Inherit the <code>ShadowMode</code> from the parent node.
    160          */
    161         Inherit
    162     }
    163 
    164     /**
    165      *  Sets a different geometry comparator for the specified bucket, one
    166      *  of Gui, Opaque, Sky, or Transparent.  The GeometryComparators are
    167      *  used to sort the accumulated list of geometries before actual rendering
    168      *  occurs.
    169      *
    170      *  <p>The most significant comparator is the one for the transparent
    171      *  bucket since there is no correct way to sort the transparent bucket
    172      *  that will handle all geometry all the time.  In certain cases, the
    173      *  application may know the best way to sort and now has the option of
    174      *  configuring a specific implementation.</p>
    175      *
    176      *  <p>The default comparators are:</p>
    177      *  <ul>
    178      *  <li>Bucket.Opaque: {@link com.jme3.renderer.queue.OpaqueComparator} which sorts
    179      *                     by material first and front to back within the same material.
    180      *  <li>Bucket.Transparent: {@link com.jme3.renderer.queue.TransparentComparator} which
    181      *                     sorts purely back to front by leading bounding edge with no material sort.
    182      *  <li>Bucket.Translucent: {@link com.jme3.renderer.queue.TransparentComparator} which
    183      *                     sorts purely back to front by leading bounding edge with no material sort. this bucket is rendered after post processors.
    184      *  <li>Bucket.Sky: {@link com.jme3.renderer.queue.NullComparator} which does no sorting
    185      *                     at all.
    186      *  <li>Bucket.Gui: {@link com.jme3.renderer.queue.GuiComparator} sorts geometries back to
    187      *                     front based on their Z values.
    188      */
    189     public void setGeometryComparator(Bucket bucket, GeometryComparator c) {
    190         switch (bucket) {
    191             case Gui:
    192                 guiList = new GeometryList(c);
    193                 break;
    194             case Opaque:
    195                 opaqueList = new GeometryList(c);
    196                 break;
    197             case Sky:
    198                 skyList = new GeometryList(c);
    199                 break;
    200             case Transparent:
    201                 transparentList = new GeometryList(c);
    202                 break;
    203             case Translucent:
    204                 translucentList = new GeometryList(c);
    205                 break;
    206             default:
    207                 throw new UnsupportedOperationException("Unknown bucket type: " + bucket);
    208         }
    209     }
    210 
    211     /**
    212      * Adds a geometry to a shadow bucket.
    213      * Note that this operation is done automatically by the
    214      * {@link RenderManager}. {@link SceneProcessor}s that handle
    215      * shadow rendering should fetch the queue by using
    216      * {@link #getShadowQueueContent(com.jme3.renderer.queue.RenderQueue.ShadowMode) },
    217      * by default no action is taken on the shadow queues.
    218      *
    219      * @param g The geometry to add
    220      * @param shadBucket The shadow bucket type, if it is
    221      * {@link ShadowMode#CastAndReceive}, it is added to both the cast
    222      * and the receive buckets.
    223      */
    224     public void addToShadowQueue(Geometry g, ShadowMode shadBucket) {
    225         switch (shadBucket) {
    226             case Inherit:
    227                 break;
    228             case Off:
    229                 break;
    230             case Cast:
    231                 shadowCast.add(g);
    232                 break;
    233             case Receive:
    234                 shadowRecv.add(g);
    235                 break;
    236             case CastAndReceive:
    237                 shadowCast.add(g);
    238                 shadowRecv.add(g);
    239                 break;
    240             default:
    241                 throw new UnsupportedOperationException("Unrecognized shadow bucket type: " + shadBucket);
    242         }
    243     }
    244 
    245     /**
    246      * Adds a geometry to the given bucket.
    247      * The {@link RenderManager} automatically handles this task
    248      * when flattening the scene graph. The bucket to add
    249      * the geometry is determined by {@link Geometry#getQueueBucket() }.
    250      *
    251      * @param g  The geometry to add
    252      * @param bucket The bucket to add to, usually
    253      * {@link Geometry#getQueueBucket() }.
    254      */
    255     public void addToQueue(Geometry g, Bucket bucket) {
    256         switch (bucket) {
    257             case Gui:
    258                 guiList.add(g);
    259                 break;
    260             case Opaque:
    261                 opaqueList.add(g);
    262                 break;
    263             case Sky:
    264                 skyList.add(g);
    265                 break;
    266             case Transparent:
    267                 transparentList.add(g);
    268                 break;
    269             case Translucent:
    270                 translucentList.add(g);
    271                 break;
    272             default:
    273                 throw new UnsupportedOperationException("Unknown bucket type: " + bucket);
    274         }
    275     }
    276 
    277     /**
    278      *
    279      * @param shadBucket
    280      * @return
    281      */
    282     public GeometryList getShadowQueueContent(ShadowMode shadBucket) {
    283         switch (shadBucket) {
    284             case Cast:
    285                 return shadowCast;
    286             case Receive:
    287                 return shadowRecv;
    288             default:
    289                 throw new IllegalArgumentException("Only Cast or Receive are allowed");
    290         }
    291     }
    292 
    293     private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear) {
    294         list.setCamera(cam); // select camera for sorting
    295         list.sort();
    296         for (int i = 0; i < list.size(); i++) {
    297             Geometry obj = list.get(i);
    298             assert obj != null;
    299             rm.renderGeometry(obj);
    300             obj.queueDistance = Float.NEGATIVE_INFINITY;
    301         }
    302         if (clear) {
    303             list.clear();
    304         }
    305     }
    306 
    307     public void renderShadowQueue(GeometryList list, RenderManager rm, Camera cam, boolean clear) {
    308         renderGeometryList(list, rm, cam, clear);
    309     }
    310 
    311     public void renderShadowQueue(ShadowMode shadBucket, RenderManager rm, Camera cam, boolean clear) {
    312         switch (shadBucket) {
    313             case Cast:
    314                 renderGeometryList(shadowCast, rm, cam, clear);
    315                 break;
    316             case Receive:
    317                 renderGeometryList(shadowRecv, rm, cam, clear);
    318                 break;
    319             default:
    320                 throw new IllegalArgumentException("Unexpected shadow bucket: " + shadBucket);
    321         }
    322     }
    323 
    324     public boolean isQueueEmpty(Bucket bucket) {
    325         switch (bucket) {
    326             case Gui:
    327                 return guiList.size() == 0;
    328             case Opaque:
    329                 return opaqueList.size() == 0;
    330             case Sky:
    331                 return skyList.size() == 0;
    332             case Transparent:
    333                 return transparentList.size() == 0;
    334             case Translucent:
    335                 return translucentList.size() == 0;
    336             default:
    337                 throw new UnsupportedOperationException("Unsupported bucket type: " + bucket);
    338         }
    339     }
    340 
    341     public void renderQueue(Bucket bucket, RenderManager rm, Camera cam) {
    342         renderQueue(bucket, rm, cam, true);
    343     }
    344 
    345     public void renderQueue(Bucket bucket, RenderManager rm, Camera cam, boolean clear) {
    346         switch (bucket) {
    347             case Gui:
    348                 renderGeometryList(guiList, rm, cam, clear);
    349                 break;
    350             case Opaque:
    351                 renderGeometryList(opaqueList, rm, cam, clear);
    352                 break;
    353             case Sky:
    354                 renderGeometryList(skyList, rm, cam, clear);
    355                 break;
    356             case Transparent:
    357                 renderGeometryList(transparentList, rm, cam, clear);
    358                 break;
    359             case Translucent:
    360                 renderGeometryList(translucentList, rm, cam, clear);
    361                 break;
    362 
    363             default:
    364                 throw new UnsupportedOperationException("Unsupported bucket type: " + bucket);
    365         }
    366     }
    367 
    368     public void clear() {
    369         opaqueList.clear();
    370         guiList.clear();
    371         transparentList.clear();
    372         translucentList.clear();
    373         skyList.clear();
    374         shadowCast.clear();
    375         shadowRecv.clear();
    376     }
    377 }
    378