OSDN Git Service

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