OSDN Git Service

* Javadocs for com.jme3.renderer
[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.IntMap.Entry;
59 import com.jme3.util.TempVars;
60 import java.util.ArrayList;
61 import java.util.Collections;
62 import java.util.List;
63 import java.util.logging.Logger;
64
65 /**
66  * <code>RenderManager</code> is a high-level rendering interface that is
67  * above the Renderer implementation. RenderManager takes care
68  * of rendering the scene graphs attached to each viewport and
69  * handling SceneProcessors.
70  *
71  * @see SceneProcessor
72  * @see ViewPort
73  * @see Spatial
74  */
75 public class RenderManager {
76
77     private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
78     
79     private Renderer renderer;
80     private Timer timer;
81     private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
82     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
83     private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
84     private Camera prevCam = null;
85     private Material forcedMaterial = null;
86     private String forcedTechnique = null;
87     private RenderState forcedRenderState = null;
88     private boolean shader;
89     private int viewX, viewY, viewWidth, viewHeight;
90     private float near, far;
91     private Matrix4f orthoMatrix = new Matrix4f();
92     private Matrix4f viewMatrix = new Matrix4f();
93     private Matrix4f projMatrix = new Matrix4f();
94     private Matrix4f viewProjMatrix = new Matrix4f();
95     private Matrix4f worldMatrix = new Matrix4f();
96     private Vector3f camUp = new Vector3f(),
97             camLeft = new Vector3f(),
98             camDir = new Vector3f(),
99             camLoc = new Vector3f();
100     //temp technique
101     private String tmpTech;
102     private boolean handleTranlucentBucket = true;
103
104     /**
105      * Create a high-level rendering interface over the
106      * low-level rendering interface.
107      * @param renderer
108      */
109     public RenderManager(Renderer renderer) {
110         this.renderer = renderer;
111         //this.shader = renderer.getCaps().contains(Caps.GLSL100);
112     }
113
114     /**
115      * Returns the pre ViewPort with the given name.
116      * 
117      * @param viewName The name of the pre ViewPort to look up
118      * @return The ViewPort, or null if not found.
119      * 
120      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera) 
121      */
122     public ViewPort getPreView(String viewName) {
123         for (int i = 0; i < preViewPorts.size(); i++) {
124             if (preViewPorts.get(i).getName().equals(viewName)) {
125                 return preViewPorts.get(i);
126             }
127         }
128         return null;
129     }
130
131     /**
132      * Removes the specified pre ViewPort.
133      * 
134      * @param view The pre ViewPort to remove
135      * @return True if the ViewPort was removed successfully.
136      * 
137      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera) 
138      */
139     public boolean removePreView(ViewPort view) {
140         return preViewPorts.remove(view);
141     }
142
143     /**
144      * Returns the main ViewPort with the given name.
145      * 
146      * @param viewName The name of the main ViewPort to look up
147      * @return The ViewPort, or null if not found.
148      * 
149      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera) 
150      */
151     public ViewPort getMainView(String viewName) {
152         for (int i = 0; i < viewPorts.size(); i++) {
153             if (viewPorts.get(i).getName().equals(viewName)) {
154                 return viewPorts.get(i);
155             }
156         }
157         return null;
158     }
159
160     /**
161      * Removes the main ViewPort with the specified name.
162      * 
163      * @param view The main ViewPort name to remove
164      * @return True if the ViewPort was removed successfully.
165      * 
166      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera) 
167      */
168     public boolean removeMainView(String viewName) {
169         for (int i = 0; i < viewPorts.size(); i++) {
170             if (viewPorts.get(i).getName().equals(viewName)) {
171                 viewPorts.remove(i);
172                 return true;
173             }
174         }
175         return false;
176     }
177
178     /**
179      * Removes the specified main ViewPort.
180      * 
181      * @param view The main ViewPort to remove
182      * @return True if the ViewPort was removed successfully.
183      * 
184      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera) 
185      */
186     public boolean removeMainView(ViewPort view) {
187         return viewPorts.remove(view);
188     }
189
190     /**
191      * Returns the post ViewPort with the given name.
192      * 
193      * @param viewName The name of the post ViewPort to look up
194      * @return The ViewPort, or null if not found.
195      * 
196      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera) 
197      */
198     public ViewPort getPostView(String viewName) {
199         for (int i = 0; i < postViewPorts.size(); i++) {
200             if (postViewPorts.get(i).getName().equals(viewName)) {
201                 return postViewPorts.get(i);
202             }
203         }
204         return null;
205     }
206
207     /**
208      * Removes the post ViewPort with the specified name.
209      * 
210      * @param view The post ViewPort name to remove
211      * @return True if the ViewPort was removed successfully.
212      * 
213      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera) 
214      */
215     public boolean removePostView(String viewName) {
216         for (int i = 0; i < postViewPorts.size(); i++) {
217             if (postViewPorts.get(i).getName().equals(viewName)) {
218                 postViewPorts.remove(i);
219
220                 return true;
221             }
222         }
223         return false;
224     }
225
226     /**
227      * Removes the specified post ViewPort.
228      * 
229      * @param view The post ViewPort to remove
230      * @return True if the ViewPort was removed successfully.
231      * 
232      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera) 
233      */
234     public boolean removePostView(ViewPort view) {
235         return postViewPorts.remove(view);
236     }
237
238     /**
239      * Returns a read-only list of all pre ViewPorts
240      * @return a read-only list of all pre ViewPorts
241      * @see #createPreView(java.lang.String, com.jme3.renderer.Camera) 
242      */
243     public List<ViewPort> getPreViews() {
244         return Collections.unmodifiableList(preViewPorts);
245     }
246
247     /**
248      * Returns a read-only list of all main ViewPorts
249      * @return a read-only list of all main ViewPorts
250      * @see #createMainView(java.lang.String, com.jme3.renderer.Camera) 
251      */
252     public List<ViewPort> getMainViews() {
253         return Collections.unmodifiableList(viewPorts);
254     }
255
256     /**
257      * Returns a read-only list of all post ViewPorts
258      * @return a read-only list of all post ViewPorts
259      * @see #createPostView(java.lang.String, com.jme3.renderer.Camera) 
260      */
261     public List<ViewPort> getPostViews() {
262         return Collections.unmodifiableList(postViewPorts);
263     }
264
265     /**
266      * Creates a new pre ViewPort, to display the given camera's content.
267      * <p>
268      * The view will be processed before the main and post viewports.
269      */
270     public ViewPort createPreView(String viewName, Camera cam) {
271         ViewPort vp = new ViewPort(viewName, cam);
272         preViewPorts.add(vp);
273         return vp;
274     }
275
276     /**
277      * Creates a new main ViewPort, to display the given camera's content.
278      * <p>
279      * The view will be processed before the post viewports but after
280      * the pre viewports.
281      */
282     public ViewPort createMainView(String viewName, Camera cam) {
283         ViewPort vp = new ViewPort(viewName, cam);
284         viewPorts.add(vp);
285         return vp;
286     }
287
288     /**
289      * Creates a new post ViewPort, to display the given camera's content.
290      * <p>
291      * The view will be processed after the pre and main viewports.
292      */
293     public ViewPort createPostView(String viewName, Camera cam) {
294         ViewPort vp = new ViewPort(viewName, cam);
295         postViewPorts.add(vp);
296         return vp;
297     }
298
299     private void notifyReshape(ViewPort vp, int w, int h) {
300         List<SceneProcessor> processors = vp.getProcessors();
301         for (SceneProcessor proc : processors) {
302             if (!proc.isInitialized()) {
303                 proc.initialize(this, vp);
304             } else {
305                 proc.reshape(vp, w, h);
306             }
307         }
308     }
309
310     /**
311      * Internal use only.
312      * Updates the resolution of all on-screen cameras to match
313      * the given width and height.
314      */
315     public void notifyReshape(int w, int h) {
316         for (ViewPort vp : preViewPorts) {
317             if (vp.getOutputFrameBuffer() == null) {
318                 Camera cam = vp.getCamera();
319                 cam.resize(w, h, true);
320             }
321             notifyReshape(vp, w, h);
322         }
323         for (ViewPort vp : viewPorts) {
324             if (vp.getOutputFrameBuffer() == null) {
325                 Camera cam = vp.getCamera();
326                 cam.resize(w, h, true);
327             }
328             notifyReshape(vp, w, h);
329         }
330         for (ViewPort vp : postViewPorts) {
331             if (vp.getOutputFrameBuffer() == null) {
332                 Camera cam = vp.getCamera();
333                 cam.resize(w, h, true);
334             }
335             notifyReshape(vp, w, h);
336         }
337     }
338
339     /**
340      * Internal use only.
341      * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
342      * based on the current world state.
343      */
344     public void updateUniformBindings(List<Uniform> params) {
345         // assums worldMatrix is properly set.
346         TempVars vars = TempVars.get();
347         assert vars.lock();
348
349         Matrix4f tempMat4 = vars.tempMat4;
350         Matrix3f tempMat3 = vars.tempMat3;
351         Vector2f tempVec2 = vars.vect2d;
352         Quaternion tempVec4 = vars.quat1;
353
354         for (int i = 0; i < params.size(); i++) {
355             Uniform u = params.get(i);
356             switch (u.getBinding()) {
357                 case WorldMatrix:
358                     u.setValue(VarType.Matrix4, worldMatrix);
359                     break;
360                 case ViewMatrix:
361                     u.setValue(VarType.Matrix4, viewMatrix);
362                     break;
363                 case ProjectionMatrix:
364                     u.setValue(VarType.Matrix4, projMatrix);
365                     break;
366                 case ViewProjectionMatrix:
367                     u.setValue(VarType.Matrix4, viewProjMatrix);
368                     break;
369                 case WorldViewMatrix:
370                     tempMat4.set(viewMatrix);
371                     tempMat4.multLocal(worldMatrix);
372                     u.setValue(VarType.Matrix4, tempMat4);
373                     break;
374                 case NormalMatrix:
375                     tempMat4.set(viewMatrix);
376                     tempMat4.multLocal(worldMatrix);
377                     tempMat4.toRotationMatrix(tempMat3);
378                     tempMat3.invertLocal();
379                     tempMat3.transposeLocal();
380                     u.setValue(VarType.Matrix3, tempMat3);
381                     break;
382                 case WorldViewProjectionMatrix:
383                     tempMat4.set(viewProjMatrix);
384                     tempMat4.multLocal(worldMatrix);
385                     u.setValue(VarType.Matrix4, tempMat4);
386                     break;
387                 case WorldMatrixInverse:
388                     tempMat4.multLocal(worldMatrix);
389                     tempMat4.invertLocal();
390                     u.setValue(VarType.Matrix4, tempMat4);
391                     break;
392                 case ViewMatrixInverse:
393                     tempMat4.set(viewMatrix);
394                     tempMat4.invertLocal();
395                     u.setValue(VarType.Matrix4, tempMat4);
396                     break;
397                 case ProjectionMatrixInverse:
398                     tempMat4.set(projMatrix);
399                     tempMat4.invertLocal();
400                     u.setValue(VarType.Matrix4, tempMat4);
401                     break;
402                 case ViewProjectionMatrixInverse:
403                     tempMat4.set(viewProjMatrix);
404                     tempMat4.invertLocal();
405                     u.setValue(VarType.Matrix4, tempMat4);
406                     break;
407                 case WorldViewMatrixInverse:
408                     tempMat4.set(viewMatrix);
409                     tempMat4.multLocal(worldMatrix);
410                     tempMat4.invertLocal();
411                     u.setValue(VarType.Matrix4, tempMat4);
412                     break;
413                 case NormalMatrixInverse:
414                     tempMat4.set(viewMatrix);
415                     tempMat4.multLocal(worldMatrix);
416                     tempMat4.toRotationMatrix(tempMat3);
417                     tempMat3.invertLocal();
418                     tempMat3.transposeLocal();
419                     tempMat3.invertLocal();
420                     u.setValue(VarType.Matrix3, tempMat3);
421                     break;
422                 case WorldViewProjectionMatrixInverse:
423                     tempMat4.set(viewProjMatrix);
424                     tempMat4.multLocal(worldMatrix);
425                     tempMat4.invertLocal();
426                     u.setValue(VarType.Matrix4, tempMat4);
427                     break;
428                 case ViewPort:
429                     tempVec4.set(viewX, viewY, viewWidth, viewHeight);
430                     u.setValue(VarType.Vector4, tempVec4);
431                     break;
432                 case Resolution:
433                     tempVec2.set(viewWidth, 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         assert vars.unlock();
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 (Entry<VertexBuffer> entry : mesh.getBuffers()) {
734                     VertexBuffer buf = entry.getValue();
735                     if (buf.getData() != null) {
736                         renderer.updateBufferData(buf);
737                     }
738                 }
739             }
740         }
741     }
742
743     /**
744      * Flattens the given scene graph into the ViewPort's RenderQueue,
745      * checking for culling as the call goes down the graph recursively.
746      * <p>
747      * First, the scene is checked for culling based on the <code>Spatial</code>s
748      * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
749      * if the camera frustum contains the scene, then this method is recursively
750      * called on its children.
751      * <p>
752      * When the scene's leaves or {@link Geometry geometries} are reached,
753      * they are each enqueued into the 
754      * {@link ViewPort#getQueue() ViewPort's render queue}.
755      * <p>
756      * In addition to enqueuing the visible geometries, this method
757      * also scenes which cast or receive shadows, by putting them into the
758      * RenderQueue's 
759      * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode) 
760      * shadow queue}. Each Spatial which has its 
761      * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
762      * set to not off, will be put into the appropriate shadow queue, note that
763      * this process does not check for frustum culling on any 
764      * {@link ShadowMode#Cast shadow casters}, as they don't have to be
765      * in the eye camera frustum to cast shadows on objects that are inside it.
766      * 
767      * @param scene The scene to flatten into the queue
768      * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
769      * used for culling and the {@link ViewPort#getQueue() queue} used to 
770      * contain the flattened scene graph.
771      */
772     public void renderScene(Spatial scene, ViewPort vp) {
773         if (scene.getParent() == null) {
774             vp.getCamera().setPlaneState(0);
775         }
776         // check culling first.
777         if (!scene.checkCulling(vp.getCamera())) {
778             // move on to shadow-only render
779             if (scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) {
780                 renderShadow(scene, vp.getQueue());
781             }
782             return;
783         }
784
785         scene.runControlRender(this, vp);
786         if (scene instanceof Node) {
787             // recurse for all children
788             Node n = (Node) scene;
789             List<Spatial> children = n.getChildren();
790             //saving cam state for culling
791             int camState = vp.getCamera().getPlaneState();
792             for (int i = 0; i < children.size(); i++) {
793                 //restoring cam state before proceeding children recusively
794                 vp.getCamera().setPlaneState(camState);
795                 renderScene(children.get(i), vp);
796
797             }
798         } else if (scene instanceof Geometry) {
799
800             // add to the render queue
801             Geometry gm = (Geometry) scene;
802             if (gm.getMaterial() == null) {
803                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
804             }
805
806             vp.getQueue().addToQueue(gm, scene.getQueueBucket());
807
808             // add to shadow queue if needed
809             RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
810             if (shadowMode != RenderQueue.ShadowMode.Off) {
811                 vp.getQueue().addToShadowQueue(gm, shadowMode);
812             }
813         }
814     }
815
816     /**
817      * Returns the camera currently used for rendering.
818      * <p>
819      * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
820      * 
821      * @return the camera currently used for rendering.
822      */
823     public Camera getCurrentCamera() {
824         return prevCam;
825     }
826
827     /**
828      * The renderer implementation used for rendering operations.
829      * 
830      * @return The renderer implementation
831      * 
832      * @see #RenderManager(com.jme3.renderer.Renderer) 
833      * @see Renderer
834      */
835     public Renderer getRenderer() {
836         return renderer;
837     }
838
839     /**
840      * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
841      * by rendering each of its visible buckets.
842      * By default the queues will automatically be cleared after rendering,
843      * so there's no need to clear them manually.
844      * 
845      * @param vp The ViewPort of which the queue will be flushed
846      * 
847      * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera) 
848      * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList) 
849      */
850     public void flushQueue(ViewPort vp) {
851         renderViewPortQueues(vp, true);
852     }
853
854     /**
855      * Clears the queue of the given ViewPort.
856      * Simply calls {@link RenderQueue#clear() } on the ViewPort's 
857      * {@link ViewPort#getQueue() render queue}.
858      * 
859      * @param vp The ViewPort of which the queue will be cleared.
860      * 
861      * @see RenderQueue#clear()
862      * @see ViewPort#getQueue()
863      */
864     public void clearQueue(ViewPort vp) {
865         vp.getQueue().clear();
866     }
867
868     /**
869      * Render the given viewport queues.
870      * <p>
871      * Changes the {@link Renderer#setDepthRange(float, float) depth range}
872      * appropriately as expected by each queue and then calls 
873      * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
874      * on the queue. Makes sure to restore the depth range to [0, 1] 
875      * at the end of the call.
876      * Note that the {@link Bucket#Translucent translucent bucket} is NOT
877      * rendered by this method. Instead the user should call 
878      * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
879      * after this call.
880      * 
881      * @param vp the viewport of which queue should be rendered
882      * @param flush If true, the queues will be cleared after
883      * rendering.
884      * 
885      * @see RenderQueue
886      * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort) 
887      */
888     public void renderViewPortQueues(ViewPort vp, boolean flush) {
889         RenderQueue rq = vp.getQueue();
890         Camera cam = vp.getCamera();
891         boolean depthRangeChanged = false;
892
893         // render opaque objects with default depth range
894         // opaque objects are sorted front-to-back, reducing overdraw
895         rq.renderQueue(Bucket.Opaque, this, cam, flush);
896
897         // render the sky, with depth range set to the farthest
898         if (!rq.isQueueEmpty(Bucket.Sky)) {
899             renderer.setDepthRange(1, 1);
900             rq.renderQueue(Bucket.Sky, this, cam, flush);
901             depthRangeChanged = true;
902         }
903
904
905         // transparent objects are last because they require blending with the
906         // rest of the scene's objects. Consequently, they are sorted
907         // back-to-front.
908         if (!rq.isQueueEmpty(Bucket.Transparent)) {
909             if (depthRangeChanged) {
910                 renderer.setDepthRange(0, 1);
911                 depthRangeChanged = false;
912             }
913
914             rq.renderQueue(Bucket.Transparent, this, cam, flush);
915         }
916
917         if (!rq.isQueueEmpty(Bucket.Gui)) {
918             renderer.setDepthRange(0, 0);
919             setCamera(cam, true);
920             rq.renderQueue(Bucket.Gui, this, cam, flush);
921             setCamera(cam, false);
922             depthRangeChanged = true;
923         }
924
925         // restore range to default
926         if (depthRangeChanged) {
927             renderer.setDepthRange(0, 1);
928         }
929     }
930
931     /**
932      * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
933      * <p>
934      * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
935      * is set to true. This method clears the translucent queue after rendering
936      * it.
937      * 
938      * @param vp The viewport of which the translucent queue should be rendered.
939      * 
940      * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) 
941      * @see #setHandleTranslucentBucket(boolean) 
942      */
943     public void renderTranslucentQueue(ViewPort vp) {
944         RenderQueue rq = vp.getQueue();
945         if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
946             rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
947         }
948     }
949
950     private void setViewPort(Camera cam) {
951         // this will make sure to update viewport only if needed
952         if (cam != prevCam || cam.isViewportChanged()) {
953             viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
954             viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
955             viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
956             viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
957             renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
958             renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
959             cam.clearViewportChanged();
960             prevCam = cam;
961
962 //            float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
963 //            float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
964 //            float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
965 //            float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
966 //            
967 //            orthoMatrix.loadIdentity();
968 //            orthoMatrix.setTranslation(translateX, translateY, 0);
969 //            orthoMatrix.setScale(scaleX, scaleY, 0); 
970
971             orthoMatrix.loadIdentity();
972             orthoMatrix.setTranslation(-1f, -1f, 0f);
973             orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
974         }
975     }
976
977     private void setViewProjection(Camera cam, boolean ortho) {
978         if (shader) {
979             if (ortho) {
980                 viewMatrix.set(Matrix4f.IDENTITY);
981                 projMatrix.set(orthoMatrix);
982                 viewProjMatrix.set(orthoMatrix);
983             } else {
984                 viewMatrix.set(cam.getViewMatrix());
985                 projMatrix.set(cam.getProjectionMatrix());
986                 viewProjMatrix.set(cam.getViewProjectionMatrix());
987             }
988
989             camLoc.set(cam.getLocation());
990             cam.getLeft(camLeft);
991             cam.getUp(camUp);
992             cam.getDirection(camDir);
993
994             near = cam.getFrustumNear();
995             far = cam.getFrustumFar();
996         } else {
997             if (ortho) {
998                 renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
999             } else {
1000                 renderer.setViewProjectionMatrices(cam.getViewMatrix(),
1001                         cam.getProjectionMatrix());
1002             }
1003
1004         }
1005     }
1006
1007     /**
1008      * Set the camera to use for rendering.
1009      * <p>
1010      * First, the camera's 
1011      * {@link Camera#setViewPort(float, float, float, float) view port parameters}
1012      * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and 
1013      * {@link Camera#getProjectionMatrix() projection} matrices are set
1014      * on the renderer. If <code>ortho</code> is <code>true</code>, then
1015      * instead of using the camera's view and projection matrices, an ortho
1016      * matrix is computed and used instead of the view projection matrix. 
1017      * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
1018      * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
1019      * 
1020      * @param cam The camera to set
1021      * @param ortho True if to use orthographic projection (for GUI rendering),
1022      * false if to use the camera's view and projection matrices.
1023      */
1024     public void setCamera(Camera cam, boolean ortho) {
1025         setViewPort(cam);
1026         setViewProjection(cam, ortho);
1027     }
1028
1029     /**
1030      * Draws the viewport but without notifying {@link SceneProcessor scene
1031      * processors} of any rendering events.
1032      * 
1033      * @param vp The ViewPort to render
1034      * 
1035      * @see #renderViewPort(com.jme3.renderer.ViewPort, float) 
1036      */
1037     public void renderViewPortRaw(ViewPort vp) {
1038         setCamera(vp.getCamera(), false);
1039         List<Spatial> scenes = vp.getScenes();
1040         for (int i = scenes.size() - 1; i >= 0; i--) {
1041             renderScene(scenes.get(i), vp);
1042         }
1043         flushQueue(vp);
1044     }
1045
1046     /**
1047      * Renders the {@link ViewPort}.
1048      * <p>
1049      * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
1050      * returns immediately. Otherwise, the ViewPort is rendered by 
1051      * the following process:<br>
1052      * <ul>
1053      * <li>All {@link SceneProcessor scene processors} that are attached
1054      * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
1055      * </li>
1056      * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method 
1057      * is called.</li>
1058      * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
1059      * is set on the Renderer</li>
1060      * <li>The camera is set on the renderer, including its view port parameters.
1061      * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
1062      * <li>Any buffers that the ViewPort requests to be cleared are cleared
1063      * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
1064      * <li>Every scene that is attached to the ViewPort is flattened into 
1065      * the ViewPort's render queue 
1066      * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
1067      * </li>
1068      * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
1069      * method is called.</li>
1070      * <li>The render queue is sorted and then flushed, sending
1071      * rendering commands to the underlying Renderer implementation. 
1072      * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
1073      * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
1074      * method is called.</li>
1075      * <li>The translucent queue of the ViewPort is sorted and then flushed
1076      * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
1077      * <li>If any objects remained in the render queue, they are removed
1078      * from the queue. This is generally objects added to the 
1079      * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) 
1080      * shadow queue}
1081      * which were not rendered because of a missing shadow renderer.</li>
1082      * </ul>
1083      * 
1084      * @param vp
1085      * @param tpf 
1086      */
1087     public void renderViewPort(ViewPort vp, float tpf) {
1088         if (!vp.isEnabled()) {
1089             return;
1090         }
1091         List<SceneProcessor> processors = vp.getProcessors();
1092         if (processors.isEmpty()) {
1093             processors = null;
1094         }
1095
1096         if (processors != null) {
1097             for (SceneProcessor proc : processors) {
1098                 if (!proc.isInitialized()) {
1099                     proc.initialize(this, vp);
1100                 }
1101                 proc.preFrame(tpf);
1102             }
1103         }
1104
1105         renderer.setFrameBuffer(vp.getOutputFrameBuffer());
1106         setCamera(vp.getCamera(), false);
1107         if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
1108             if (vp.isClearColor()) {
1109                 renderer.setBackgroundColor(vp.getBackgroundColor());
1110             }
1111             renderer.clearBuffers(vp.isClearColor(),
1112                     vp.isClearDepth(),
1113                     vp.isClearStencil());
1114         }
1115
1116         List<Spatial> scenes = vp.getScenes();
1117         for (int i = scenes.size() - 1; i >= 0; i--) {
1118             renderScene(scenes.get(i), vp);
1119         }
1120
1121         if (processors != null) {
1122             for (SceneProcessor proc : processors) {
1123                 proc.postQueue(vp.getQueue());
1124             }
1125         }
1126
1127         flushQueue(vp);
1128
1129         if (processors != null) {
1130             for (SceneProcessor proc : processors) {
1131                 proc.postFrame(vp.getOutputFrameBuffer());
1132             }
1133         }
1134         //renders the translucent objects queue after processors have been rendered
1135         renderTranslucentQueue(vp);
1136         // clear any remaining spatials that were not rendered.
1137         clearQueue(vp);
1138     }
1139
1140     /**
1141      * Called by the application to render any ViewPorts
1142      * added to this RenderManager.
1143      * <p>
1144      * Renders any viewports that were added using the following methods:
1145      * <ul>
1146      * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
1147      * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
1148      * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
1149      * </ul>
1150      * 
1151      * @param tpf Time per frame value
1152      */
1153     public void render(float tpf) {
1154         if (renderer instanceof NullRenderer) {
1155             return;
1156         }
1157
1158         this.shader = renderer.getCaps().contains(Caps.GLSL100);
1159
1160         for (int i = 0; i < preViewPorts.size(); i++) {
1161             renderViewPort(preViewPorts.get(i), tpf);
1162         }
1163         for (int i = 0; i < viewPorts.size(); i++) {
1164             renderViewPort(viewPorts.get(i), tpf);
1165         }
1166         for (int i = 0; i < postViewPorts.size(); i++) {
1167             renderViewPort(postViewPorts.get(i), tpf);
1168         }
1169     }
1170
1171 }