OSDN Git Service

Properly use bitmasks on camera for checking culling ( to avoid checking against...
[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.RenderState;
36 import com.jme3.math.Matrix3f;
37 import com.jme3.math.Matrix4f;
38 import com.jme3.math.Quaternion;
39 import com.jme3.math.Vector2f;
40 import com.jme3.math.Vector3f;
41 import com.jme3.post.SceneProcessor;
42 import com.jme3.renderer.queue.GeometryList;
43 import com.jme3.renderer.queue.RenderQueue;
44 import com.jme3.renderer.queue.RenderQueue.Bucket;
45 import com.jme3.scene.Geometry;
46 import com.jme3.scene.Mesh;
47 import com.jme3.scene.Node;
48 import com.jme3.scene.Spatial;
49 import com.jme3.scene.VertexBuffer;
50 import com.jme3.shader.Uniform;
51 import com.jme3.shader.VarType;
52 import com.jme3.system.NullRenderer;
53 import com.jme3.system.Timer;
54 import com.jme3.util.IntMap.Entry;
55 import com.jme3.util.TempVars;
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.logging.Logger;
60
61 /**
62  * <code>RenderManager</code> is a high-level rendering interface that is
63  * above the Renderer implementation. RenderManager takes care
64  * of rendering the scene graphs attached to each viewport and
65  * handling SceneProcessors.
66  *
67  * @see SceneProcessor
68  * @see ViewPort
69  * @see Spatial
70  */
71 public class RenderManager {
72
73     private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
74     private Renderer renderer;
75     private Timer timer;
76     private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
77     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
78     private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
79     private Camera prevCam = null;
80     private Material forcedMaterial = null;
81     private String forcedTechnique = null;
82     private RenderState forcedRenderState = null;
83     private boolean shader;
84     private int viewX, viewY, viewWidth, viewHeight;
85     private float near, far;
86     private Matrix4f orthoMatrix = new Matrix4f();
87     private Matrix4f viewMatrix = new Matrix4f();
88     private Matrix4f projMatrix = new Matrix4f();
89     private Matrix4f viewProjMatrix = new Matrix4f();
90     private Matrix4f worldMatrix = new Matrix4f();
91     private Vector3f camUp = new Vector3f(),
92             camLeft = new Vector3f(),
93             camDir = new Vector3f(),
94             camLoc = new Vector3f();
95     //temp technique
96     private String tmpTech;
97
98     /**
99      * Create a high-level rendering interface over the
100      * low-level rendering interface.
101      * @param renderer
102      */
103     public RenderManager(Renderer renderer) {
104         this.renderer = renderer;
105         //this.shader = renderer.getCaps().contains(Caps.GLSL100);
106     }
107
108     public ViewPort getPreView(String viewName) {
109         for (int i = 0; i < preViewPorts.size(); i++) {
110             if (preViewPorts.get(i).getName().equals(viewName)) {
111                 return preViewPorts.get(i);
112             }
113         }
114         return null;
115     }
116
117     public boolean removePreView(ViewPort view) {
118         return preViewPorts.remove(view);
119     }
120
121     public ViewPort getMainView(String viewName) {
122         for (int i = 0; i < viewPorts.size(); i++) {
123             if (viewPorts.get(i).getName().equals(viewName)) {
124                 return viewPorts.get(i);
125             }
126         }
127         return null;
128     }
129
130     public boolean removeMainView(String viewName) {
131         for (int i = 0; i < viewPorts.size(); i++) {
132             if (viewPorts.get(i).getName().equals(viewName)) {
133                 viewPorts.remove(i);
134                 return true;
135             }
136         }
137         return false;
138     }
139
140     public boolean removeMainView(ViewPort view) {
141         return viewPorts.remove(view);
142     }
143
144     public ViewPort getPostView(String viewName) {
145         for (int i = 0; i < postViewPorts.size(); i++) {
146             if (postViewPorts.get(i).getName().equals(viewName)) {
147                 return postViewPorts.get(i);
148             }
149         }
150         return null;
151     }
152
153     public boolean removePostView(String viewName) {
154         for (int i = 0; i < postViewPorts.size(); i++) {
155             if (postViewPorts.get(i).getName().equals(viewName)) {
156                 postViewPorts.remove(i);
157
158                 return true;
159             }
160         }
161         return false;
162     }
163
164     public boolean removePostView(ViewPort view) {
165         return postViewPorts.remove(view);
166     }
167
168     public List<ViewPort> getPreViews() {
169         return Collections.unmodifiableList(preViewPorts);
170     }
171
172     public List<ViewPort> getMainViews() {
173         return Collections.unmodifiableList(viewPorts);
174     }
175
176     public List<ViewPort> getPostViews() {
177         return Collections.unmodifiableList(postViewPorts);
178     }
179
180     /**
181      * Creates a new viewport, to display the given camera's content.
182      * The view will be processed before the primary viewport.
183      * @param viewName
184      * @param cam
185      * @return
186      */
187     public ViewPort createPreView(String viewName, Camera cam) {
188         ViewPort vp = new ViewPort(viewName, cam);
189         preViewPorts.add(vp);
190         return vp;
191     }
192
193     public ViewPort createMainView(String viewName, Camera cam) {
194         ViewPort vp = new ViewPort(viewName, cam);
195         viewPorts.add(vp);
196         return vp;
197     }
198
199     public ViewPort createPostView(String viewName, Camera cam) {
200         ViewPort vp = new ViewPort(viewName, cam);
201         postViewPorts.add(vp);
202         return vp;
203     }
204
205     private void notifyReshape(ViewPort vp, int w, int h) {
206         List<SceneProcessor> processors = vp.getProcessors();
207         for (SceneProcessor proc : processors) {
208             if (!proc.isInitialized()) {
209                 proc.initialize(this, vp);
210             } else {
211                 proc.reshape(vp, w, h);
212             }
213         }
214     }
215
216     /**
217      * @param w
218      * @param h
219      */
220     public void notifyReshape(int w, int h) {
221         for (ViewPort vp : preViewPorts) {
222             if (vp.getOutputFrameBuffer() == null) {
223                 Camera cam = vp.getCamera();
224                 cam.resize(w, h, true);
225             }
226             notifyReshape(vp, w, h);
227         }
228         for (ViewPort vp : viewPorts) {
229             if (vp.getOutputFrameBuffer() == null) {
230                 Camera cam = vp.getCamera();
231                 cam.resize(w, h, true);
232             }
233             notifyReshape(vp, w, h);
234         }
235         for (ViewPort vp : postViewPorts) {
236             if (vp.getOutputFrameBuffer() == null) {
237                 Camera cam = vp.getCamera();
238                 cam.resize(w, h, true);
239             }
240             notifyReshape(vp, w, h);
241         }
242     }
243
244     public void updateUniformBindings(List<Uniform> params) {
245         // assums worldMatrix is properly set.
246         TempVars vars = TempVars.get();
247         assert vars.lock();
248
249         Matrix4f tempMat4 = vars.tempMat4;
250         Matrix3f tempMat3 = vars.tempMat3;
251         Vector2f tempVec2 = vars.vect2d;
252         Quaternion tempVec4 = vars.quat1;
253
254         for (int i = 0; i < params.size(); i++) {
255             Uniform u = params.get(i);
256             switch (u.getBinding()) {
257                 case WorldMatrix:
258                     u.setValue(VarType.Matrix4, worldMatrix);
259                     break;
260                 case ViewMatrix:
261                     u.setValue(VarType.Matrix4, viewMatrix);
262                     break;
263                 case ProjectionMatrix:
264                     u.setValue(VarType.Matrix4, projMatrix);
265                     break;
266                 case ViewProjectionMatrix:
267                     u.setValue(VarType.Matrix4, viewProjMatrix);
268                     break;
269                 case WorldViewMatrix:
270                     tempMat4.set(viewMatrix);
271                     tempMat4.multLocal(worldMatrix);
272                     u.setValue(VarType.Matrix4, tempMat4);
273                     break;
274                 case NormalMatrix:
275                     tempMat4.set(viewMatrix);
276                     tempMat4.multLocal(worldMatrix);
277                     tempMat4.toRotationMatrix(tempMat3);
278                     tempMat3.invertLocal();
279                     tempMat3.transposeLocal();
280                     u.setValue(VarType.Matrix3, tempMat3);
281                     break;
282                 case WorldViewProjectionMatrix:
283                     tempMat4.set(viewProjMatrix);
284                     tempMat4.multLocal(worldMatrix);
285                     u.setValue(VarType.Matrix4, tempMat4);
286                     break;
287                 case WorldMatrixInverse:
288                     tempMat4.multLocal(worldMatrix);
289                     tempMat4.invertLocal();
290                     u.setValue(VarType.Matrix4, tempMat4);
291                     break;
292                 case ViewMatrixInverse:
293                     tempMat4.set(viewMatrix);
294                     tempMat4.invertLocal();
295                     u.setValue(VarType.Matrix4, tempMat4);
296                     break;
297                 case ProjectionMatrixInverse:
298                     tempMat4.set(projMatrix);
299                     tempMat4.invertLocal();
300                     u.setValue(VarType.Matrix4, tempMat4);
301                     break;
302                 case ViewProjectionMatrixInverse:
303                     tempMat4.set(viewProjMatrix);
304                     tempMat4.invertLocal();
305                     u.setValue(VarType.Matrix4, tempMat4);
306                     break;
307                 case WorldViewMatrixInverse:
308                     tempMat4.set(viewMatrix);
309                     tempMat4.multLocal(worldMatrix);
310                     tempMat4.invertLocal();
311                     u.setValue(VarType.Matrix4, tempMat4);
312                     break;
313                 case NormalMatrixInverse:
314                     tempMat4.set(viewMatrix);
315                     tempMat4.multLocal(worldMatrix);
316                     tempMat4.toRotationMatrix(tempMat3);
317                     tempMat3.invertLocal();
318                     tempMat3.transposeLocal();
319                     tempMat3.invertLocal();
320                     u.setValue(VarType.Matrix3, tempMat3);
321                     break;
322                 case WorldViewProjectionMatrixInverse:
323                     tempMat4.set(viewProjMatrix);
324                     tempMat4.multLocal(worldMatrix);
325                     tempMat4.invertLocal();
326                     u.setValue(VarType.Matrix4, tempMat4);
327                     break;
328                 case ViewPort:
329                     tempVec4.set(viewX, viewY, viewWidth, viewHeight);
330                     u.setValue(VarType.Vector4, tempVec4);
331                     break;
332                 case Resolution:
333                     tempVec2.set(viewWidth, viewHeight);
334                     u.setValue(VarType.Vector2, tempVec2);
335                     break;
336                 case Aspect:
337                     float aspect = ((float) viewWidth) / viewHeight;
338                     u.setValue(VarType.Float, aspect);
339                     break;
340                 case FrustumNearFar:
341                     tempVec2.set(near, far);
342                     u.setValue(VarType.Vector2, tempVec2);
343                     break;
344                 case CameraPosition:
345                     u.setValue(VarType.Vector3, camLoc);
346                     break;
347                 case CameraDirection:
348                     u.setValue(VarType.Vector3, camDir);
349                     break;
350                 case CameraLeft:
351                     u.setValue(VarType.Vector3, camLeft);
352                     break;
353                 case CameraUp:
354                     u.setValue(VarType.Vector3, camUp);
355                     break;
356                 case Time:
357                     u.setValue(VarType.Float, timer.getTimeInSeconds());
358                     break;
359                 case Tpf:
360                     u.setValue(VarType.Float, timer.getTimePerFrame());
361                     break;
362                 case FrameRate:
363                     u.setValue(VarType.Float, timer.getFrameRate());
364                     break;
365             }
366         }
367
368         assert vars.unlock();
369     }
370
371     /**
372      * Set the material to use to render all future objects.
373      * This overrides the material set on the geometry and renders
374      * with the provided material instead.
375      * Use null to clear the material and return renderer to normal
376      * functionality.
377      * @param mat
378      */
379     public void setForcedMaterial(Material mat) {
380         forcedMaterial = mat;
381     }
382
383     public RenderState getForcedRenderState() {
384         return forcedRenderState;
385     }
386
387     public void setForcedRenderState(RenderState forcedRenderState) {
388         this.forcedRenderState = forcedRenderState;
389     }
390
391     public void setWorldMatrix(Matrix4f mat) {
392         if (shader) {
393             worldMatrix.set(mat);
394         } else {
395             renderer.setWorldMatrix(mat);
396         }
397     }
398
399     public void renderGeometry(Geometry g) {
400         if (g.isIgnoreTransform()) {
401             setWorldMatrix(Matrix4f.IDENTITY);
402         } else {
403             setWorldMatrix(g.getWorldMatrix());
404         }
405
406         //if forcedTechnique we try to force it for render,
407         //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
408         //else the geom is not rendered
409         if (forcedTechnique != null) {
410             if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
411                 tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
412                 g.getMaterial().selectTechnique(forcedTechnique, this);
413                 // use geometry's material
414                 g.getMaterial().render(g, this);
415                 g.getMaterial().selectTechnique(tmpTech, this);
416                 //Reverted this part from revision 6197
417                 //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
418             } else if (forcedMaterial != null) {
419                 // use forced material
420                 forcedMaterial.render(g, this);
421             }
422         } else if (forcedMaterial != null) {
423             // use forced material
424             forcedMaterial.render(g, this);
425         } else {
426             g.getMaterial().render(g, this);
427         }
428         //re applying default render state at the end of the render to avoid depth write issues, MUST BE A BETTER WAY
429         renderer.applyRenderState(RenderState.DEFAULT);
430     }
431
432     public void renderGeometryList(GeometryList gl) {
433         for (int i = 0; i < gl.size(); i++) {
434             renderGeometry(gl.get(i));
435         }
436     }
437
438     /**
439      * If a spatial is not inside the eye frustum, it
440      * is still rendered in the shadow frustum through this
441      * recursive method.
442      * @param s
443      * @param r
444      */
445     private void renderShadow(Spatial s, RenderQueue rq) {
446         if (s instanceof Node) {
447             Node n = (Node) s;
448             List<Spatial> children = n.getChildren();
449             for (int i = 0; i < children.size(); i++) {
450                 renderShadow(children.get(i), rq);
451             }
452         } else if (s instanceof Geometry) {
453             Geometry gm = (Geometry) s;
454
455             RenderQueue.ShadowMode shadowMode = s.getShadowMode();
456             if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
457                 //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
458                 rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
459             }
460         }
461     }
462
463     public void preloadScene(Spatial scene) {
464         if (scene instanceof Node) {
465             // recurse for all children
466             Node n = (Node) scene;
467             List<Spatial> children = n.getChildren();
468             for (int i = 0; i < children.size(); i++) {
469                 preloadScene(children.get(i));
470             }
471         } else if (scene instanceof Geometry) {
472             // add to the render queue
473             Geometry gm = (Geometry) scene;
474             if (gm.getMaterial() == null) {
475                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
476             }
477
478             gm.getMaterial().preload(this);
479             Mesh mesh = gm.getMesh();
480             if (mesh != null) {
481                 for (Entry<VertexBuffer> entry : mesh.getBuffers()) {
482                     VertexBuffer buf = entry.getValue();
483                     if (buf.getData() != null) {
484                         renderer.updateBufferData(buf);
485                     }
486                 }
487             }
488         }
489     }
490
491     /**
492      * Render scene graph
493      * @param s
494      * @param r
495      * @param cam
496      */
497     public void renderScene(Spatial scene, ViewPort vp) {
498         if (scene.getParent() == null) {
499             vp.getCamera().setPlaneState(0);
500         }
501         // check culling first.
502         if (!scene.checkCulling(vp.getCamera())) {
503             // move on to shadow-only render
504             if (scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) {
505                 renderShadow(scene, vp.getQueue());
506             }
507             return;
508         }
509
510         scene.runControlRender(this, vp);
511         if (scene instanceof Node) {
512             // recurse for all children
513             Node n = (Node) scene;
514             List<Spatial> children = n.getChildren();
515             //saving cam state for culling
516             int camState = vp.getCamera().getPlaneState();
517             for (int i = 0; i < children.size(); i++) {
518                 //restoring cam state before proceeding children recusively
519                 vp.getCamera().setPlaneState(camState);
520                 renderScene(children.get(i), vp);
521                
522             }
523         } else if (scene instanceof Geometry) {
524
525             // add to the render queue
526             Geometry gm = (Geometry) scene;
527             if (gm.getMaterial() == null) {
528                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
529             }
530
531             vp.getQueue().addToQueue(gm, scene.getQueueBucket());
532
533             // add to shadow queue if needed
534             RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
535             if (shadowMode != RenderQueue.ShadowMode.Off) {
536                 vp.getQueue().addToShadowQueue(gm, shadowMode);
537             }
538         }
539     }
540
541     public Camera getCurrentCamera() {
542         return prevCam;
543     }
544
545     public Renderer getRenderer() {
546         return renderer;
547     }
548
549     /**
550      * Render the given viewport queues, flushing the geometryList
551      * @param vp the viewport
552      */
553     public void flushQueue(ViewPort vp) {
554         renderViewPortQueues(vp, true);
555     }
556
557     public void clearQueue(ViewPort vp) {
558         vp.getQueue().clear();
559     }
560
561     //Nehon 08/18/2010 changed flushQueue to renderViewPortQueues with a flush boolean param
562     /**
563      * Render the given viewport queues
564      * @param vp the viewport
565      * @param flush true to flush geometryList
566      */
567     public void renderViewPortQueues(ViewPort vp, boolean flush) {
568         RenderQueue rq = vp.getQueue();
569         Camera cam = vp.getCamera();
570         boolean depthRangeChanged = false;
571
572         // render opaque objects with default depth range
573         // opaque objects are sorted front-to-back, reducing overdraw
574         rq.renderQueue(Bucket.Opaque, this, cam, flush);
575
576         // render the sky, with depth range set to the farthest
577         if (!rq.isQueueEmpty(Bucket.Sky)) {
578             renderer.setDepthRange(1, 1);
579             rq.renderQueue(Bucket.Sky, this, cam, flush);
580             depthRangeChanged = true;
581         }
582
583
584         // transparent objects are last because they require blending with the
585         // rest of the scene's objects. Consequently, they are sorted
586         // back-to-front.
587         if (!rq.isQueueEmpty(Bucket.Transparent)) {
588             if (depthRangeChanged) {
589                 renderer.setDepthRange(0, 1);
590                 depthRangeChanged = false;
591             }
592
593             rq.renderQueue(Bucket.Transparent, this, cam, flush);
594         }
595
596         if (!rq.isQueueEmpty(Bucket.Gui)) {
597             renderer.setDepthRange(0, 0);
598             setCamera(cam, true);
599             rq.renderQueue(Bucket.Gui, this, cam, flush);
600             setCamera(cam, false);
601             depthRangeChanged = true;
602         }
603
604         // restore range to default
605         if (depthRangeChanged) {
606             renderer.setDepthRange(0, 1);
607         }
608     }
609
610     private void setViewPort(Camera cam) {
611         // this will make sure to update viewport only if needed
612         if (cam != prevCam || cam.isViewportChanged()) {
613             viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
614             viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
615             viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
616             viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
617             renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
618             renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
619             cam.clearViewportChanged();
620             prevCam = cam;
621
622 //            float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
623 //            float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
624 //            float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
625 //            float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
626 //            
627 //            orthoMatrix.loadIdentity();
628 //            orthoMatrix.setTranslation(translateX, translateY, 0);
629 //            orthoMatrix.setScale(scaleX, scaleY, 0); 
630
631             orthoMatrix.loadIdentity();
632             orthoMatrix.setTranslation(-1f, -1f, 0f);
633             orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
634         }
635     }
636
637     private void setViewProjection(Camera cam, boolean ortho) {
638         if (shader) {
639             if (ortho) {
640                 viewMatrix.set(Matrix4f.IDENTITY);
641                 projMatrix.set(orthoMatrix);
642                 viewProjMatrix.set(orthoMatrix);
643             } else {
644                 viewMatrix.set(cam.getViewMatrix());
645                 projMatrix.set(cam.getProjectionMatrix());
646                 viewProjMatrix.set(cam.getViewProjectionMatrix());
647             }
648
649             camLoc.set(cam.getLocation());
650             cam.getLeft(camLeft);
651             cam.getUp(camUp);
652             cam.getDirection(camDir);
653
654             near = cam.getFrustumNear();
655             far = cam.getFrustumFar();
656         } else {
657             if (ortho) {
658                 renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
659             } else {
660                 renderer.setViewProjectionMatrices(cam.getViewMatrix(),
661                         cam.getProjectionMatrix());
662             }
663
664         }
665     }
666
667     public void setCamera(Camera cam, boolean ortho) {
668         setViewPort(cam);
669         setViewProjection(cam, ortho);
670     }
671
672     /**
673      * Draws the viewport but doesn't invoke processors.
674      * @param vp
675      */
676     public void renderViewPortRaw(ViewPort vp) {
677         setCamera(vp.getCamera(), false);
678         List<Spatial> scenes = vp.getScenes();
679         for (int i = scenes.size() - 1; i >= 0; i--) {
680             renderScene(scenes.get(i), vp);
681         }
682         flushQueue(vp);
683     }
684
685     public void renderViewPort(ViewPort vp, float tpf) {
686         if (!vp.isEnabled()) {
687             return;
688         }
689         List<SceneProcessor> processors = vp.getProcessors();
690         if (processors.size() == 0) {
691             processors = null;
692         }
693
694         if (processors != null) {
695             for (SceneProcessor proc : processors) {
696                 if (!proc.isInitialized()) {
697                     proc.initialize(this, vp);
698                 }
699                 proc.preFrame(tpf);
700             }
701         }
702
703         renderer.setFrameBuffer(vp.getOutputFrameBuffer());
704         setCamera(vp.getCamera(), false);
705         if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
706             if (vp.isClearColor()) {
707                 renderer.setBackgroundColor(vp.getBackgroundColor());
708             }
709             renderer.clearBuffers(vp.isClearColor(),
710                     vp.isClearDepth(),
711                     vp.isClearStencil());
712         }
713
714         List<Spatial> scenes = vp.getScenes();
715         for (int i = scenes.size() - 1; i >= 0; i--) {
716             renderScene(scenes.get(i), vp);
717         }
718
719         if (processors != null) {
720             for (SceneProcessor proc : processors) {
721                 proc.postQueue(vp.getQueue());
722             }
723         }
724
725         flushQueue(vp);
726
727         if (processors != null) {
728             for (SceneProcessor proc : processors) {
729                 proc.postFrame(vp.getOutputFrameBuffer());
730             }
731         }
732
733         // clear any remaining spatials that were not rendered.
734         clearQueue(vp);
735     }
736
737     public void render(float tpf) {
738         if (renderer instanceof NullRenderer) {
739             return;
740         }
741
742         this.shader = renderer.getCaps().contains(Caps.GLSL100);
743
744         for (int i = 0; i < preViewPorts.size(); i++) {
745             renderViewPort(preViewPorts.get(i), tpf);
746         }
747         for (int i = 0; i < viewPorts.size(); i++) {
748             renderViewPort(viewPorts.get(i), tpf);
749         }
750         for (int i = 0; i < postViewPorts.size(); i++) {
751             renderViewPort(postViewPorts.get(i), tpf);
752         }
753     }
754
755     //Remy - 09/14/2010 - added a setter for the timer in order to correctly populate g_Time and g_Tpf in the shaders
756     public void setTimer(Timer timer) {
757         this.timer = timer;
758     }
759
760     public String getForcedTechnique() {
761         return forcedTechnique;
762     }
763
764     public void setForcedTechnique(String forcedTechnique) {
765         this.forcedTechnique = forcedTechnique;
766     }
767
768     public void setAlphaToCoverage(boolean value) {
769         renderer.setAlphaToCoverage(value);
770     }
771 }