1/*
2 * Copyright (c) 2009-2012 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 */
32package com.jme3.water;
33
34import com.jme3.asset.AssetManager;
35import com.jme3.export.InputCapsule;
36import com.jme3.export.JmeExporter;
37import com.jme3.export.JmeImporter;
38import com.jme3.export.OutputCapsule;
39import com.jme3.light.DirectionalLight;
40import com.jme3.light.Light;
41import com.jme3.material.Material;
42import com.jme3.math.*;
43import com.jme3.post.Filter;
44import com.jme3.post.Filter.Pass;
45import com.jme3.renderer.Camera;
46import com.jme3.renderer.RenderManager;
47import com.jme3.renderer.ViewPort;
48import com.jme3.scene.Node;
49import com.jme3.scene.Spatial;
50import com.jme3.texture.Image.Format;
51import com.jme3.texture.Texture.WrapMode;
52import com.jme3.texture.Texture2D;
53import com.jme3.util.TempVars;
54import java.io.IOException;
55
56/**
57 * The WaterFilter is a 2D post process that simulate water.
58 * It renders water above and under water.
59 * See this blog post for more info <a href="http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/">http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/</a>
60 *
61 *
62 * @author Rémy Bouquet aka Nehon
63 */
64public class WaterFilter extends Filter {
65
66    private Pass reflectionPass;
67    protected Spatial reflectionScene;
68    protected ViewPort reflectionView;
69    private Texture2D normalTexture;
70    private Texture2D foamTexture;
71    private Texture2D causticsTexture;
72    private Texture2D heightTexture;
73    private Plane plane;
74    private Camera reflectionCam;
75    protected Ray ray = new Ray();
76    private Vector3f targetLocation = new Vector3f();
77    private ReflectionProcessor reflectionProcessor;
78    private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
79            0.0f, 0.5f, 0.0f, 0.5f,
80            0.0f, 0.0f, 0.0f, 0.5f,
81            0.0f, 0.0f, 0.0f, 1.0f);
82    private Matrix4f textureProjMatrix = new Matrix4f();
83    private boolean underWater;
84    private RenderManager renderManager;
85    private ViewPort viewPort;
86    private float time = 0;
87    //properties
88    private float speed = 1;
89    private Vector3f lightDirection = new Vector3f(0, -1, 0);
90    private ColorRGBA lightColor = ColorRGBA.White;
91    private float waterHeight = 0.0f;
92    private ColorRGBA waterColor = new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f);
93    private ColorRGBA deepWaterColor = new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f);
94    private Vector3f colorExtinction = new Vector3f(5.0f, 20.0f, 30.0f);
95    private float waterTransparency = 0.1f;
96    private float maxAmplitude = 1.5f;
97    private float shoreHardness = 0.1f;
98    private boolean useFoam = true;
99    private float foamIntensity = 0.5f;
100    private float foamHardness = 1.0f;
101    private Vector3f foamExistence = new Vector3f(0.45f, 4.35f, 1.5f);
102    private float waveScale = 0.005f;
103    private float sunScale = 3.0f;
104    private float shininess = 0.7f;
105    private Vector2f windDirection = new Vector2f(0.0f, -1.0f);
106    private int reflectionMapSize = 512;
107    private boolean useRipples = true;
108    private float normalScale = 3.0f;
109    private boolean useHQShoreline = true;
110    private boolean useSpecular = true;
111    private boolean useRefraction = true;
112    private float refractionStrength = 0.0f;
113    private float refractionConstant = 0.5f;
114    private float reflectionDisplace = 30;
115    private float underWaterFogDistance = 120;
116    private boolean useCaustics = true;
117    private float causticsIntensity = 0.5f;
118
119    /**
120     * Create a Water Filter
121     */
122    public WaterFilter() {
123        super("WaterFilter");
124    }
125
126    public WaterFilter(Node reflectionScene, Vector3f lightDirection) {
127        super("WaterFilter");
128        this.reflectionScene = reflectionScene;
129        this.lightDirection = lightDirection;
130    }
131
132    @Override
133    protected boolean isRequiresDepthTexture() {
134        return true;
135    }
136
137    @Override
138    protected void preFrame(float tpf) {
139        time = time + (tpf * speed);
140        material.setFloat("Time", time);
141        Camera sceneCam = viewPort.getCamera();
142        biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
143        material.setMatrix4("TextureProjMatrix", textureProjMatrix);
144        material.setVector3("CameraPosition", sceneCam.getLocation());
145        material.setMatrix4("ViewProjectionMatrixInverse", sceneCam.getViewProjectionMatrix().invert());
146
147        material.setFloat("WaterHeight", waterHeight);
148
149        //update reflection cam
150        ray.setOrigin(sceneCam.getLocation());
151        ray.setDirection(sceneCam.getDirection());
152        plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
153        reflectionProcessor.setReflectionClipPlane(plane);
154        boolean inv = false;
155        if (!ray.intersectsWherePlane(plane, targetLocation)) {
156            ray.setDirection(ray.getDirection().negateLocal());
157            ray.intersectsWherePlane(plane, targetLocation);
158            inv = true;
159        }
160        Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
161        reflectionCam.setLocation(loc);
162        reflectionCam.setFrustum(sceneCam.getFrustumNear(),
163                sceneCam.getFrustumFar(),
164                sceneCam.getFrustumLeft(),
165                sceneCam.getFrustumRight(),
166                sceneCam.getFrustumTop(),
167                sceneCam.getFrustumBottom());
168        TempVars vars = TempVars.get();
169
170
171        vars.vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
172        float planeDistance = plane.pseudoDistance(vars.vect1);
173        vars.vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
174        vars.vect3.set(vars.vect1.subtractLocal(vars.vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
175
176        reflectionCam.lookAt(targetLocation, vars.vect3);
177        vars.release();
178
179        if (inv) {
180            reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
181        }
182
183        //if we're under water no need to compute reflection
184        if (sceneCam.getLocation().y >= waterHeight) {
185            boolean rtb = true;
186            if (!renderManager.isHandleTranslucentBucket()) {
187                renderManager.setHandleTranslucentBucket(true);
188                rtb = false;
189            }
190            renderManager.renderViewPort(reflectionView, tpf);
191            if (!rtb) {
192                renderManager.setHandleTranslucentBucket(false);
193            }
194            renderManager.setCamera(sceneCam, false);
195            renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
196
197
198            underWater = false;
199        } else {
200            underWater = true;
201        }
202    }
203
204    @Override
205    protected Material getMaterial() {
206        return material;
207    }
208
209    private DirectionalLight findLight(Node node) {
210        for (Light light : node.getWorldLightList()) {
211            if (light instanceof DirectionalLight) {
212                return (DirectionalLight) light;
213            }
214        }
215        for (Spatial child : node.getChildren()) {
216            if (child instanceof Node) {
217                return findLight((Node) child);
218            }
219        }
220
221        return null;
222    }
223
224    @Override
225    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
226
227        if (reflectionScene == null) {
228            reflectionScene = vp.getScenes().get(0);
229            DirectionalLight l = findLight((Node) reflectionScene);
230            if (l != null) {
231                lightDirection = l.getDirection();
232            }
233
234        }
235
236        this.renderManager = renderManager;
237        this.viewPort = vp;
238        reflectionPass = new Pass();
239        reflectionPass.init(renderManager.getRenderer(), reflectionMapSize, reflectionMapSize, Format.RGBA8, Format.Depth);
240        reflectionCam = new Camera(reflectionMapSize, reflectionMapSize);
241        reflectionView = new ViewPort("reflectionView", reflectionCam);
242        reflectionView.setClearFlags(true, true, true);
243        reflectionView.attachScene(reflectionScene);
244        reflectionView.setOutputFrameBuffer(reflectionPass.getRenderFrameBuffer());
245        plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
246        reflectionProcessor = new ReflectionProcessor(reflectionCam, reflectionPass.getRenderFrameBuffer(), plane);
247        reflectionView.addProcessor(reflectionProcessor);
248
249        normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
250        if (foamTexture == null) {
251            foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
252        }
253        if (causticsTexture == null) {
254            causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
255        }
256        heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
257
258        normalTexture.setWrap(WrapMode.Repeat);
259        foamTexture.setWrap(WrapMode.Repeat);
260        causticsTexture.setWrap(WrapMode.Repeat);
261        heightTexture.setWrap(WrapMode.Repeat);
262
263        material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
264        material.setTexture("HeightMap", heightTexture);
265        material.setTexture("CausticsMap", causticsTexture);
266        material.setTexture("FoamMap", foamTexture);
267        material.setTexture("NormalMap", normalTexture);
268        material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
269
270        material.setFloat("WaterTransparency", waterTransparency);
271        material.setFloat("NormalScale", normalScale);
272        material.setFloat("R0", refractionConstant);
273        material.setFloat("MaxAmplitude", maxAmplitude);
274        material.setVector3("LightDir", lightDirection);
275        material.setColor("LightColor", lightColor);
276        material.setFloat("ShoreHardness", shoreHardness);
277        material.setFloat("RefractionStrength", refractionStrength);
278        material.setFloat("WaveScale", waveScale);
279        material.setVector3("FoamExistence", foamExistence);
280        material.setFloat("SunScale", sunScale);
281        material.setVector3("ColorExtinction", colorExtinction);
282        material.setFloat("Shininess", shininess);
283        material.setColor("WaterColor", waterColor);
284        material.setColor("DeepWaterColor", deepWaterColor);
285        material.setVector2("WindDirection", windDirection);
286        material.setFloat("FoamHardness", foamHardness);
287        material.setBoolean("UseRipples", useRipples);
288        material.setBoolean("UseHQShoreline", useHQShoreline);
289        material.setBoolean("UseSpecular", useSpecular);
290        material.setBoolean("UseFoam", useFoam);
291        material.setBoolean("UseCaustics", useCaustics);
292        material.setBoolean("UseRefraction", useRefraction);
293        material.setFloat("ReflectionDisplace", reflectionDisplace);
294        material.setFloat("FoamIntensity", foamIntensity);
295        material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
296        material.setFloat("CausticsIntensity", causticsIntensity);
297
298
299    }
300
301    @Override
302    public void write(JmeExporter ex) throws IOException {
303        super.write(ex);
304        OutputCapsule oc = ex.getCapsule(this);
305
306        oc.write(speed, "speed", 1f);
307        oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
308        oc.write(lightColor, "lightColor", ColorRGBA.White);
309        oc.write(waterHeight, "waterHeight", 0.0f);
310        oc.write(waterColor, "waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
311        oc.write(deepWaterColor, "deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
312
313        oc.write(colorExtinction, "colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
314        oc.write(waterTransparency, "waterTransparency", 0.1f);
315        oc.write(maxAmplitude, "maxAmplitude", 1.5f);
316        oc.write(shoreHardness, "shoreHardness", 0.1f);
317        oc.write(useFoam, "useFoam", true);
318
319        oc.write(foamIntensity, "foamIntensity", 0.5f);
320        oc.write(foamHardness, "foamHardness", 1.0f);
321
322        oc.write(foamExistence, "foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
323        oc.write(waveScale, "waveScale", 0.005f);
324
325        oc.write(sunScale, "sunScale", 3.0f);
326        oc.write(shininess, "shininess", 0.7f);
327        oc.write(windDirection, "windDirection", new Vector2f(0.0f, -1.0f));
328        oc.write(reflectionMapSize, "reflectionMapSize", 512);
329        oc.write(useRipples, "useRipples", true);
330
331        oc.write(normalScale, "normalScale", 3.0f);
332        oc.write(useHQShoreline, "useHQShoreline", true);
333
334        oc.write(useSpecular, "useSpecular", true);
335
336        oc.write(useRefraction, "useRefraction", true);
337        oc.write(refractionStrength, "refractionStrength", 0.0f);
338        oc.write(refractionConstant, "refractionConstant", 0.5f);
339        oc.write(reflectionDisplace, "reflectionDisplace", 30f);
340        oc.write(underWaterFogDistance, "underWaterFogDistance", 120f);
341        oc.write(causticsIntensity, "causticsIntensity", 0.5f);
342
343        oc.write(useCaustics, "useCaustics", true);
344    }
345
346    @Override
347    public void read(JmeImporter im) throws IOException {
348        super.read(im);
349        InputCapsule ic = im.getCapsule(this);
350        speed = ic.readFloat("speed", 1f);
351        lightDirection = (Vector3f) ic.readSavable("lightDirection", new Vector3f(0, -1, 0));
352        lightColor = (ColorRGBA) ic.readSavable("lightColor", ColorRGBA.White);
353        waterHeight = ic.readFloat("waterHeight", 0.0f);
354        waterColor = (ColorRGBA) ic.readSavable("waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
355        deepWaterColor = (ColorRGBA) ic.readSavable("deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
356
357        colorExtinction = (Vector3f) ic.readSavable("colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
358        waterTransparency = ic.readFloat("waterTransparency", 0.1f);
359        maxAmplitude = ic.readFloat("maxAmplitude", 1.5f);
360        shoreHardness = ic.readFloat("shoreHardness", 0.1f);
361        useFoam = ic.readBoolean("useFoam", true);
362
363        foamIntensity = ic.readFloat("foamIntensity", 0.5f);
364        foamHardness = ic.readFloat("foamHardness", 1.0f);
365
366        foamExistence = (Vector3f) ic.readSavable("foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
367        waveScale = ic.readFloat("waveScale", 0.005f);
368
369        sunScale = ic.readFloat("sunScale", 3.0f);
370        shininess = ic.readFloat("shininess", 0.7f);
371        windDirection = (Vector2f) ic.readSavable("windDirection", new Vector2f(0.0f, -1.0f));
372        reflectionMapSize = ic.readInt("reflectionMapSize", 512);
373        useRipples = ic.readBoolean("useRipples", true);
374
375        normalScale = ic.readFloat("normalScale", 3.0f);
376        useHQShoreline = ic.readBoolean("useHQShoreline", true);
377
378        useSpecular = ic.readBoolean("useSpecular", true);
379
380        useRefraction = ic.readBoolean("useRefraction", true);
381        refractionStrength = ic.readFloat("refractionStrength", 0.0f);
382        refractionConstant = ic.readFloat("refractionConstant", 0.5f);
383        reflectionDisplace = ic.readFloat("reflectionDisplace", 30f);
384        underWaterFogDistance = ic.readFloat("underWaterFogDistance", 120f);
385        causticsIntensity = ic.readFloat("causticsIntensity", 0.5f);
386
387        useCaustics = ic.readBoolean("useCaustics", true);
388
389    }
390
391    /**
392     * gets the height of the water plane
393     * @return
394     */
395    public float getWaterHeight() {
396        return waterHeight;
397    }
398
399    /**
400     * Sets the height of the water plane
401     * default is 0.0
402     * @param waterHeight
403     */
404    public void setWaterHeight(float waterHeight) {
405        this.waterHeight = waterHeight;
406    }
407
408    /**
409     * sets the scene to render in the reflection map
410     * @param reflectionScene
411     */
412    public void setReflectionScene(Spatial reflectionScene) {
413        this.reflectionScene = reflectionScene;
414    }
415
416    /**
417     * returns the waterTransparency value
418     * @return
419     */
420    public float getWaterTransparency() {
421        return waterTransparency;
422    }
423
424    /**
425     * Sets how fast will colours fade out. You can also think about this
426     * values as how clear water is. Therefore use smaller values (eg. 0.05)
427     * to have crystal clear water and bigger to achieve "muddy" water.
428     * default is 0.1f
429     * @param waterTransparency
430     */
431    public void setWaterTransparency(float waterTransparency) {
432        this.waterTransparency = waterTransparency;
433        if (material != null) {
434            material.setFloat("WaterTransparency", waterTransparency);
435        }
436    }
437
438    /**
439     * Returns the normal scales applied to the normal map
440     * @return
441     */
442    public float getNormalScale() {
443        return normalScale;
444    }
445
446    /**
447     * Sets the normal scaling factors to apply to the normal map.
448     * the higher the value the more small ripples will be visible on the waves.
449     * default is 1.0
450     * @param normalScale
451     */
452    public void setNormalScale(float normalScale) {
453        this.normalScale = normalScale;
454        if (material != null) {
455            material.setFloat("NormalScale", normalScale);
456        }
457    }
458
459    /**
460     * returns the refractoin constant
461     * @return
462     */
463    public float getRefractionConstant() {
464        return refractionConstant;
465    }
466
467    /**
468     * This is a constant related to the index of refraction (IOR) used to compute the fresnel term.
469     * F = R0 + (1-R0)( 1 - N.V)^5
470     * where F is the fresnel term, R0 the constant, N the normal vector and V tne view vector.
471     * It usually depend on the material you are lookinh through (here water).
472     * Default value is 0.3f
473     * In practice, the lowest the value and the less the reflection can be seen on water
474     * @param refractionConstant
475     */
476    public void setRefractionConstant(float refractionConstant) {
477        this.refractionConstant = refractionConstant;
478        if (material != null) {
479            material.setFloat("R0", refractionConstant);
480        }
481    }
482
483    /**
484     * return the maximum wave amplitude
485     * @return
486     */
487    public float getMaxAmplitude() {
488        return maxAmplitude;
489    }
490
491    /**
492     * Sets the maximum waves amplitude
493     * default is 1.0
494     * @param maxAmplitude
495     */
496    public void setMaxAmplitude(float maxAmplitude) {
497        this.maxAmplitude = maxAmplitude;
498        if (material != null) {
499            material.setFloat("MaxAmplitude", maxAmplitude);
500        }
501    }
502
503    /**
504     * gets the light direction
505     * @return
506     */
507    public Vector3f getLightDirection() {
508        return lightDirection;
509    }
510
511    /**
512     * Sets the light direction
513     * @param lightDirection
514     */
515    public void setLightDirection(Vector3f lightDirection) {
516        this.lightDirection = lightDirection;
517        if (material != null) {
518            material.setVector3("LightDir", lightDirection);
519        }
520    }
521
522    /**
523     * returns the light color
524     * @return
525     */
526    public ColorRGBA getLightColor() {
527        return lightColor;
528    }
529
530    /**
531     * Sets the light color to use
532     * default is white
533     * @param lightColor
534     */
535    public void setLightColor(ColorRGBA lightColor) {
536        this.lightColor = lightColor;
537        if (material != null) {
538            material.setColor("LightColor", lightColor);
539        }
540    }
541
542    /**
543     * Return the shoreHardeness
544     * @return
545     */
546    public float getShoreHardness() {
547        return shoreHardness;
548    }
549
550    /**
551     * The smaller this value is, the softer the transition between
552     * shore and water. If you want hard edges use very big value.
553     * Default is 0.1f.
554     * @param shoreHardness
555     */
556    public void setShoreHardness(float shoreHardness) {
557        this.shoreHardness = shoreHardness;
558        if (material != null) {
559            material.setFloat("ShoreHardness", shoreHardness);
560        }
561    }
562
563    /**
564     * returns the foam hardness
565     * @return
566     */
567    public float getFoamHardness() {
568        return foamHardness;
569    }
570
571    /**
572     * Sets the foam hardness : How much the foam will blend with the shore to avoid hard edged water plane.
573     * Default is 1.0
574     * @param foamHardness
575     */
576    public void setFoamHardness(float foamHardness) {
577        this.foamHardness = foamHardness;
578        if (material != null) {
579            material.setFloat("FoamHardness", foamHardness);
580        }
581    }
582
583    /**
584     * returns the refractionStrenght
585     * @return
586     */
587    public float getRefractionStrength() {
588        return refractionStrength;
589    }
590
591    /**
592     * This value modifies current fresnel term. If you want to weaken
593     * reflections use bigger value. If you want to empasize them use
594     * value smaller then 0. Default is 0.0f.
595     * @param refractionStrength
596     */
597    public void setRefractionStrength(float refractionStrength) {
598        this.refractionStrength = refractionStrength;
599        if (material != null) {
600            material.setFloat("RefractionStrength", refractionStrength);
601        }
602    }
603
604    /**
605     * returns the scale factor of the waves height map
606     * @return
607     */
608    public float getWaveScale() {
609        return waveScale;
610    }
611
612    /**
613     * Sets the scale factor of the waves height map
614     * the smaller the value the bigger the waves
615     * default is 0.005f
616     * @param waveScale
617     */
618    public void setWaveScale(float waveScale) {
619        this.waveScale = waveScale;
620        if (material != null) {
621            material.setFloat("WaveScale", waveScale);
622        }
623    }
624
625    /**
626     * returns the foam existance vector
627     * @return
628     */
629    public Vector3f getFoamExistence() {
630        return foamExistence;
631    }
632
633    /**
634     * Describes at what depth foam starts to fade out and
635     * at what it is completely invisible. The third value is at
636     * what height foam for waves appear (+ waterHeight).
637     * default is (0.45, 4.35, 1.0);
638     * @param foamExistence
639     */
640    public void setFoamExistence(Vector3f foamExistence) {
641        this.foamExistence = foamExistence;
642        if (material != null) {
643            material.setVector3("FoamExistence", foamExistence);
644        }
645    }
646
647    /**
648     * gets the scale of the sun
649     * @return
650     */
651    public float getSunScale() {
652        return sunScale;
653    }
654
655    /**
656     * Sets the scale of the sun for specular effect
657     * @param sunScale
658     */
659    public void setSunScale(float sunScale) {
660        this.sunScale = sunScale;
661        if (material != null) {
662            material.setFloat("SunScale", sunScale);
663        }
664    }
665
666    /**
667     * Returns the color exctinction vector of the water
668     * @return
669     */
670    public Vector3f getColorExtinction() {
671        return colorExtinction;
672    }
673
674    /**
675     * Return at what depth the refraction color extinct
676     * the first value is for red
677     * the second is for green
678     * the third is for blue
679     * Play with thos parameters to "trouble" the water
680     * default is (5.0, 20.0, 30.0f);
681     * @param colorExtinction
682     */
683    public void setColorExtinction(Vector3f colorExtinction) {
684        this.colorExtinction = colorExtinction;
685        if (material != null) {
686            material.setVector3("ColorExtinction", colorExtinction);
687        }
688    }
689
690    /**
691     * Sets the foam texture
692     * @param foamTexture
693     */
694    public void setFoamTexture(Texture2D foamTexture) {
695        this.foamTexture = foamTexture;
696        foamTexture.setWrap(WrapMode.Repeat);
697        if (material != null) {
698            material.setTexture("FoamMap", foamTexture);
699        }
700    }
701
702    /**
703     * Sets the height texture
704     * @param heightTexture
705     */
706    public void setHeightTexture(Texture2D heightTexture) {
707        this.heightTexture = heightTexture;
708        heightTexture.setWrap(WrapMode.Repeat);
709    }
710
711    /**
712     * Sets the normal Texture
713     * @param normalTexture
714     */
715    public void setNormalTexture(Texture2D normalTexture) {
716        this.normalTexture = normalTexture;
717        normalTexture.setWrap(WrapMode.Repeat);
718    }
719
720    /**
721     * return the shininess factor of the water
722     * @return
723     */
724    public float getShininess() {
725        return shininess;
726    }
727
728    /**
729     * Sets the shinines factor of the water
730     * default is 0.7f
731     * @param shininess
732     */
733    public void setShininess(float shininess) {
734        this.shininess = shininess;
735        if (material != null) {
736            material.setFloat("Shininess", shininess);
737        }
738    }
739
740    /**
741     * retruns the speed of the waves
742     * @return
743     */
744    public float getSpeed() {
745        return speed;
746    }
747
748    /**
749     * Set the speed of the waves (0.0 is still) default is 1.0
750     * @param speed
751     */
752    public void setSpeed(float speed) {
753        this.speed = speed;
754    }
755
756    /**
757     * returns the color of the water
758     *
759     * @return
760     */
761    public ColorRGBA getWaterColor() {
762        return waterColor;
763    }
764
765    /**
766     * Sets the color of the water
767     * see setDeepWaterColor for deep water color
768     * default is (0.0078f, 0.5176f, 0.5f,1.0f) (greenish blue)
769     * @param waterColor
770     */
771    public void setWaterColor(ColorRGBA waterColor) {
772        this.waterColor = waterColor;
773        if (material != null) {
774            material.setColor("WaterColor", waterColor);
775        }
776    }
777
778    /**
779     * returns the deep water color
780     * @return
781     */
782    public ColorRGBA getDeepWaterColor() {
783        return deepWaterColor;
784    }
785
786    /**
787     * sets the deep water color
788     * see setWaterColor for general color
789     * default is (0.0039f, 0.00196f, 0.145f,1.0f) (very dark blue)
790     * @param deepWaterColor
791     */
792    public void setDeepWaterColor(ColorRGBA deepWaterColor) {
793        this.deepWaterColor = deepWaterColor;
794        if (material != null) {
795            material.setColor("DeepWaterColor", deepWaterColor);
796        }
797    }
798
799    /**
800     * returns the wind direction
801     * @return
802     */
803    public Vector2f getWindDirection() {
804        return windDirection;
805    }
806
807    /**
808     * sets the wind direction
809     * the direction where the waves move
810     * default is (0.0f, -1.0f)
811     * @param windDirection
812     */
813    public void setWindDirection(Vector2f windDirection) {
814        this.windDirection = windDirection;
815        if (material != null) {
816            material.setVector2("WindDirection", windDirection);
817        }
818    }
819
820    /**
821     * returns the size of the reflection map
822     * @return
823     */
824    public int getReflectionMapSize() {
825        return reflectionMapSize;
826    }
827
828    /**
829     * Sets the size of the reflection map
830     * default is 512, the higher, the better quality, but the slower the effect.
831     * @param reflectionMapSize
832     */
833    public void setReflectionMapSize(int reflectionMapSize) {
834        this.reflectionMapSize = reflectionMapSize;
835    }
836
837    /**
838     * returns true if the water uses foam
839     * @return
840     */
841    public boolean isUseFoam() {
842        return useFoam;
843    }
844
845    /**
846     * set to true to use foam with water
847     * default true
848     * @param useFoam
849     */
850    public void setUseFoam(boolean useFoam) {
851        this.useFoam = useFoam;
852        if (material != null) {
853            material.setBoolean("UseFoam", useFoam);
854        }
855
856    }
857
858    /**
859     * sets the texture to use to render caustics on the ground underwater
860     * @param causticsTexture
861     */
862    public void setCausticsTexture(Texture2D causticsTexture) {
863        this.causticsTexture = causticsTexture;
864        if (material != null) {
865            material.setTexture("causticsMap", causticsTexture);
866        }
867    }
868
869    /**
870     * returns true if caustics are rendered
871     * @return
872     */
873    public boolean isUseCaustics() {
874        return useCaustics;
875    }
876
877    /**
878     * set to true if you want caustics to be rendered on the ground underwater, false otherwise
879     * @param useCaustics
880     */
881    public void setUseCaustics(boolean useCaustics) {
882        this.useCaustics = useCaustics;
883        if (material != null) {
884            material.setBoolean("UseCaustics", useCaustics);
885        }
886    }
887
888    /**
889     * return true
890     * @return
891     */
892    public boolean isUseHQShoreline() {
893        return useHQShoreline;
894    }
895
896    public void setUseHQShoreline(boolean useHQShoreline) {
897        this.useHQShoreline = useHQShoreline;
898        if (material != null) {
899            material.setBoolean("UseHQShoreline", useHQShoreline);
900        }
901
902    }
903
904    /**
905     * returns true if the water use the refraction
906     * @return
907     */
908    public boolean isUseRefraction() {
909        return useRefraction;
910    }
911
912    /**
913     * set to true to use refraction (default is true)
914     * @param useRefraction
915     */
916    public void setUseRefraction(boolean useRefraction) {
917        this.useRefraction = useRefraction;
918        if (material != null) {
919            material.setBoolean("UseRefraction", useRefraction);
920        }
921
922    }
923
924    /**
925     * returns true if the ater use ripples
926     * @return
927     */
928    public boolean isUseRipples() {
929        return useRipples;
930    }
931
932    /**
933     *
934     * Set to true tu use ripples
935     * @param useRipples
936     */
937    public void setUseRipples(boolean useRipples) {
938        this.useRipples = useRipples;
939        if (material != null) {
940            material.setBoolean("UseRipples", useRipples);
941        }
942
943    }
944
945    /**
946     * returns true if the water use specular
947     * @return
948     */
949    public boolean isUseSpecular() {
950        return useSpecular;
951    }
952
953    /**
954     * Set to true to use specular lightings on the water
955     * @param useSpecular
956     */
957    public void setUseSpecular(boolean useSpecular) {
958        this.useSpecular = useSpecular;
959        if (material != null) {
960            material.setBoolean("UseSpecular", useSpecular);
961        }
962    }
963
964    /**
965     * returns the foam intensity
966     * @return
967     */
968    public float getFoamIntensity() {
969        return foamIntensity;
970    }
971
972    /**
973     * sets the foam intensity default is 0.5f
974     * @param foamIntensity
975     */
976    public void setFoamIntensity(float foamIntensity) {
977        this.foamIntensity = foamIntensity;
978        if (material != null) {
979            material.setFloat("FoamIntensity", foamIntensity);
980
981        }
982    }
983
984    /**
985     * returns the reflection displace
986     * see {@link setReflectionDisplace(float reflectionDisplace)}
987     * @return
988     */
989    public float getReflectionDisplace() {
990        return reflectionDisplace;
991    }
992
993    /**
994     * Sets the reflection displace. define how troubled will look the reflection in the water. default is 30
995     * @param reflectionDisplace
996     */
997    public void setReflectionDisplace(float reflectionDisplace) {
998        this.reflectionDisplace = reflectionDisplace;
999        if (material != null) {
1000            material.setFloat("m_ReflectionDisplace", reflectionDisplace);
1001        }
1002    }
1003
1004    /**
1005     * returns true if the camera is under the water level
1006     * @return
1007     */
1008    public boolean isUnderWater() {
1009        return underWater;
1010    }
1011
1012    /**
1013     * returns the distance of the fog when under water
1014     * @return
1015     */
1016    public float getUnderWaterFogDistance() {
1017        return underWaterFogDistance;
1018    }
1019
1020    /**
1021     * sets the distance of the fog when under water.
1022     * default is 120 (120 world units) use a high value to raise the view range under water
1023     * @param underWaterFogDistance
1024     */
1025    public void setUnderWaterFogDistance(float underWaterFogDistance) {
1026        this.underWaterFogDistance = underWaterFogDistance;
1027        if (material != null) {
1028            material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
1029        }
1030    }
1031
1032    /**
1033     * get the intensity of caustics under water
1034     * @return
1035     */
1036    public float getCausticsIntensity() {
1037        return causticsIntensity;
1038    }
1039
1040    /**
1041     * sets the intensity of caustics under water. goes from 0 to 1, default is 0.5f
1042     * @param causticsIntensity
1043     */
1044    public void setCausticsIntensity(float causticsIntensity) {
1045        this.causticsIntensity = causticsIntensity;
1046        if (material != null) {
1047            material.setFloat("CausticsIntensity", causticsIntensity);
1048        }
1049    }
1050}
1051