1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5package com.jme3.post.filters;
6
7import com.jme3.asset.AssetManager;
8import com.jme3.effect.ParticleEmitter;
9import com.jme3.material.Material;
10import com.jme3.math.ColorRGBA;
11import com.jme3.post.Filter;
12import com.jme3.renderer.RenderManager;
13import com.jme3.renderer.Renderer;
14import com.jme3.renderer.ViewPort;
15import com.jme3.renderer.queue.RenderQueue;
16import com.jme3.scene.Node;
17
18import com.jme3.scene.Spatial;
19import com.jme3.texture.FrameBuffer;
20import com.jme3.texture.Texture;
21import com.jme3.texture.Texture2D;
22import java.util.logging.Level;
23import java.util.logging.Logger;
24
25/**
26 * A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
27 * just create a TranslucentBucketFilter and add it to the Filter list of a FilterPostPorcessor
28 * @author Nehon
29 */
30public final class TranslucentBucketFilter extends Filter {
31
32    private final static Logger logger = Logger.getLogger(TranslucentBucketFilter.class.getName());
33    private RenderManager renderManager;
34    private boolean enabledSoftParticles = false;
35    private Texture depthTexture;
36    private ViewPort viewPort;
37
38    public TranslucentBucketFilter() {
39        super("TranslucentBucketFilter");
40    }
41
42    public TranslucentBucketFilter(boolean enabledSoftParticles) {
43        this();
44        this.enabledSoftParticles = enabledSoftParticles;
45    }
46
47    @Override
48    protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
49        this.renderManager = rm;
50        this.viewPort = vp;
51        material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
52        material.setColor("Color", ColorRGBA.White);
53        Texture2D tex = processor.getFilterTexture();
54        material.setTexture("Texture", tex);
55        if (tex.getImage().getMultiSamples() > 1) {
56            material.setInt("NumSamples", tex.getImage().getMultiSamples());
57        } else {
58            material.clearParam("NumSamples");
59        }
60        renderManager.setHandleTranslucentBucket(false);
61        if (enabledSoftParticles && depthTexture != null) {
62            initSoftParticles(vp, true);
63        }
64    }
65
66    private void initSoftParticles(ViewPort vp, boolean enabledSP) {
67        if (depthTexture != null) {
68            for (Spatial scene : vp.getScenes()) {
69                makeSoftParticleEmitter(scene, enabledSP && enabled);
70            }
71        }
72
73    }
74
75    @Override
76    protected void setDepthTexture(Texture depthTexture) {
77        this.depthTexture = depthTexture;
78        if (enabledSoftParticles && depthTexture != null) {
79            initSoftParticles(viewPort, true);
80        }
81    }
82
83    /**
84     * Override this method and return false if your Filter does not need the scene texture
85     * @return
86     */
87    @Override
88    protected boolean isRequiresSceneTexture() {
89        return false;
90    }
91
92    @Override
93    protected boolean isRequiresDepthTexture() {
94        return enabledSoftParticles;
95    }
96
97    @Override
98    protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
99        renderManager.setCamera(viewPort.getCamera(), false);
100        if (prevFilterBuffer != sceneBuffer) {
101            renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
102        }
103        renderManager.getRenderer().setFrameBuffer(sceneBuffer);
104        viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
105    }
106
107    @Override
108    protected void cleanUpFilter(Renderer r) {
109        if (renderManager != null) {
110            renderManager.setHandleTranslucentBucket(true);
111        }
112
113        initSoftParticles(viewPort, false);
114    }
115
116    @Override
117    protected Material getMaterial() {
118        return material;
119    }
120
121    @Override
122    public void setEnabled(boolean enabled) {
123        super.setEnabled(enabled);
124        if (renderManager != null) {
125            renderManager.setHandleTranslucentBucket(!enabled);
126        }
127        initSoftParticles(viewPort, enabledSoftParticles);
128    }
129
130    private void makeSoftParticleEmitter(Spatial scene, boolean enabled) {
131        if (scene instanceof Node) {
132            Node n = (Node) scene;
133            for (Spatial child : n.getChildren()) {
134                makeSoftParticleEmitter(child, enabled);
135            }
136        }
137        if (scene instanceof ParticleEmitter) {
138            ParticleEmitter emitter = (ParticleEmitter) scene;
139            if (enabled) {
140                enabledSoftParticles = enabled;
141
142                emitter.getMaterial().selectTechnique("SoftParticles", renderManager);
143                emitter.getMaterial().setTexture("DepthTexture", processor.getDepthTexture());
144                emitter.setQueueBucket(RenderQueue.Bucket.Translucent);
145
146                logger.log(Level.INFO, "Made particle Emitter {0} soft.", emitter.getName());
147            } else {
148                emitter.getMaterial().clearParam("DepthTexture");
149                emitter.getMaterial().selectTechnique("Default", renderManager);
150               // emitter.setQueueBucket(RenderQueue.Bucket.Transparent);
151                logger.log(Level.INFO, "Particle Emitter {0} is not soft anymore.", emitter.getName());
152            }
153        }
154    }
155}
156