OSDN Git Service

* Fixed issue where Nifty GUI would consume all mouse button events
[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                 case AmbientLightColor:
366                     break;
367             }
368         }
369
370         assert vars.unlock();
371     }
372
373     /**
374      * Set the material to use to render all future objects.
375      * This overrides the material set on the geometry and renders
376      * with the provided material instead.
377      * Use null to clear the material and return renderer to normal
378      * functionality.
379      * @param mat
380      */
381     public void setForcedMaterial(Material mat) {
382         forcedMaterial = mat;
383     }
384
385     public RenderState getForcedRenderState() {
386         return forcedRenderState;
387     }
388
389     public void setForcedRenderState(RenderState forcedRenderState) {
390         this.forcedRenderState = forcedRenderState;
391     }
392
393     public void setWorldMatrix(Matrix4f mat) {
394         if (shader) {
395             worldMatrix.set(mat);
396         } else {
397             renderer.setWorldMatrix(mat);
398         }
399     }
400
401     public void renderGeometry(Geometry g) {
402         if (g.isIgnoreTransform()) {
403             setWorldMatrix(Matrix4f.IDENTITY);
404         } else {
405             setWorldMatrix(g.getWorldMatrix());
406         }
407
408         //if forcedTechnique we try to force it for render,
409         //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
410         //else the geom is not rendered
411         if (forcedTechnique != null) {
412             if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
413                 tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
414                 g.getMaterial().selectTechnique(forcedTechnique, this);
415                 // use geometry's material
416                 g.getMaterial().render(g, this);
417                 g.getMaterial().selectTechnique(tmpTech, this);
418                 //Reverted this part from revision 6197
419                 //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
420             } else if (forcedMaterial != null) {
421                 // use forced material
422                 forcedMaterial.render(g, this);
423             }
424         } else if (forcedMaterial != null) {
425             // use forced material
426             forcedMaterial.render(g, this);
427         } else {            
428             g.getMaterial().render(g, this);
429         }
430         //re applying default render state at the end of the render to avoid depth write issues, MUST BE A BETTER WAY
431         renderer.applyRenderState(RenderState.DEFAULT);
432     }
433
434     public void renderGeometryList(GeometryList gl) {
435         for (int i = 0; i < gl.size(); i++) {
436             renderGeometry(gl.get(i));
437         }
438
439     }
440
441     /**
442      * If a spatial is not inside the eye frustum, it
443      * is still rendered in the shadow frustum through this
444      * recursive method.
445      * @param s
446      * @param r
447      */
448     private void renderShadow(Spatial s, RenderQueue rq) {
449         if (s instanceof Node) {
450             Node n = (Node) s;
451             List<Spatial> children = n.getChildren();
452             for (int i = 0; i < children.size(); i++) {
453                 renderShadow(children.get(i), rq);
454             }
455         } else if (s instanceof Geometry) {
456             Geometry gm = (Geometry) s;
457
458             RenderQueue.ShadowMode shadowMode = s.getShadowMode();
459             if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
460                 //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
461                 rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
462             }
463         }
464     }
465
466     public void preloadScene(Spatial scene) {
467         if (scene instanceof Node) {
468             // recurse for all children
469             Node n = (Node) scene;
470             List<Spatial> children = n.getChildren();
471             for (int i = 0; i < children.size(); i++) {
472                 preloadScene(children.get(i));
473             }
474         } else if (scene instanceof Geometry) {
475             // add to the render queue
476             Geometry gm = (Geometry) scene;
477             if (gm.getMaterial() == null) {
478                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
479             }
480
481             gm.getMaterial().preload(this);
482             Mesh mesh = gm.getMesh();
483             if (mesh != null) {
484                 for (Entry<VertexBuffer> entry : mesh.getBuffers()) {
485                     VertexBuffer buf = entry.getValue();
486                     if (buf.getData() != null) {
487                         renderer.updateBufferData(buf);
488                     }
489                 }
490             }
491         }
492     }
493
494     /**
495      * Render scene graph
496      * @param s
497      * @param r
498      * @param cam
499      */
500     public void renderScene(Spatial scene, ViewPort vp) {
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             for (int i = 0; i < children.size(); i++) {
516                 renderScene(children.get(i), vp);
517             }
518         } else if (scene instanceof Geometry) {
519
520             // add to the render queue
521             Geometry gm = (Geometry) scene;
522             if (gm.getMaterial() == null) {
523                 throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
524             }
525
526             vp.getQueue().addToQueue(gm, scene.getQueueBucket());
527
528             // add to shadow queue if needed
529             RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
530             if (shadowMode != RenderQueue.ShadowMode.Off) {
531                 vp.getQueue().addToShadowQueue(gm, shadowMode);
532             }
533         }
534     }
535
536     public Camera getCurrentCamera() {
537         return prevCam;
538     }
539
540     public Renderer getRenderer() {
541         return renderer;
542     }
543
544     /**
545      * Render the given viewport queues, flushing the geometryList
546      * @param vp the viewport
547      */
548     public void flushQueue(ViewPort vp) {
549         renderViewPortQueues(vp, true);
550     }
551
552     public void clearQueue(ViewPort vp) {
553         vp.getQueue().clear();
554     }
555
556     //Nehon 08/18/2010 changed flushQueue to renderViewPortQueues with a flush boolean param
557     /**
558      * Render the given viewport queues
559      * @param vp the viewport
560      * @param flush true to flush geometryList
561      */
562     public void renderViewPortQueues(ViewPort vp, boolean flush) {
563         RenderQueue rq = vp.getQueue();
564         Camera cam = vp.getCamera();
565         boolean depthRangeChanged = false;
566
567         // render opaque objects with default depth range
568         // opaque objects are sorted front-to-back, reducing overdraw
569         rq.renderQueue(Bucket.Opaque, this, cam, flush);
570
571         // render the sky, with depth range set to the farthest
572         if (!rq.isQueueEmpty(Bucket.Sky)) {
573             renderer.setDepthRange(1, 1);
574             rq.renderQueue(Bucket.Sky, this, cam, flush);
575             depthRangeChanged = true;
576         }
577
578
579         // transparent objects are last because they require blending with the
580         // rest of the scene's objects. Consequently, they are sorted
581         // back-to-front.
582         if (!rq.isQueueEmpty(Bucket.Transparent)) {
583             if (depthRangeChanged) {
584                 renderer.setDepthRange(0, 1);
585                 depthRangeChanged = false;
586             }
587
588             rq.renderQueue(Bucket.Transparent, this, cam, flush);
589         }
590
591         if (!rq.isQueueEmpty(Bucket.Gui)) {
592             renderer.setDepthRange(0, 0);
593             setCamera(cam, true);
594             rq.renderQueue(Bucket.Gui, this, cam, flush);
595             setCamera(cam, false);
596             depthRangeChanged = true;
597         }
598
599         // restore range to default
600         if (depthRangeChanged) {
601             renderer.setDepthRange(0, 1);
602         }
603     }
604
605     private void setViewPort(Camera cam) {
606         // this will make sure to update viewport only if needed
607         if (cam != prevCam || cam.isViewportChanged()) {
608             viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
609             viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
610             viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
611             viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
612             renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
613             renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
614             cam.clearViewportChanged();
615             prevCam = cam;
616
617             float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
618             float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
619             float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
620             float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
621             orthoMatrix.loadIdentity();
622             orthoMatrix.setTranslation(translateX, translateY, 0);
623             orthoMatrix.setScale(scaleX, scaleY, /*-1f*/ 0f);
624 //             System.out.println(orthoMatrix);
625         }
626     }
627
628     private void setViewProjection(Camera cam, boolean ortho) {
629         if (shader) {
630             if (ortho) {
631                 viewMatrix.set(Matrix4f.IDENTITY);
632                 projMatrix.set(orthoMatrix);
633                 viewProjMatrix.set(orthoMatrix);
634             } else {
635                 viewMatrix.set(cam.getViewMatrix());
636                 projMatrix.set(cam.getProjectionMatrix());
637                 viewProjMatrix.set(cam.getViewProjectionMatrix());
638             }
639
640
641             camLoc.set(cam.getLocation());
642             cam.getLeft(camLeft);
643             cam.getUp(camUp);
644             cam.getDirection(camDir);
645
646             near = cam.getFrustumNear();
647             far = cam.getFrustumFar();
648         } else {
649             if (ortho) {
650                 renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
651             } else {
652                 renderer.setViewProjectionMatrices(cam.getViewMatrix(),
653                         cam.getProjectionMatrix());
654             }
655
656         }
657     }
658
659     public void setCamera(Camera cam, boolean ortho) {
660         setViewPort(cam);
661         setViewProjection(cam, ortho);
662     }
663
664     /**
665      * Draws the viewport but doesn't invoke processors.
666      * @param vp
667      */
668     public void renderViewPortRaw(ViewPort vp) {
669         setCamera(vp.getCamera(), false);
670         List<Spatial> scenes = vp.getScenes();
671         for (int i = scenes.size() - 1; i >= 0; i--) {
672             renderScene(scenes.get(i), vp);
673         }
674         flushQueue(vp);
675     }
676
677     public void renderViewPort(ViewPort vp, float tpf) {
678         if (!vp.isEnabled()) {
679                 return;
680         }
681         List<SceneProcessor> processors = vp.getProcessors();
682         if (processors.size() == 0) {
683             processors = null;
684         }
685
686         if (processors != null) {
687             for (SceneProcessor proc : processors) {
688                 if (!proc.isInitialized()) {
689                     proc.initialize(this, vp);
690                 }
691                 proc.preFrame(tpf);
692             }
693         }
694
695         renderer.setFrameBuffer(vp.getOutputFrameBuffer());
696         setCamera(vp.getCamera(), false);
697         if (vp.isClearEnabled()) {
698             renderer.setBackgroundColor(vp.getBackgroundColor());
699             renderer.clearBuffers(vp.isClearColor(),
700                     vp.isClearDepth(),
701                     vp.isClearStencil());
702         }
703
704         List<Spatial> scenes = vp.getScenes();
705         for (int i = scenes.size() - 1; i >= 0; i--) {
706             renderScene(scenes.get(i), vp);
707         }
708
709         if (processors != null) {
710             for (SceneProcessor proc : processors) {
711                 proc.postQueue(vp.getQueue());
712             }
713         }
714
715         flushQueue(vp);
716
717         if (processors != null) {
718             for (SceneProcessor proc : processors) {
719                 proc.postFrame(vp.getOutputFrameBuffer());
720             }
721         }
722
723         // clear any remaining spatials that were not rendered.
724         clearQueue(vp);
725     }
726
727     public void render(float tpf) {
728         if (renderer instanceof NullRenderer) {
729             return;
730         }
731
732         this.shader = renderer.getCaps().contains(Caps.GLSL100);
733
734         for (int i = 0; i < preViewPorts.size(); i++) {
735             renderViewPort(preViewPorts.get(i), tpf);
736         }
737         for (int i = 0; i < viewPorts.size(); i++) {
738             renderViewPort(viewPorts.get(i), tpf);
739         }
740         for (int i = 0; i < postViewPorts.size(); i++) {
741             renderViewPort(postViewPorts.get(i), tpf);
742         }
743     }
744
745     //Remy - 09/14/2010 - added a setter for the timer in order to correctly populate g_Time and g_Tpf in the shaders
746     public void setTimer(Timer timer) {
747         this.timer = timer;
748     }
749
750     public String getForcedTechnique() {
751         return forcedTechnique;
752     }
753
754     public void setForcedTechnique(String forcedTechnique) {
755         this.forcedTechnique = forcedTechnique;
756     }
757
758     public void setAlphaToCoverage(boolean value) {
759         renderer.setAlphaToCoverage(value);
760     }
761 }