Home | History | Annotate | Download | only in renderer
      1 /*
      2  * Copyright (c) 2009-2012 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;
     33 
     34 import com.jme3.material.Material;
     35 import com.jme3.material.MaterialDef;
     36 import com.jme3.material.RenderState;
     37 import com.jme3.material.Technique;
     38 import com.jme3.math.*;
     39 import com.jme3.post.SceneProcessor;
     40 import com.jme3.renderer.queue.GeometryList;
     41 import com.jme3.renderer.queue.RenderQueue;
     42 import com.jme3.renderer.queue.RenderQueue.Bucket;
     43 import com.jme3.renderer.queue.RenderQueue.ShadowMode;
     44 import com.jme3.scene.*;
     45 import com.jme3.shader.Uniform;
     46 import com.jme3.shader.UniformBinding;
     47 import com.jme3.shader.VarType;
     48 import com.jme3.system.NullRenderer;
     49 import com.jme3.system.Timer;
     50 import com.jme3.util.IntMap.Entry;
     51 import com.jme3.util.TempVars;
     52 import java.util.ArrayList;
     53 import java.util.Collections;
     54 import java.util.List;
     55 import java.util.logging.Logger;
     56 
     57 /**
     58  * <code>RenderManager</code> is a high-level rendering interface that is
     59  * above the Renderer implementation. RenderManager takes care
     60  * of rendering the scene graphs attached to each viewport and
     61  * handling SceneProcessors.
     62  *
     63  * @see SceneProcessor
     64  * @see ViewPort
     65  * @see Spatial
     66  */
     67 public class RenderManager {
     68 
     69     private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
     70 
     71     private Renderer renderer;
     72     private Timer timer;
     73     private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
     74     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
     75     private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
     76     private Camera prevCam = null;
     77     private Material forcedMaterial = null;
     78     private String forcedTechnique = null;
     79     private RenderState forcedRenderState = null;
     80     private boolean shader;
     81     private int viewX, viewY, viewWidth, viewHeight;
     82     private float near, far;
     83     private Matrix4f orthoMatrix = new Matrix4f();
     84     private Matrix4f viewMatrix = new Matrix4f();
     85     private Matrix4f projMatrix = new Matrix4f();
     86     private Matrix4f viewProjMatrix = new Matrix4f();
     87     private Matrix4f worldMatrix = new Matrix4f();
     88     private Vector3f camUp = new Vector3f(),
     89             camLeft = new Vector3f(),
     90             camDir = new Vector3f(),
     91             camLoc = new Vector3f();
     92     //temp technique
     93     private String tmpTech;
     94     private boolean handleTranlucentBucket = true;
     95 
     96     /**
     97      * Create a high-level rendering interface over the
     98      * low-level rendering interface.
     99      * @param renderer
    100      */
    101     public RenderManager(Renderer renderer) {
    102         this.renderer = renderer;
    103         //this.shader = renderer.getCaps().contains(Caps.GLSL100);
    104     }
    105 
    106     /**
    107      * Returns the pre ViewPort with the given name.
    108      *
    109      * @param viewName The name of the pre ViewPort to look up
    110      * @return The ViewPort, or null if not found.
    111      *
    112      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
    113      */
    114     public ViewPort getPreView(String viewName) {
    115         for (int i = 0; i < preViewPorts.size(); i++) {
    116             if (preViewPorts.get(i).getName().equals(viewName)) {
    117                 return preViewPorts.get(i);
    118             }
    119         }
    120         return null;
    121     }
    122 
    123     /**
    124      * Removes the specified pre ViewPort.
    125      *
    126      * @param view The pre ViewPort to remove
    127      * @return True if the ViewPort was removed successfully.
    128      *
    129      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
    130      */
    131     public boolean removePreView(ViewPort view) {
    132         return preViewPorts.remove(view);
    133     }
    134 
    135     /**
    136      * Returns the main ViewPort with the given name.
    137      *
    138      * @param viewName The name of the main ViewPort to look up
    139      * @return The ViewPort, or null if not found.
    140      *
    141      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
    142      */
    143     public ViewPort getMainView(String viewName) {
    144         for (int i = 0; i < viewPorts.size(); i++) {
    145             if (viewPorts.get(i).getName().equals(viewName)) {
    146                 return viewPorts.get(i);
    147             }
    148         }
    149         return null;
    150     }
    151 
    152     /**
    153      * Removes the main ViewPort with the specified name.
    154      *
    155      * @param viewName The main ViewPort name to remove
    156      * @return True if the ViewPort was removed successfully.
    157      *
    158      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
    159      */
    160     public boolean removeMainView(String viewName) {
    161         for (int i = 0; i < viewPorts.size(); i++) {
    162             if (viewPorts.get(i).getName().equals(viewName)) {
    163                 viewPorts.remove(i);
    164                 return true;
    165             }
    166         }
    167         return false;
    168     }
    169 
    170     /**
    171      * Removes the specified main ViewPort.
    172      *
    173      * @param view The main ViewPort to remove
    174      * @return True if the ViewPort was removed successfully.
    175      *
    176      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
    177      */
    178     public boolean removeMainView(ViewPort view) {
    179         return viewPorts.remove(view);
    180     }
    181 
    182     /**
    183      * Returns the post ViewPort with the given name.
    184      *
    185      * @param viewName The name of the post ViewPort to look up
    186      * @return The ViewPort, or null if not found.
    187      *
    188      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
    189      */
    190     public ViewPort getPostView(String viewName) {
    191         for (int i = 0; i < postViewPorts.size(); i++) {
    192             if (postViewPorts.get(i).getName().equals(viewName)) {
    193                 return postViewPorts.get(i);
    194             }
    195         }
    196         return null;
    197     }
    198 
    199     /**
    200      * Removes the post ViewPort with the specified name.
    201      *
    202      * @param viewName The post ViewPort name to remove
    203      * @return True if the ViewPort was removed successfully.
    204      *
    205      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
    206      */
    207     public boolean removePostView(String viewName) {
    208         for (int i = 0; i < postViewPorts.size(); i++) {
    209             if (postViewPorts.get(i).getName().equals(viewName)) {
    210                 postViewPorts.remove(i);
    211 
    212                 return true;
    213             }
    214         }
    215         return false;
    216     }
    217 
    218     /**
    219      * Removes the specified post ViewPort.
    220      *
    221      * @param view The post ViewPort to remove
    222      * @return True if the ViewPort was removed successfully.
    223      *
    224      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
    225      */
    226     public boolean removePostView(ViewPort view) {
    227         return postViewPorts.remove(view);
    228     }
    229 
    230     /**
    231      * Returns a read-only list of all pre ViewPorts
    232      * @return a read-only list of all pre ViewPorts
    233      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
    234      */
    235     public List<ViewPort> getPreViews() {
    236         return Collections.unmodifiableList(preViewPorts);
    237     }
    238 
    239     /**
    240      * Returns a read-only list of all main ViewPorts
    241      * @return a read-only list of all main ViewPorts
    242      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
    243      */
    244     public List<ViewPort> getMainViews() {
    245         return Collections.unmodifiableList(viewPorts);
    246     }
    247 
    248     /**
    249      * Returns a read-only list of all post ViewPorts
    250      * @return a read-only list of all post ViewPorts
    251      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
    252      */
    253     public List<ViewPort> getPostViews() {
    254         return Collections.unmodifiableList(postViewPorts);
    255     }
    256 
    257     /**
    258      * Creates a new pre ViewPort, to display the given camera's content.
    259      * <p>
    260      * The view will be processed before the main and post viewports.
    261      */
    262     public ViewPort createPreView(String viewName, Camera cam) {
    263         ViewPort vp = new ViewPort(viewName, cam);
    264         preViewPorts.add(vp);
    265         return vp;
    266     }
    267 
    268     /**
    269      * Creates a new main ViewPort, to display the given camera's content.
    270      * <p>
    271      * The view will be processed before the post viewports but after
    272      * the pre viewports.
    273      */
    274     public ViewPort createMainView(String viewName, Camera cam) {
    275         ViewPort vp = new ViewPort(viewName, cam);
    276         viewPorts.add(vp);
    277         return vp;
    278     }
    279 
    280     /**
    281      * Creates a new post ViewPort, to display the given camera's content.
    282      * <p>
    283      * The view will be processed after the pre and main viewports.
    284      */
    285     public ViewPort createPostView(String viewName, Camera cam) {
    286         ViewPort vp = new ViewPort(viewName, cam);
    287         postViewPorts.add(vp);
    288         return vp;
    289     }
    290 
    291     private void notifyReshape(ViewPort vp, int w, int h) {
    292         List<SceneProcessor> processors = vp.getProcessors();
    293         for (SceneProcessor proc : processors) {
    294             if (!proc.isInitialized()) {
    295                 proc.initialize(this, vp);
    296             } else {
    297                 proc.reshape(vp, w, h);
    298             }
    299         }
    300     }
    301 
    302     /**
    303      * Internal use only.
    304      * Updates the resolution of all on-screen cameras to match
    305      * the given width and height.
    306      */
    307     public void notifyReshape(int w, int h) {
    308         for (ViewPort vp : preViewPorts) {
    309             if (vp.getOutputFrameBuffer() == null) {
    310                 Camera cam = vp.getCamera();
    311                 cam.resize(w, h, true);
    312             }
    313             notifyReshape(vp, w, h);
    314         }
    315         for (ViewPort vp : viewPorts) {
    316             if (vp.getOutputFrameBuffer() == null) {
    317                 Camera cam = vp.getCamera();
    318                 cam.resize(w, h, true);
    319             }
    320             notifyReshape(vp, w, h);
    321         }
    322         for (ViewPort vp : postViewPorts) {
    323             if (vp.getOutputFrameBuffer() == null) {
    324                 Camera cam = vp.getCamera();
    325                 cam.resize(w, h, true);
    326             }
    327             notifyReshape(vp, w, h);
    328         }
    329     }
    330 
    331     /**
    332      * Internal use only.
    333      * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
    334      * based on the current world state.
    335      */
    336     public void updateUniformBindings(List<Uniform> params) {
    337         // assums worldMatrix is properly set.
    338         TempVars vars = TempVars.get();
    339 
    340         Matrix4f tempMat4 = vars.tempMat4;
    341         Matrix3f tempMat3 = vars.tempMat3;
    342         Vector2f tempVec2 = vars.vect2d;
    343         Quaternion tempVec4 = vars.quat1;
    344 
    345         for (int i = 0; i < params.size(); i++) {
    346             Uniform u = params.get(i);
    347             switch (u.getBinding()) {
    348                 case WorldMatrix:
    349                     u.setValue(VarType.Matrix4, worldMatrix);
    350                     break;
    351                 case ViewMatrix:
    352                     u.setValue(VarType.Matrix4, viewMatrix);
    353                     break;
    354                 case ProjectionMatrix:
    355                     u.setValue(VarType.Matrix4, projMatrix);
    356                     break;
    357                 case ViewProjectionMatrix:
    358                     u.setValue(VarType.Matrix4, viewProjMatrix);
    359                     break;
    360                 case WorldViewMatrix:
    361                     tempMat4.set(viewMatrix);
    362                     tempMat4.multLocal(worldMatrix);
    363                     u.setValue(VarType.Matrix4, tempMat4);
    364                     break;
    365                 case NormalMatrix:
    366                     tempMat4.set(viewMatrix);
    367                     tempMat4.multLocal(worldMatrix);
    368                     tempMat4.toRotationMatrix(tempMat3);
    369                     tempMat3.invertLocal();
    370                     tempMat3.transposeLocal();
    371                     u.setValue(VarType.Matrix3, tempMat3);
    372                     break;
    373                 case WorldViewProjectionMatrix:
    374                     tempMat4.set(viewProjMatrix);
    375                     tempMat4.multLocal(worldMatrix);
    376                     u.setValue(VarType.Matrix4, tempMat4);
    377                     break;
    378                 case WorldMatrixInverse:
    379                     tempMat4.set(worldMatrix);
    380                     tempMat4.invertLocal();
    381                     u.setValue(VarType.Matrix4, tempMat4);
    382                     break;
    383                 case WorldMatrixInverseTranspose:
    384                     worldMatrix.toRotationMatrix(tempMat3);
    385                     tempMat3.invertLocal().transposeLocal();
    386                     u.setValue(VarType.Matrix3, tempMat3);
    387                     break;
    388                 case ViewMatrixInverse:
    389                     tempMat4.set(viewMatrix);
    390                     tempMat4.invertLocal();
    391                     u.setValue(VarType.Matrix4, tempMat4);
    392                     break;
    393                 case ProjectionMatrixInverse:
    394                     tempMat4.set(projMatrix);
    395                     tempMat4.invertLocal();
    396                     u.setValue(VarType.Matrix4, tempMat4);
    397                     break;
    398                 case ViewProjectionMatrixInverse:
    399                     tempMat4.set(viewProjMatrix);
    400                     tempMat4.invertLocal();
    401                     u.setValue(VarType.Matrix4, tempMat4);
    402                     break;
    403                 case WorldViewMatrixInverse:
    404                     tempMat4.set(viewMatrix);
    405                     tempMat4.multLocal(worldMatrix);
    406                     tempMat4.invertLocal();
    407                     u.setValue(VarType.Matrix4, tempMat4);
    408                     break;
    409                 case NormalMatrixInverse:
    410                     tempMat4.set(viewMatrix);
    411                     tempMat4.multLocal(worldMatrix);
    412                     tempMat4.toRotationMatrix(tempMat3);
    413                     tempMat3.invertLocal();
    414                     tempMat3.transposeLocal();
    415                     tempMat3.invertLocal();
    416                     u.setValue(VarType.Matrix3, tempMat3);
    417                     break;
    418                 case WorldViewProjectionMatrixInverse:
    419                     tempMat4.set(viewProjMatrix);
    420                     tempMat4.multLocal(worldMatrix);
    421                     tempMat4.invertLocal();
    422                     u.setValue(VarType.Matrix4, tempMat4);
    423                     break;
    424                 case ViewPort:
    425                     tempVec4.set(viewX, viewY, viewWidth, viewHeight);
    426                     u.setValue(VarType.Vector4, tempVec4);
    427                     break;
    428                 case Resolution:
    429                     tempVec2.set(viewWidth, viewHeight);
    430                     u.setValue(VarType.Vector2, tempVec2);
    431                     break;
    432                 case ResolutionInverse:
    433                     tempVec2.set(1f / viewWidth, 1f / viewHeight);
    434                     u.setValue(VarType.Vector2, tempVec2);
    435                     break;
    436                 case Aspect:
    437                     float aspect = ((float) viewWidth) / viewHeight;
    438                     u.setValue(VarType.Float, aspect);
    439                     break;
    440                 case FrustumNearFar:
    441                     tempVec2.set(near, far);
    442                     u.setValue(VarType.Vector2, tempVec2);
    443                     break;
    444                 case CameraPosition:
    445                     u.setValue(VarType.Vector3, camLoc);
    446                     break;
    447                 case CameraDirection:
    448                     u.setValue(VarType.Vector3, camDir);
    449                     break;
    450                 case CameraLeft:
    451                     u.setValue(VarType.Vector3, camLeft);
    452                     break;
    453                 case CameraUp:
    454                     u.setValue(VarType.Vector3, camUp);
    455                     break;
    456                 case Time:
    457                     u.setValue(VarType.Float, timer.getTimeInSeconds());
    458                     break;
    459                 case Tpf:
    460                     u.setValue(VarType.Float, timer.getTimePerFrame());
    461                     break;
    462                 case FrameRate:
    463                     u.setValue(VarType.Float, timer.getFrameRate());
    464                     break;
    465             }
    466         }
    467 
    468         vars.release();
    469     }
    470 
    471     /**
    472      * Set the material to use to render all future objects.
    473      * This overrides the material set on the geometry and renders
    474      * with the provided material instead.
    475      * Use null to clear the material and return renderer to normal
    476      * functionality.
    477      * @param mat The forced material to set, or null to return to normal
    478      */
    479     public void setForcedMaterial(Material mat) {
    480         forcedMaterial = mat;
    481     }
    482 
    483     /**
    484      * Returns the forced render state previously set with
    485      * {@link #setForcedRenderState(com.jme3.material.RenderState) }.
    486      * @return the forced render state
    487      */
    488     public RenderState getForcedRenderState() {
    489         return forcedRenderState;
    490     }
    491 
    492     /**
    493      * Set the render state to use for all future objects.
    494      * This overrides the render state set on the material and instead
    495      * forces this render state to be applied for all future materials
    496      * rendered. Set to null to return to normal functionality.
    497      *
    498      * @param forcedRenderState The forced render state to set, or null
    499      * to return to normal
    500      */
    501     public void setForcedRenderState(RenderState forcedRenderState) {
    502         this.forcedRenderState = forcedRenderState;
    503     }
    504 
    505     /**
    506      * Set the timer that should be used to query the time based
    507      * {@link UniformBinding}s for material world parameters.
    508      *
    509      * @param timer The timer to query time world parameters
    510      */
    511     public void setTimer(Timer timer) {
    512         this.timer = timer;
    513     }
    514 
    515     /**
    516      * Returns the forced technique name set.
    517      *
    518      * @return the forced technique name set.
    519      *
    520      * @see #setForcedTechnique(java.lang.String)
    521      */
    522     public String getForcedTechnique() {
    523         return forcedTechnique;
    524     }
    525 
    526     /**
    527      * Sets the forced technique to use when rendering geometries.
    528      * <p>
    529      * If the specified technique name is available on the geometry's
    530      * material, then it is used, otherwise, the
    531      * {@link #setForcedMaterial(com.jme3.material.Material) forced material} is used.
    532      * If a forced material is not set and the forced technique name cannot
    533      * be found on the material, the geometry will <em>not</em> be rendered.
    534      *
    535      * @param forcedTechnique The forced technique name to use, set to null
    536      * to return to normal functionality.
    537      *
    538      * @see #renderGeometry(com.jme3.scene.Geometry)
    539      */
    540     public void setForcedTechnique(String forcedTechnique) {
    541         this.forcedTechnique = forcedTechnique;
    542     }
    543 
    544     /**
    545      * Enable or disable alpha-to-coverage.
    546      * <p>
    547      * When alpha to coverage is enabled and the renderer implementation
    548      * supports it, then alpha blending will be replaced with alpha dissolve
    549      * if multi-sampling is also set on the renderer.
    550      * This feature allows avoiding of alpha blending artifacts due to
    551      * lack of triangle-level back-to-front sorting.
    552      *
    553      * @param value True to enable alpha-to-coverage, false otherwise.
    554      */
    555     public void setAlphaToCoverage(boolean value) {
    556         renderer.setAlphaToCoverage(value);
    557     }
    558 
    559     /**
    560      * True if the translucent bucket should automatically be rendered
    561      * by the RenderManager.
    562      *
    563      * @return Whether or not the translucent bucket is rendered.
    564      *
    565      * @see #setHandleTranslucentBucket(boolean)
    566      */
    567     public boolean isHandleTranslucentBucket() {
    568         return handleTranlucentBucket;
    569     }
    570 
    571     /**
    572      * Enable or disable rendering of the
    573      * {@link Bucket#Translucent translucent bucket}
    574      * by the RenderManager. The default is enabled.
    575      *
    576      * @param handleTranslucentBucket Whether or not the translucent bucket should
    577      * be rendered.
    578      */
    579     public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
    580         this.handleTranlucentBucket = handleTranslucentBucket;
    581     }
    582 
    583     /**
    584      * Internal use only. Sets the world matrix to use for future
    585      * rendering. This has no effect unless objects are rendered manually
    586      * using {@link Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) }.
    587      * Using {@link #renderGeometry(com.jme3.scene.Geometry) } will
    588      * override this value.
    589      *
    590      * @param mat The world matrix to set
    591      */
    592     public void setWorldMatrix(Matrix4f mat) {
    593         if (shader) {
    594             worldMatrix.set(mat);
    595         } else {
    596             renderer.setWorldMatrix(mat);
    597         }
    598     }
    599 
    600     /**
    601      * Renders the given geometry.
    602      * <p>
    603      * First the proper world matrix is set, if
    604      * the geometry's {@link Geometry#setIgnoreTransform(boolean) ignore transform}
    605      * feature is enabled, the identity world matrix is used, otherwise, the
    606      * geometry's {@link Geometry#getWorldMatrix() world transform matrix} is used.
    607      * <p>
    608      * Once the world matrix is applied, the proper material is chosen for rendering.
    609      * If a {@link #setForcedMaterial(com.jme3.material.Material) forced material} is
    610      * set on this RenderManager, then it is used for rendering the geometry,
    611      * otherwise, the {@link Geometry#getMaterial() geometry's material} is used.
    612      * <p>
    613      * If a {@link #setForcedTechnique(java.lang.String) forced technique} is
    614      * set on this RenderManager, then it is selected automatically
    615      * on the geometry's material and is used for rendering. Otherwise, one
    616      * of the {@link MaterialDef#getDefaultTechniques() default techniques} is
    617      * used.
    618      * <p>
    619      * If a {@link #setForcedRenderState(com.jme3.material.RenderState) forced
    620      * render state} is set on this RenderManager, then it is used
    621      * for rendering the material, and the material's own render state is ignored.
    622      * Otherwise, the material's render state is used as intended.
    623      *
    624      * @param g The geometry to render
    625      *
    626      * @see Technique
    627      * @see RenderState
    628      * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
    629      * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
    630      */
    631     public void renderGeometry(Geometry g) {
    632         if (g.isIgnoreTransform()) {
    633             setWorldMatrix(Matrix4f.IDENTITY);
    634         } else {
    635             setWorldMatrix(g.getWorldMatrix());
    636         }
    637 
    638         //if forcedTechnique we try to force it for render,
    639         //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
    640         //else the geom is not rendered
    641         if (forcedTechnique != null) {
    642             if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
    643                 tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
    644                 g.getMaterial().selectTechnique(forcedTechnique, this);
    645                 // use geometry's material
    646                 g.getMaterial().render(g, this);
    647                 g.getMaterial().selectTechnique(tmpTech, this);
    648                 //Reverted this part from revision 6197
    649                 //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
    650             } else if (forcedMaterial != null) {
    651                 // use forced material
    652                 forcedMaterial.render(g, this);
    653             }
    654         } else if (forcedMaterial != null) {
    655             // use forced material
    656             forcedMaterial.render(g, this);
    657         } else {
    658             g.getMaterial().render(g, this);
    659         }
    660     }
    661 
    662     /**
    663      * Renders the given GeometryList.
    664      * <p>
    665      * For every geometry in the list, the
    666      * {@link #renderGeometry(com.jme3.scene.Geometry) } method is called.
    667      *
    668      * @param gl The geometry list to render.
    669      *
    670      * @see GeometryList
    671      * @see #renderGeometry(com.jme3.scene.Geometry)
    672      */
    673     public void renderGeometryList(GeometryList gl) {
    674         for (int i = 0; i < gl.size(); i++) {
    675             renderGeometry(gl.get(i));
    676         }
    677     }
    678 
    679     /**
    680      * If a spatial is not inside the eye frustum, it
    681      * is still rendered in the shadow frustum (shadow casting queue)
    682      * through this recursive method.
    683      */
    684     private void renderShadow(Spatial s, RenderQueue rq) {
    685         if (s instanceof Node) {
    686             Node n = (Node) s;
    687             List<Spatial> children = n.getChildren();
    688             for (int i = 0; i < children.size(); i++) {
    689                 renderShadow(children.get(i), rq);
    690             }
    691         } else if (s instanceof Geometry) {
    692             Geometry gm = (Geometry) s;
    693 
    694             RenderQueue.ShadowMode shadowMode = s.getShadowMode();
    695             if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
    696                 //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
    697                 rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
    698             }
    699         }
    700     }
    701 
    702     /**
    703      * Preloads a scene for rendering.
    704      * <p>
    705      * After invocation of this method, the underlying
    706      * renderer would have uploaded any textures, shaders and meshes
    707      * used by the given scene to the video driver.
    708      * Using this method is useful when wishing to avoid the initial pause
    709      * when rendering a scene for the first time. Note that it is not
    710      * guaranteed that the underlying renderer will actually choose to upload
    711      * the data to the GPU so some pause is still to be expected.
    712      *
    713      * @param scene The scene to preload
    714      */
    715     public void preloadScene(Spatial scene) {
    716         if (scene instanceof Node) {
    717             // recurse for all children
    718             Node n = (Node) scene;
    719             List<Spatial> children = n.getChildren();
    720             for (int i = 0; i < children.size(); i++) {
    721                 preloadScene(children.get(i));
    722             }
    723         } else if (scene instanceof Geometry) {
    724             // add to the render queue
    725             Geometry gm = (Geometry) scene;
    726             if (gm.getMaterial() == null) {
    727                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
    728             }
    729 
    730             gm.getMaterial().preload(this);
    731             Mesh mesh = gm.getMesh();
    732             if (mesh != null) {
    733                 for (VertexBuffer vb : mesh.getBufferList().getArray()) {
    734                     if (vb.getData() != null) {
    735                         renderer.updateBufferData(vb);
    736                     }
    737                 }
    738             }
    739         }
    740     }
    741 
    742     /**
    743      * Flattens the given scene graph into the ViewPort's RenderQueue,
    744      * checking for culling as the call goes down the graph recursively.
    745      * <p>
    746      * First, the scene is checked for culling based on the <code>Spatial</code>s
    747      * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
    748      * if the camera frustum contains the scene, then this method is recursively
    749      * called on its children.
    750      * <p>
    751      * When the scene's leaves or {@link Geometry geometries} are reached,
    752      * they are each enqueued into the
    753      * {@link ViewPort#getQueue() ViewPort's render queue}.
    754      * <p>
    755      * In addition to enqueuing the visible geometries, this method
    756      * also scenes which cast or receive shadows, by putting them into the
    757      * RenderQueue's
    758      * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
    759      * shadow queue}. Each Spatial which has its
    760      * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
    761      * set to not off, will be put into the appropriate shadow queue, note that
    762      * this process does not check for frustum culling on any
    763      * {@link ShadowMode#Cast shadow casters}, as they don't have to be
    764      * in the eye camera frustum to cast shadows on objects that are inside it.
    765      *
    766      * @param scene The scene to flatten into the queue
    767      * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
    768      * used for culling and the {@link ViewPort#getQueue() queue} used to
    769      * contain the flattened scene graph.
    770      */
    771     public void renderScene(Spatial scene, ViewPort vp) {
    772         if (scene.getParent() == null) {
    773             vp.getCamera().setPlaneState(0);
    774         }
    775         // check culling first.
    776         if (!scene.checkCulling(vp.getCamera())) {
    777             // move on to shadow-only render
    778             if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint()!=Spatial.CullHint.Always) {
    779                 renderShadow(scene, vp.getQueue());
    780             }
    781             return;
    782         }
    783 
    784         scene.runControlRender(this, vp);
    785         if (scene instanceof Node) {
    786             // recurse for all children
    787             Node n = (Node) scene;
    788             List<Spatial> children = n.getChildren();
    789             //saving cam state for culling
    790             int camState = vp.getCamera().getPlaneState();
    791             for (int i = 0; i < children.size(); i++) {
    792                 //restoring cam state before proceeding children recusively
    793                 vp.getCamera().setPlaneState(camState);
    794                 renderScene(children.get(i), vp);
    795 
    796             }
    797         } else if (scene instanceof Geometry) {
    798 
    799             // add to the render queue
    800             Geometry gm = (Geometry) scene;
    801             if (gm.getMaterial() == null) {
    802                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
    803             }
    804 
    805             vp.getQueue().addToQueue(gm, scene.getQueueBucket());
    806 
    807             // add to shadow queue if needed
    808             RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
    809             if (shadowMode != RenderQueue.ShadowMode.Off) {
    810                 vp.getQueue().addToShadowQueue(gm, shadowMode);
    811             }
    812         }
    813     }
    814 
    815     /**
    816      * Returns the camera currently used for rendering.
    817      * <p>
    818      * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
    819      *
    820      * @return the camera currently used for rendering.
    821      */
    822     public Camera getCurrentCamera() {
    823         return prevCam;
    824     }
    825 
    826     /**
    827      * The renderer implementation used for rendering operations.
    828      *
    829      * @return The renderer implementation
    830      *
    831      * @see #RenderManager(com.jme3.renderer.Renderer)
    832      * @see Renderer
    833      */
    834     public Renderer getRenderer() {
    835         return renderer;
    836     }
    837 
    838     /**
    839      * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
    840      * by rendering each of its visible buckets.
    841      * By default the queues will automatically be cleared after rendering,
    842      * so there's no need to clear them manually.
    843      *
    844      * @param vp The ViewPort of which the queue will be flushed
    845      *
    846      * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera)
    847      * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList)
    848      */
    849     public void flushQueue(ViewPort vp) {
    850         renderViewPortQueues(vp, true);
    851     }
    852 
    853     /**
    854      * Clears the queue of the given ViewPort.
    855      * Simply calls {@link RenderQueue#clear() } on the ViewPort's
    856      * {@link ViewPort#getQueue() render queue}.
    857      *
    858      * @param vp The ViewPort of which the queue will be cleared.
    859      *
    860      * @see RenderQueue#clear()
    861      * @see ViewPort#getQueue()
    862      */
    863     public void clearQueue(ViewPort vp) {
    864         vp.getQueue().clear();
    865     }
    866 
    867     /**
    868      * Render the given viewport queues.
    869      * <p>
    870      * Changes the {@link Renderer#setDepthRange(float, float) depth range}
    871      * appropriately as expected by each queue and then calls
    872      * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
    873      * on the queue. Makes sure to restore the depth range to [0, 1]
    874      * at the end of the call.
    875      * Note that the {@link Bucket#Translucent translucent bucket} is NOT
    876      * rendered by this method. Instead the user should call
    877      * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
    878      * after this call.
    879      *
    880      * @param vp the viewport of which queue should be rendered
    881      * @param flush If true, the queues will be cleared after
    882      * rendering.
    883      *
    884      * @see RenderQueue
    885      * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort)
    886      */
    887     public void renderViewPortQueues(ViewPort vp, boolean flush) {
    888         RenderQueue rq = vp.getQueue();
    889         Camera cam = vp.getCamera();
    890         boolean depthRangeChanged = false;
    891 
    892         // render opaque objects with default depth range
    893         // opaque objects are sorted front-to-back, reducing overdraw
    894         rq.renderQueue(Bucket.Opaque, this, cam, flush);
    895 
    896         // render the sky, with depth range set to the farthest
    897         if (!rq.isQueueEmpty(Bucket.Sky)) {
    898             renderer.setDepthRange(1, 1);
    899             rq.renderQueue(Bucket.Sky, this, cam, flush);
    900             depthRangeChanged = true;
    901         }
    902 
    903 
    904         // transparent objects are last because they require blending with the
    905         // rest of the scene's objects. Consequently, they are sorted
    906         // back-to-front.
    907         if (!rq.isQueueEmpty(Bucket.Transparent)) {
    908             if (depthRangeChanged) {
    909                 renderer.setDepthRange(0, 1);
    910                 depthRangeChanged = false;
    911             }
    912 
    913             rq.renderQueue(Bucket.Transparent, this, cam, flush);
    914         }
    915 
    916         if (!rq.isQueueEmpty(Bucket.Gui)) {
    917             renderer.setDepthRange(0, 0);
    918             setCamera(cam, true);
    919             rq.renderQueue(Bucket.Gui, this, cam, flush);
    920             setCamera(cam, false);
    921             depthRangeChanged = true;
    922         }
    923 
    924         // restore range to default
    925         if (depthRangeChanged) {
    926             renderer.setDepthRange(0, 1);
    927         }
    928     }
    929 
    930     /**
    931      * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
    932      * <p>
    933      * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
    934      * is set to true. This method clears the translucent queue after rendering
    935      * it.
    936      *
    937      * @param vp The viewport of which the translucent queue should be rendered.
    938      *
    939      * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean)
    940      * @see #setHandleTranslucentBucket(boolean)
    941      */
    942     public void renderTranslucentQueue(ViewPort vp) {
    943         RenderQueue rq = vp.getQueue();
    944         if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
    945             rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
    946         }
    947     }
    948 
    949     private void setViewPort(Camera cam) {
    950         // this will make sure to update viewport only if needed
    951         if (cam != prevCam || cam.isViewportChanged()) {
    952             viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
    953             viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
    954             viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
    955             viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
    956             renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
    957             renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
    958             cam.clearViewportChanged();
    959             prevCam = cam;
    960 
    961 //            float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
    962 //            float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
    963 //            float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
    964 //            float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
    965 //
    966 //            orthoMatrix.loadIdentity();
    967 //            orthoMatrix.setTranslation(translateX, translateY, 0);
    968 //            orthoMatrix.setScale(scaleX, scaleY, 0);
    969 
    970             orthoMatrix.loadIdentity();
    971             orthoMatrix.setTranslation(-1f, -1f, 0f);
    972             orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
    973         }
    974     }
    975 
    976     private void setViewProjection(Camera cam, boolean ortho) {
    977         if (shader) {
    978             if (ortho) {
    979                 viewMatrix.set(Matrix4f.IDENTITY);
    980                 projMatrix.set(orthoMatrix);
    981                 viewProjMatrix.set(orthoMatrix);
    982             } else {
    983                 viewMatrix.set(cam.getViewMatrix());
    984                 projMatrix.set(cam.getProjectionMatrix());
    985                 viewProjMatrix.set(cam.getViewProjectionMatrix());
    986             }
    987 
    988             camLoc.set(cam.getLocation());
    989             cam.getLeft(camLeft);
    990             cam.getUp(camUp);
    991             cam.getDirection(camDir);
    992 
    993             near = cam.getFrustumNear();
    994             far = cam.getFrustumFar();
    995         } else {
    996             if (ortho) {
    997                 renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
    998             } else {
    999                 renderer.setViewProjectionMatrices(cam.getViewMatrix(),
   1000                         cam.getProjectionMatrix());
   1001             }
   1002 
   1003         }
   1004     }
   1005 
   1006     /**
   1007      * Set the camera to use for rendering.
   1008      * <p>
   1009      * First, the camera's
   1010      * {@link Camera#setViewPort(float, float, float, float) view port parameters}
   1011      * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and
   1012      * {@link Camera#getProjectionMatrix() projection} matrices are set
   1013      * on the renderer. If <code>ortho</code> is <code>true</code>, then
   1014      * instead of using the camera's view and projection matrices, an ortho
   1015      * matrix is computed and used instead of the view projection matrix.
   1016      * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
   1017      * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
   1018      *
   1019      * @param cam The camera to set
   1020      * @param ortho True if to use orthographic projection (for GUI rendering),
   1021      * false if to use the camera's view and projection matrices.
   1022      */
   1023     public void setCamera(Camera cam, boolean ortho) {
   1024         setViewPort(cam);
   1025         setViewProjection(cam, ortho);
   1026     }
   1027 
   1028     /**
   1029      * Draws the viewport but without notifying {@link SceneProcessor scene
   1030      * processors} of any rendering events.
   1031      *
   1032      * @param vp The ViewPort to render
   1033      *
   1034      * @see #renderViewPort(com.jme3.renderer.ViewPort, float)
   1035      */
   1036     public void renderViewPortRaw(ViewPort vp) {
   1037         setCamera(vp.getCamera(), false);
   1038         List<Spatial> scenes = vp.getScenes();
   1039         for (int i = scenes.size() - 1; i >= 0; i--) {
   1040             renderScene(scenes.get(i), vp);
   1041         }
   1042         flushQueue(vp);
   1043     }
   1044 
   1045     /**
   1046      * Renders the {@link ViewPort}.
   1047      * <p>
   1048      * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
   1049      * returns immediately. Otherwise, the ViewPort is rendered by
   1050      * the following process:<br>
   1051      * <ul>
   1052      * <li>All {@link SceneProcessor scene processors} that are attached
   1053      * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
   1054      * </li>
   1055      * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method
   1056      * is called.</li>
   1057      * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
   1058      * is set on the Renderer</li>
   1059      * <li>The camera is set on the renderer, including its view port parameters.
   1060      * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
   1061      * <li>Any buffers that the ViewPort requests to be cleared are cleared
   1062      * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
   1063      * <li>Every scene that is attached to the ViewPort is flattened into
   1064      * the ViewPort's render queue
   1065      * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
   1066      * </li>
   1067      * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
   1068      * method is called.</li>
   1069      * <li>The render queue is sorted and then flushed, sending
   1070      * rendering commands to the underlying Renderer implementation.
   1071      * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
   1072      * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
   1073      * method is called.</li>
   1074      * <li>The translucent queue of the ViewPort is sorted and then flushed
   1075      * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
   1076      * <li>If any objects remained in the render queue, they are removed
   1077      * from the queue. This is generally objects added to the
   1078      * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
   1079      * shadow queue}
   1080      * which were not rendered because of a missing shadow renderer.</li>
   1081      * </ul>
   1082      *
   1083      * @param vp
   1084      * @param tpf
   1085      */
   1086     public void renderViewPort(ViewPort vp, float tpf) {
   1087         if (!vp.isEnabled()) {
   1088             return;
   1089         }
   1090         List<SceneProcessor> processors = vp.getProcessors();
   1091         if (processors.isEmpty()) {
   1092             processors = null;
   1093         }
   1094 
   1095         if (processors != null) {
   1096             for (SceneProcessor proc : processors) {
   1097                 if (!proc.isInitialized()) {
   1098                     proc.initialize(this, vp);
   1099                 }
   1100                 proc.preFrame(tpf);
   1101             }
   1102         }
   1103 
   1104         renderer.setFrameBuffer(vp.getOutputFrameBuffer());
   1105         setCamera(vp.getCamera(), false);
   1106         if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
   1107             if (vp.isClearColor()) {
   1108                 renderer.setBackgroundColor(vp.getBackgroundColor());
   1109             }
   1110             renderer.clearBuffers(vp.isClearColor(),
   1111                     vp.isClearDepth(),
   1112                     vp.isClearStencil());
   1113         }
   1114 
   1115         List<Spatial> scenes = vp.getScenes();
   1116         for (int i = scenes.size() - 1; i >= 0; i--) {
   1117             renderScene(scenes.get(i), vp);
   1118         }
   1119 
   1120         if (processors != null) {
   1121             for (SceneProcessor proc : processors) {
   1122                 proc.postQueue(vp.getQueue());
   1123             }
   1124         }
   1125 
   1126         flushQueue(vp);
   1127 
   1128         if (processors != null) {
   1129             for (SceneProcessor proc : processors) {
   1130                 proc.postFrame(vp.getOutputFrameBuffer());
   1131             }
   1132         }
   1133         //renders the translucent objects queue after processors have been rendered
   1134         renderTranslucentQueue(vp);
   1135         // clear any remaining spatials that were not rendered.
   1136         clearQueue(vp);
   1137     }
   1138 
   1139     /**
   1140      * Called by the application to render any ViewPorts
   1141      * added to this RenderManager.
   1142      * <p>
   1143      * Renders any viewports that were added using the following methods:
   1144      * <ul>
   1145      * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
   1146      * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
   1147      * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
   1148      * </ul>
   1149      *
   1150      * @param tpf Time per frame value
   1151      */
   1152     public void render(float tpf, boolean mainFrameBufferActive) {
   1153         if (renderer instanceof NullRenderer) {
   1154             return;
   1155         }
   1156 
   1157         this.shader = renderer.getCaps().contains(Caps.GLSL100);
   1158 
   1159         for (int i = 0; i < preViewPorts.size(); i++) {
   1160             ViewPort vp = preViewPorts.get(i);
   1161             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
   1162                 renderViewPort(vp, tpf);
   1163             }
   1164         }
   1165         for (int i = 0; i < viewPorts.size(); i++) {
   1166             ViewPort vp = viewPorts.get(i);
   1167             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
   1168                 renderViewPort(vp, tpf);
   1169             }
   1170         }
   1171         for (int i = 0; i < postViewPorts.size(); i++) {
   1172             ViewPort vp = postViewPorts.get(i);
   1173             if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
   1174                 renderViewPort(vp, tpf);
   1175             }
   1176         }
   1177     }
   1178 }
   1179