diff --git a/engine/src/core/com/jme3/post/Filter.java b/engine/src/core/com/jme3/post/Filter.java index f85ed8053..0c1c01b0e 100644 --- a/engine/src/core/com/jme3/post/Filter.java +++ b/engine/src/core/com/jme3/post/Filter.java @@ -1,435 +1,437 @@ -/* - * Copyright (c) 2009-2010 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.post; - -import com.jme3.asset.AssetManager; -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.export.OutputCapsule; -import com.jme3.export.Savable; -import com.jme3.material.Material; -import com.jme3.renderer.Caps; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.ViewPort; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture2D; -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -/** - * Filters are 2D effects applied to the rendered scene.
- * The filter is fed with the rendered scene image rendered in an offscreen frame buffer.
- * This texture is applied on a fullscreen quad, with a special material.
- * This material uses a shader that aplly the desired effect to the scene texture.
- *
- * This class is abstract, any Filter must extend it.
- * Any filter holds a frameBuffer and a texture
- * The getMaterial must return a Material that use a GLSL shader immplementing the desired effect
- * - * @author Rémy Bouquet aka Nehon - */ -public abstract class Filter implements Savable { - - - private String name; - protected Pass defaultPass; - protected List postRenderPasses; - protected Material material; - protected boolean enabled = true; - protected FilterPostProcessor processor; - - public Filter(String name) { - this.name = name; - } - - /** - * Inner class Pass - * Pass are like filters in filters. - * Some filters will need multiple passes before the final render - */ - public class Pass { - - protected FrameBuffer renderFrameBuffer; - protected Texture2D renderedTexture; - protected Texture2D depthTexture; - protected Material passMaterial; - - /** - * init the pass called internally - * @param renderer - * @param width - * @param height - * @param textureFormat - * @param depthBufferFormat - * @param numSamples - */ - public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth) { - Collection caps = renderer.getCaps(); - if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) { - renderFrameBuffer = new FrameBuffer(width, height, numSamples); - renderedTexture = new Texture2D(width, height, numSamples, textureFormat); - if(renderDepth){ - depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat); - renderFrameBuffer.setDepthTexture(depthTexture); - } - } else { - renderFrameBuffer = new FrameBuffer(width, height, 1); - renderedTexture = new Texture2D(width, height, textureFormat); - if(renderDepth){ - depthTexture = new Texture2D(width, height, depthBufferFormat); - renderFrameBuffer.setDepthTexture(depthTexture); - } - } - - renderFrameBuffer.setColorTexture(renderedTexture); - renderFrameBuffer.setDepthBuffer(depthBufferFormat); - - } - - /** - * init the pass called internally - * @param renderer - * @param width - * @param height - * @param textureFormat - * @param depthBufferFormat - */ - public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) { - init(renderer, width, height, textureFormat, depthBufferFormat, 1); - } - - public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples) { - init(renderer, width, height, textureFormat, depthBufferFormat, numSamples, false); - } - - /** - * init the pass called internally - * @param renderer - * @param width - * @param height - * @param textureFormat - * @param depthBufferFormat - * @param numSample - * @param material - */ - public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material) { - init(renderer, width, height, textureFormat, depthBufferFormat, numSample); - passMaterial = material; - } - - public boolean requiresSceneAsTexture() { - return false; - } - - public boolean requiresDepthAsTexture() { - return false; - } - - public void beforeRender() { - } - - public FrameBuffer getRenderFrameBuffer() { - return renderFrameBuffer; - } - - public void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) { - this.renderFrameBuffer = renderFrameBuffer; - } - - public Texture2D getDepthTexture() { - return depthTexture; - } - - public Texture2D getRenderedTexture() { - return renderedTexture; - } - - public void setRenderedTexture(Texture2D renderedTexture) { - this.renderedTexture = renderedTexture; - } - - public Material getPassMaterial() { - return passMaterial; - } - - public void setPassMaterial(Material passMaterial) { - this.passMaterial = passMaterial; - } - - public void cleanup(Renderer r) { - } - } - - /** - * returns the default pass texture format - * @return - */ - protected Format getDefaultPassTextureFormat() { - return Format.RGBA8; - } - - /** - * returns the default pass depth format - * @return - */ - protected Format getDefaultPassDepthFormat() { - return Format.Depth; - } - - /** - * contruct a Filter - */ - protected Filter() { - this("filter"); - } - - /** - * - * initialize this filter - * use InitFilter for overriding filter initialization - * @param manager the assetManager - * @param renderManager the renderManager - * @param vp the viewport - * @param w the width - * @param h the height - */ - protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { - // cleanup(renderManager.getRenderer()); - defaultPass = new Pass(); - defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat()); - initFilter(manager, renderManager, vp, w, h); - } - - /** - * cleanup this filter - * @param r - */ - protected final void cleanup(Renderer r) { - processor = null; - if (defaultPass != null) { - defaultPass.cleanup(r); - } - if (postRenderPasses != null) { - for (Iterator it = postRenderPasses.iterator(); it.hasNext();) { - Pass pass = it.next(); - pass.cleanup(r); - } - } - cleanUpFilter(r); - } - - /** - * Initialization of sub classes filters - * This method is called once when the filter is added to the FilterPostProcessor - * It should contain Material initializations and extra passes initialization - * @param manager the assetManager - * @param renderManager the renderManager - * @param vp the viewPort where this filter is rendered - * @param w the width of the filter - * @param h the height of the filter - */ - protected abstract void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h); - - /** - * override this method if you have some cleanup to do - * @param r the renderer - */ - protected void cleanUpFilter(Renderer r) { - } - - ; - - /** - * Must return the material used for this filter. - * this method is called every frame. - * - * @return the material used for this filter. - */ - protected abstract Material getMaterial(); - - /** - * Override this method if you want to make a pre pass, before the actual rendering of the frame - * @param renderManager - * @param viewPort - */ - protected void postQueue(RenderManager renderManager, ViewPort viewPort) { - } - - /** - * Override this method if you want to modify parameters according to tpf before the rendering of the frame. - * This is usefull for animated filters - * Also it can be the place to render pre passes - * @param tpf the time used to render the previous frame - */ - protected void preFrame(float tpf) { - } - - /** - * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering - * @param renderManager - * @param viewPort - * @param prevFilterBuffer - * @param sceneBuffer - */ - protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) { - } - - /** - * 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 - * This method should always begin by super.write(ex); - * @param ex - * @throws IOException - */ - public void write(JmeExporter ex) throws IOException { - OutputCapsule oc = ex.getCapsule(this); - oc.write(name, "name", ""); - oc.write(enabled, "enabled", true); - } - - /** - * Override this method if you want to load extra properties when the filter - * is loaded else only basic properties of the filter will be loaded - * This method should always begin by super.read(im); - */ - public void read(JmeImporter im) throws IOException { - InputCapsule ic = im.getCapsule(this); - name = ic.readString("name", ""); - enabled = ic.readBoolean("enabled", true); - } - - /** - * returns the name of the filter - * @return - */ - public String getName() { - return name; - } - - /** - * Sets the name of the filter - * @param name - */ - public void setName(String name) { - this.name = name; - } - - /** - * returns the default pass frame buffer - * @return - */ - protected FrameBuffer getRenderFrameBuffer() { - return defaultPass.renderFrameBuffer; - } - - /** - * sets the default pas frame buffer - * @param renderFrameBuffer - */ - protected void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) { - this.defaultPass.renderFrameBuffer = renderFrameBuffer; - } - - /** - * returns the rendered texture of this filter - * @return - */ - protected Texture2D getRenderedTexture() { - return defaultPass.renderedTexture; - } - - /** - * sets the rendered texture of this filter - * @param renderedTexture - */ - protected void setRenderedTexture(Texture2D renderedTexture) { - this.defaultPass.renderedTexture = renderedTexture; - } - - /** - * Override this method and return true if your Filter needs the depth texture - * - * @return true if your Filter need the depth texture - */ - protected boolean isRequiresDepthTexture() { - return false; - } - - /** - * Override this method and return false if your Filter does not need the scene texture - * - * @return false if your Filter does not need the scene texture - */ - protected boolean isRequiresSceneTexture() { - return true; - } - - /** - * returns the list of the postRender passes - * @return - */ - protected List getPostRenderPasses() { - return postRenderPasses; - } - - /** - * Enable or disable this filter - * @param enabled true to enable - */ - public void setEnabled(boolean enabled) { - if (processor != null) { - processor.setFilterState(this, enabled); - } else { - this.enabled = enabled; - } - } - - /** - * returns ttrue if the filter is enabled - * @return enabled - */ - public boolean isEnabled() { - return enabled; - } - - /** - * sets a reference to the FilterPostProcessor ti which this filter is attached - * @param proc - */ - protected void setProcessor(FilterPostProcessor proc) { - processor = proc; - } -} +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.post; + +import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.material.Material; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture2D; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * Filters are 2D effects applied to the rendered scene.
+ * The filter is fed with the rendered scene image rendered in an offscreen frame buffer.
+ * This texture is applied on a fullscreen quad, with a special material.
+ * This material uses a shader that aplly the desired effect to the scene texture.
+ *
+ * This class is abstract, any Filter must extend it.
+ * Any filter holds a frameBuffer and a texture
+ * The getMaterial must return a Material that use a GLSL shader immplementing the desired effect
+ * + * @author Rémy Bouquet aka Nehon + */ +public abstract class Filter implements Savable { + + + private String name; + protected Pass defaultPass; + protected List postRenderPasses; + protected Material material; + protected boolean enabled = true; + protected FilterPostProcessor processor; + + public Filter(String name) { + this.name = name; + } + + /** + * Inner class Pass + * Pass are like filters in filters. + * Some filters will need multiple passes before the final render + */ + public class Pass { + + protected FrameBuffer renderFrameBuffer; + protected Texture2D renderedTexture; + protected Texture2D depthTexture; + protected Material passMaterial; + + /** + * init the pass called internally + * @param renderer + * @param width + * @param height + * @param textureFormat + * @param depthBufferFormat + * @param numSamples + */ + public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples, boolean renderDepth) { + Collection caps = renderer.getCaps(); + if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample) && caps.contains(Caps.OpenGL31)) { + renderFrameBuffer = new FrameBuffer(width, height, numSamples); + renderedTexture = new Texture2D(width, height, numSamples, textureFormat); + renderFrameBuffer.setDepthBuffer(depthBufferFormat); + if (renderDepth) { + depthTexture = new Texture2D(width, height, numSamples, depthBufferFormat); + renderFrameBuffer.setDepthTexture(depthTexture); + } + } else { + renderFrameBuffer = new FrameBuffer(width, height, 1); + renderedTexture = new Texture2D(width, height, textureFormat); + renderFrameBuffer.setDepthBuffer(depthBufferFormat); + if (renderDepth) { + depthTexture = new Texture2D(width, height, depthBufferFormat); + renderFrameBuffer.setDepthTexture(depthTexture); + } + } + + renderFrameBuffer.setColorTexture(renderedTexture); + + + } + + /** + * init the pass called internally + * @param renderer + * @param width + * @param height + * @param textureFormat + * @param depthBufferFormat + */ + public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat) { + init(renderer, width, height, textureFormat, depthBufferFormat, 1); + } + + public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSamples) { + init(renderer, width, height, textureFormat, depthBufferFormat, numSamples, false); + } + + /** + * init the pass called internally + * @param renderer + * @param width + * @param height + * @param textureFormat + * @param depthBufferFormat + * @param numSample + * @param material + */ + public void init(Renderer renderer, int width, int height, Format textureFormat, Format depthBufferFormat, int numSample, Material material) { + init(renderer, width, height, textureFormat, depthBufferFormat, numSample); + passMaterial = material; + } + + public boolean requiresSceneAsTexture() { + return false; + } + + public boolean requiresDepthAsTexture() { + return false; + } + + public void beforeRender() { + } + + public FrameBuffer getRenderFrameBuffer() { + return renderFrameBuffer; + } + + public void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) { + this.renderFrameBuffer = renderFrameBuffer; + } + + public Texture2D getDepthTexture() { + return depthTexture; + } + + public Texture2D getRenderedTexture() { + return renderedTexture; + } + + public void setRenderedTexture(Texture2D renderedTexture) { + this.renderedTexture = renderedTexture; + } + + public Material getPassMaterial() { + return passMaterial; + } + + public void setPassMaterial(Material passMaterial) { + this.passMaterial = passMaterial; + } + + public void cleanup(Renderer r) { + } + } + + /** + * returns the default pass texture format + * @return + */ + protected Format getDefaultPassTextureFormat() { + return Format.RGBA8; + } + + /** + * returns the default pass depth format + * @return + */ + protected Format getDefaultPassDepthFormat() { + return Format.Depth; + } + + /** + * contruct a Filter + */ + protected Filter() { + this("filter"); + } + + /** + * + * initialize this filter + * use InitFilter for overriding filter initialization + * @param manager the assetManager + * @param renderManager the renderManager + * @param vp the viewport + * @param w the width + * @param h the height + */ + protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { + // cleanup(renderManager.getRenderer()); + defaultPass = new Pass(); + defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat()); + initFilter(manager, renderManager, vp, w, h); + } + + /** + * cleanup this filter + * @param r + */ + protected final void cleanup(Renderer r) { + processor = null; + if (defaultPass != null) { + defaultPass.cleanup(r); + } + if (postRenderPasses != null) { + for (Iterator it = postRenderPasses.iterator(); it.hasNext();) { + Pass pass = it.next(); + pass.cleanup(r); + } + } + cleanUpFilter(r); + } + + /** + * Initialization of sub classes filters + * This method is called once when the filter is added to the FilterPostProcessor + * It should contain Material initializations and extra passes initialization + * @param manager the assetManager + * @param renderManager the renderManager + * @param vp the viewPort where this filter is rendered + * @param w the width of the filter + * @param h the height of the filter + */ + protected abstract void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h); + + /** + * override this method if you have some cleanup to do + * @param r the renderer + */ + protected void cleanUpFilter(Renderer r) { + } + + ; + + /** + * Must return the material used for this filter. + * this method is called every frame. + * + * @return the material used for this filter. + */ + protected abstract Material getMaterial(); + + /** + * Override this method if you want to make a pre pass, before the actual rendering of the frame + * @param renderManager + * @param viewPort + */ + protected void postQueue(RenderManager renderManager, ViewPort viewPort) { + } + + /** + * Override this method if you want to modify parameters according to tpf before the rendering of the frame. + * This is usefull for animated filters + * Also it can be the place to render pre passes + * @param tpf the time used to render the previous frame + */ + protected void preFrame(float tpf) { + } + + /** + * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering + * @param renderManager + * @param viewPort + * @param prevFilterBuffer + * @param sceneBuffer + */ + protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) { + } + + /** + * 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 + * This method should always begin by super.write(ex); + * @param ex + * @throws IOException + */ + public void write(JmeExporter ex) throws IOException { + OutputCapsule oc = ex.getCapsule(this); + oc.write(name, "name", ""); + oc.write(enabled, "enabled", true); + } + + /** + * Override this method if you want to load extra properties when the filter + * is loaded else only basic properties of the filter will be loaded + * This method should always begin by super.read(im); + */ + public void read(JmeImporter im) throws IOException { + InputCapsule ic = im.getCapsule(this); + name = ic.readString("name", ""); + enabled = ic.readBoolean("enabled", true); + } + + /** + * returns the name of the filter + * @return + */ + public String getName() { + return name; + } + + /** + * Sets the name of the filter + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * returns the default pass frame buffer + * @return + */ + protected FrameBuffer getRenderFrameBuffer() { + return defaultPass.renderFrameBuffer; + } + + /** + * sets the default pas frame buffer + * @param renderFrameBuffer + */ + protected void setRenderFrameBuffer(FrameBuffer renderFrameBuffer) { + this.defaultPass.renderFrameBuffer = renderFrameBuffer; + } + + /** + * returns the rendered texture of this filter + * @return + */ + protected Texture2D getRenderedTexture() { + return defaultPass.renderedTexture; + } + + /** + * sets the rendered texture of this filter + * @param renderedTexture + */ + protected void setRenderedTexture(Texture2D renderedTexture) { + this.defaultPass.renderedTexture = renderedTexture; + } + + /** + * Override this method and return true if your Filter needs the depth texture + * + * @return true if your Filter need the depth texture + */ + protected boolean isRequiresDepthTexture() { + return false; + } + + /** + * Override this method and return false if your Filter does not need the scene texture + * + * @return false if your Filter does not need the scene texture + */ + protected boolean isRequiresSceneTexture() { + return true; + } + + /** + * returns the list of the postRender passes + * @return + */ + protected List getPostRenderPasses() { + return postRenderPasses; + } + + /** + * Enable or disable this filter + * @param enabled true to enable + */ + public void setEnabled(boolean enabled) { + if (processor != null) { + processor.setFilterState(this, enabled); + } else { + this.enabled = enabled; + } + } + + /** + * returns ttrue if the filter is enabled + * @return enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * sets a reference to the FilterPostProcessor ti which this filter is attached + * @param proc + */ + protected void setProcessor(FilterPostProcessor proc) { + processor = proc; + } +}