• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.post;
33 
34 import com.jme3.asset.AssetManager;
35 import com.jme3.export.*;
36 import com.jme3.material.Material;
37 import com.jme3.renderer.Caps;
38 import com.jme3.renderer.RenderManager;
39 import com.jme3.renderer.Renderer;
40 import com.jme3.renderer.ViewPort;
41 import com.jme3.texture.FrameBuffer;
42 import com.jme3.texture.Image.Format;
43 import com.jme3.texture.Texture;
44 import com.jme3.texture.Texture2D;
45 import java.io.IOException;
46 import java.util.Collection;
47 import java.util.Iterator;
48 import java.util.List;
49 
50 /**
51  * Filters are 2D effects applied to the rendered scene.<br>
52  * The filter is fed with the rendered scene image rendered in an offscreen frame buffer.<br>
53  * This texture is applied on a fullscreen quad, with a special material.<br>
54  * This material uses a shader that aplly the desired effect to the scene texture.<br>
55  * <br>
56  * This class is abstract, any Filter must extend it.<br>
57  * Any filter holds a frameBuffer and a texture<br>
58  * The getMaterial must return a Material that use a GLSL shader immplementing the desired effect<br>
59  *
60  * @author Rémy Bouquet aka Nehon
61  */
62 public abstract class Filter implements Savable {
63 
64 
65     private String name;
66     protected Pass defaultPass;
67     protected List<Pass> postRenderPasses;
68     protected Material material;
69     protected boolean enabled = true;
70     protected FilterPostProcessor processor;
71 
Filter(String name)72     public Filter(String name) {
73         this.name = name;
74     }
75 
76     /**
77      * Inner class Pass
78      * Pass are like filters in filters.
79      * Some filters will need multiple passes before the final render
80      */
81     public class Pass {
82 
83         protected FrameBuffer renderFrameBuffer;
84         protected Texture2D renderedTexture;
85         protected Texture2D depthTexture;
86         protected Material passMaterial;
87 
88         /**
89          * init the pass called internally
90          * @param renderer
91          * @param width
92          * @param height
93          * @param textureFormat
94          * @param depthBufferFormat
95          * @param numSamples
96          */
init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth)97         public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth) {
98             Collection<Caps> caps = renderer.getCaps();
99             if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) {
100                 renderFrameBuffer = new FrameBuffer(width, height, numSamples);
101                 renderedTexture = new Texture2D(width, height, numSamples, textureFormat);
102                 renderFrameBuffer.setDepthBuffer(depthBufferFormat);
103                 if (renderDepth) {
104                     depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat);
105                     renderFrameBuffer.setDepthTexture(depthTexture);
106                 }
107             } else {
108                 renderFrameBuffer = new FrameBuffer(width, height, 1);
109                 renderedTexture = new Texture2D(width, height, textureFormat);
110                 renderFrameBuffer.setDepthBuffer(depthBufferFormat);
111                 if (renderDepth) {
112                     depthTexture = new Texture2D(width, height, depthBufferFormat);
113                     renderFrameBuffer.setDepthTexture(depthTexture);
114                 }
115             }
116 
117             renderFrameBuffer.setColorTexture(renderedTexture);
118 
119 
120         }
121 
122         /**
123          *  init the pass called internally
124          * @param renderer
125          * @param width
126          * @param height
127          * @param textureFormat
128          * @param depthBufferFormat
129          */
init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat)130         public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) {
131             init(renderer, width, height, textureFormat, depthBufferFormat, 1);
132         }
133 
init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples)134         public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples) {
135             init(renderer, width, height, textureFormat, depthBufferFormat, numSamples, false);
136         }
137 
138         /**
139          *  init the pass called internally
140          * @param renderer
141          * @param width
142          * @param height
143          * @param textureFormat
144          * @param depthBufferFormat
145          * @param numSample
146          * @param material
147          */
init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material)148         public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material) {
149             init(renderer, width, height, textureFormat, depthBufferFormat, numSample);
150             passMaterial = material;
151         }
152 
requiresSceneAsTexture()153         public boolean requiresSceneAsTexture() {
154             return false;
155         }
156 
requiresDepthAsTexture()157         public boolean requiresDepthAsTexture() {
158             return false;
159         }
160 
beforeRender()161         public void beforeRender() {
162         }
163 
getRenderFrameBuffer()164         public FrameBuffer getRenderFrameBuffer() {
165             return renderFrameBuffer;
166         }
167 
setRenderFrameBuffer(FrameBuffer renderFrameBuffer)168         public void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
169             this.renderFrameBuffer = renderFrameBuffer;
170         }
171 
getDepthTexture()172         public Texture2D getDepthTexture() {
173             return depthTexture;
174         }
175 
getRenderedTexture()176         public Texture2D getRenderedTexture() {
177             return renderedTexture;
178         }
179 
setRenderedTexture(Texture2D renderedTexture)180         public void setRenderedTexture(Texture2D renderedTexture) {
181             this.renderedTexture = renderedTexture;
182         }
183 
getPassMaterial()184         public Material getPassMaterial() {
185             return passMaterial;
186         }
187 
setPassMaterial(Material passMaterial)188         public void setPassMaterial(Material passMaterial) {
189             this.passMaterial = passMaterial;
190         }
191 
cleanup(Renderer r)192         public void cleanup(Renderer r) {
193         }
194     }
195 
196     /**
197      * returns the default pass texture format
198      * @return
199      */
getDefaultPassTextureFormat()200     protected Format getDefaultPassTextureFormat() {
201         return Format.RGBA8;
202     }
203 
204     /**
205      * returns the default pass depth format
206      * @return
207      */
getDefaultPassDepthFormat()208     protected Format getDefaultPassDepthFormat() {
209         return Format.Depth;
210     }
211 
212     /**
213      * contruct a Filter
214      */
Filter()215     protected Filter() {
216         this("filter");
217     }
218 
219     /**
220      *
221      * initialize this filter
222      * use InitFilter for overriding filter initialization
223      * @param manager the assetManager
224      * @param renderManager the renderManager
225      * @param vp the viewport
226      * @param w the width
227      * @param h the height
228      */
init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h)229     protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
230         //  cleanup(renderManager.getRenderer());
231         defaultPass = new Pass();
232         defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat());
233         initFilter(manager, renderManager, vp, w, h);
234     }
235 
236     /**
237      * cleanup this filter
238      * @param r
239      */
cleanup(Renderer r)240     protected final void cleanup(Renderer r) {
241         processor = null;
242         if (defaultPass != null) {
243             defaultPass.cleanup(r);
244         }
245         if (postRenderPasses != null) {
246             for (Iterator<Pass> it = postRenderPasses.iterator(); it.hasNext();) {
247                 Pass pass = it.next();
248                 pass.cleanup(r);
249             }
250         }
251         cleanUpFilter(r);
252     }
253 
254     /**
255      * Initialization of sub classes filters
256      * This method is called once when the filter is added to the FilterPostProcessor
257      * It should contain Material initializations and extra passes initialization
258      * @param manager the assetManager
259      * @param renderManager the renderManager
260      * @param vp the viewPort where this filter is rendered
261      * @param w the width of the filter
262      * @param h the height of the filter
263      */
initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h)264     protected abstract void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h);
265 
266     /**
267      * override this method if you have some cleanup to do
268      * @param r the renderer
269      */
cleanUpFilter(Renderer r)270     protected void cleanUpFilter(Renderer r) {
271     }
272 
273     /**
274      * Must return the material used for this filter.
275      * this method is called every frame.
276      *
277      * @return the material used for this filter.
278      */
getMaterial()279     protected abstract Material getMaterial();
280 
281     /**
282      * Override if you want to do something special with the depth texture;
283      * @param depthTexture
284      */
setDepthTexture(Texture depthTexture)285     protected void setDepthTexture(Texture depthTexture){
286         getMaterial().setTexture("DepthTexture", depthTexture);
287     }
288 
289     /**
290      * Override this method if you want to make a pre pass, before the actual rendering of the frame
291      * @param renderManager
292      * @param viewPort
293      */
postQueue(RenderManager renderManager, ViewPort viewPort)294     protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
295     }
296 
297     /**
298      * Override this method if you want to modify parameters according to tpf before the rendering of the frame.
299      * This is usefull for animated filters
300      * Also it can be the place to render pre passes
301      * @param tpf the time used to render the previous frame
302      */
preFrame(float tpf)303     protected void preFrame(float tpf) {
304     }
305 
306     /**
307      * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering
308      * @param renderManager
309      * @param viewPort
310      * @param prevFilterBuffer
311      * @param sceneBuffer
312      */
postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer)313     protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
314     }
315 
316     /**
317      * Override this method if you want to save extra properties when the filter is saved else only basic properties of the filter will be saved
318      * This method should always begin by super.write(ex);
319      * @param ex
320      * @throws IOException
321      */
write(JmeExporter ex)322     public void write(JmeExporter ex) throws IOException {
323         OutputCapsule oc = ex.getCapsule(this);
324         oc.write(name, "name", "");
325         oc.write(enabled, "enabled", true);
326     }
327 
328     /**
329      * Override this method if you want to load extra properties when the filter
330      * is loaded else only basic properties of the filter will be loaded
331      * This method should always begin by super.read(im);
332      */
read(JmeImporter im)333     public void read(JmeImporter im) throws IOException {
334         InputCapsule ic = im.getCapsule(this);
335         name = ic.readString("name", "");
336         enabled = ic.readBoolean("enabled", true);
337     }
338 
339     /**
340      * returns the name of the filter
341      * @return
342      */
getName()343     public String getName() {
344         return name;
345     }
346 
347     /**
348      * Sets the name of the filter
349      * @param name
350      */
setName(String name)351     public void setName(String name) {
352         this.name = name;
353     }
354 
355     /**
356      * returns the default pass frame buffer
357      * @return
358      */
getRenderFrameBuffer()359     protected FrameBuffer getRenderFrameBuffer() {
360         return defaultPass.renderFrameBuffer;
361     }
362 
363     /**
364      * sets the default pas frame buffer
365      * @param renderFrameBuffer
366      */
setRenderFrameBuffer(FrameBuffer renderFrameBuffer)367     protected void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) {
368         this.defaultPass.renderFrameBuffer = renderFrameBuffer;
369     }
370 
371     /**
372      * returns the rendered texture of this filter
373      * @return
374      */
getRenderedTexture()375     protected Texture2D getRenderedTexture() {
376         return defaultPass.renderedTexture;
377     }
378 
379     /**
380      * sets the rendered texture of this filter
381      * @param renderedTexture
382      */
setRenderedTexture(Texture2D renderedTexture)383     protected void setRenderedTexture(Texture2D renderedTexture) {
384         this.defaultPass.renderedTexture = renderedTexture;
385     }
386 
387     /**
388      * Override this method and return true if your Filter needs the depth texture
389      *
390      * @return true if your Filter need the depth texture
391      */
isRequiresDepthTexture()392     protected boolean isRequiresDepthTexture() {
393         return false;
394     }
395 
396     /**
397      * Override this method and return false if your Filter does not need the scene texture
398      *
399      * @return false if your Filter does not need the scene texture
400      */
isRequiresSceneTexture()401     protected boolean isRequiresSceneTexture() {
402         return true;
403     }
404 
405     /**
406      * returns the list of the postRender passes
407      * @return
408      */
getPostRenderPasses()409     protected List<Pass> getPostRenderPasses() {
410         return postRenderPasses;
411     }
412 
413     /**
414      * Enable or disable this filter
415      * @param enabled true to enable
416      */
setEnabled(boolean enabled)417     public void setEnabled(boolean enabled) {
418         if (processor != null) {
419             processor.setFilterState(this, enabled);
420         } else {
421             this.enabled = enabled;
422         }
423     }
424 
425     /**
426      * returns ttrue if the filter is enabled
427      * @return enabled
428      */
isEnabled()429     public boolean isEnabled() {
430         return enabled;
431     }
432 
433     /**
434      * sets a reference to the FilterPostProcessor ti which this filter is attached
435      * @param proc
436      */
setProcessor(FilterPostProcessor proc)437     protected void setProcessor(FilterPostProcessor proc) {
438         processor = proc;
439     }
440 }
441