aboutsummaryrefslogtreecommitdiffstats
path: root/ardor3d-effects
diff options
context:
space:
mode:
authorRenanse <[email protected]>2013-03-14 21:52:41 -0500
committerRenanse <[email protected]>2013-03-14 21:52:41 -0500
commit19bd8d8e1e5de5d31fab60bf2a3dedc9778782d0 (patch)
treef14c233f6181afaf91d00f83d5e078af27c3cafd /ardor3d-effects
parentaedbc04cc0c605496fc5aa12ba074643ef16d6d9 (diff)
parentc81013c8f8bec5588be7e762a254c509286cbb46 (diff)
Merge remote-tracking branch 'origin/master'
Conflicts: ardor3d-collada/src/main/java/com/ardor3d/extension/model/collada/jdom/data/DataCache.java
Diffstat (limited to 'ardor3d-effects')
-rw-r--r--ardor3d-effects/.classpath9
-rw-r--r--ardor3d-effects/.project17
-rw-r--r--ardor3d-effects/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--ardor3d-effects/.settings/org.eclipse.jdt.core.prefs2
-rw-r--r--ardor3d-effects/.settings/org.eclipse.jdt.ui.prefs1
-rw-r--r--ardor3d-effects/pom.xml64
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/bloom/BloomRenderPass.java880
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/Particle.java3
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleControllerListener.java36
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleFactory.java94
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleMesh.java2
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleSystem.java2164
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/HeightGenerator.java62
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ImprovedNoise.java150
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ProjectedGrid.java1323
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterHeightGenerator.java254
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterNode.java2170
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ParallelSplitShadowMapPass.java2728
-rw-r--r--ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ShadowRenderCallback.java40
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/add2textures.frag40
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.frag146
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.vert36
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal5.frag50
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal7.frag54
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal9.frag58
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5.frag56
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag50
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical7.frag60
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical9.frag64
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.frag48
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.vert36
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.frag34
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.vert36
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom_extract.frag50
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_horizontal9.frag60
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_vertical9.frag60
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.frag152
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.vert98
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.frag176
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.vert98
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.frag174
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.vert106
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.frag200
-rw-r--r--ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.vert106
-rw-r--r--ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/MockPSSMCamera.java38
-rw-r--r--ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/TestPSSMCamera.java118
46 files changed, 6086 insertions, 6120 deletions
diff --git a/ardor3d-effects/.classpath b/ardor3d-effects/.classpath
deleted file mode 100644
index b2417a3..0000000
--- a/ardor3d-effects/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry kind="src" path="src/main/resources"/>
- <classpathentry combineaccessrules="false" kind="src" path="/ardor3d-core"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/ardor3d-effects/.project b/ardor3d-effects/.project
deleted file mode 100644
index a38130a..0000000
--- a/ardor3d-effects/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>ardor3d-effects</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/ardor3d-effects/.settings/org.eclipse.core.resources.prefs b/ardor3d-effects/.settings/org.eclipse.core.resources.prefs
deleted file mode 100644
index e21a61e..0000000
--- a/ardor3d-effects/.settings/org.eclipse.core.resources.prefs
+++ /dev/null
@@ -1,3 +0,0 @@
-#Wed Jan 07 11:32:43 PST 2009
-eclipse.preferences.version=1
-encoding/<project>=UTF-8
diff --git a/ardor3d-effects/.settings/org.eclipse.jdt.core.prefs b/ardor3d-effects/.settings/org.eclipse.jdt.core.prefs
index e914104..19eadb6 100644
--- a/ardor3d-effects/.settings/org.eclipse.jdt.core.prefs
+++ b/ardor3d-effects/.settings/org.eclipse.jdt.core.prefs
@@ -1,4 +1,3 @@
-#Tue Apr 06 11:29:47 CDT 2010
eclipse.preferences.version=1
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
@@ -17,6 +16,7 @@ org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
diff --git a/ardor3d-effects/.settings/org.eclipse.jdt.ui.prefs b/ardor3d-effects/.settings/org.eclipse.jdt.ui.prefs
index f479490..7588391 100644
--- a/ardor3d-effects/.settings/org.eclipse.jdt.ui.prefs
+++ b/ardor3d-effects/.settings/org.eclipse.jdt.ui.prefs
@@ -1,4 +1,3 @@
-#Sun Jan 04 11:43:23 CST 2009
cleanup.add_default_serial_version_id=true
cleanup.add_generated_serial_version_id=false
cleanup.add_missing_annotations=true
diff --git a/ardor3d-effects/pom.xml b/ardor3d-effects/pom.xml
index 123dbe3..ee8b241 100644
--- a/ardor3d-effects/pom.xml
+++ b/ardor3d-effects/pom.xml
@@ -1,32 +1,32 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.ardor3d</groupId>
- <artifactId>ardor3d</artifactId>
- <version>0.9-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <artifactId>ardor3d-effects</artifactId>
- <packaging>bundle</packaging>
- <name>Ardor 3D Effects</name>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>ardor3d-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
-</project>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.ardor3d</groupId>
+ <artifactId>ardor3d</artifactId>
+ <version>0.9-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>ardor3d-effects</artifactId>
+ <packaging>bundle</packaging>
+ <name>Ardor 3D Effects</name>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ardor3d-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/bloom/BloomRenderPass.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/bloom/BloomRenderPass.java
index 1ef32bd..00a8260 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/bloom/BloomRenderPass.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/bloom/BloomRenderPass.java
@@ -1,440 +1,440 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.bloom;
-
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.ardor3d.framework.DisplaySettings;
-import com.ardor3d.image.Texture;
-import com.ardor3d.image.Texture2D;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.ContextCapabilities;
-import com.ardor3d.renderer.ContextManager;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.renderer.TextureRenderer;
-import com.ardor3d.renderer.TextureRendererFactory;
-import com.ardor3d.renderer.pass.Pass;
-import com.ardor3d.renderer.queue.RenderBucketType;
-import com.ardor3d.renderer.state.BlendState;
-import com.ardor3d.renderer.state.GLSLShaderObjectsState;
-import com.ardor3d.renderer.state.RenderState;
-import com.ardor3d.renderer.state.TextureState;
-import com.ardor3d.scenegraph.Renderable;
-import com.ardor3d.scenegraph.hint.CullHint;
-import com.ardor3d.scenegraph.hint.LightCombineMode;
-import com.ardor3d.scenegraph.hint.TextureCombineMode;
-import com.ardor3d.scenegraph.shape.Quad;
-import com.ardor3d.util.resource.ResourceLocatorTool;
-
-/**
- * GLSL bloom effect pass. - Render supplied source to a texture - Extract intensity - Blur intensity - Blend with first
- * pass
- */
-public class BloomRenderPass extends Pass {
- /** The Constant logger. */
- private static final Logger logger = Logger.getLogger(BloomRenderPass.class.getName());
-
- private static final long serialVersionUID = 1L;
-
- private double throttle = 0;
- private double sinceLast = 1;
-
- private TextureRenderer tRenderer = null;
- private TextureRenderer fullTRenderer = null;
- private Texture2D mainTexture = null;
- private Texture2D secondTexture = null;
- private Texture2D screenTexture = null;
-
- private Quad fullScreenQuad = null;
-
- private GLSLShaderObjectsState extractionShader = null;
- private GLSLShaderObjectsState blurShader = null;
- private GLSLShaderObjectsState blurShaderHorizontal = null;
- private GLSLShaderObjectsState blurShaderVertical = null;
- private GLSLShaderObjectsState finalShader = null;
-
- private final Camera cam;
- private final int renderScale;
-
- private int nrBlurPasses;
- private float blurSize;
- private float blurIntensityMultiplier;
- private float exposurePow;
- private float exposureCutoff;
- private boolean supported = true;
- private boolean useCurrentScene = false;
-
- private boolean useSeparateConvolution = false;
-
- public static String shaderDirectory = "com/ardor3d/extension/effect/bloom/";
-
- private boolean initialized = false;
-
- /**
- * Reset bloom parameters to default
- */
- public void resetParameters() {
- nrBlurPasses = 2;
- blurSize = 0.02f;
- blurIntensityMultiplier = 1.3f;
- exposurePow = 3.0f;
- exposureCutoff = 0.0f;
- }
-
- /**
- * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
- */
- @Override
- public void cleanUp() {
- super.cleanUp();
- if (tRenderer != null) {
- tRenderer.cleanup();
- }
- if (fullTRenderer != null) {
- fullTRenderer.cleanup();
- }
- }
-
- public boolean isSupported() {
- return supported;
- }
-
- /**
- * Creates a new bloom renderpass
- *
- * @param cam
- * Camera used for rendering the bloomsource
- * @param renderScale
- * Scale of bloom texture
- */
- public BloomRenderPass(final Camera cam, final int renderScale) {
- this.cam = cam;
- this.renderScale = renderScale;
- resetParameters();
- }
-
- @Override
- protected void doUpdate(final double tpf) {
- super.doUpdate(tpf);
- sinceLast += tpf;
- }
-
- @Override
- public void doRender(final Renderer r) {
- if (!initialized) {
- doInit(r);
- }
-
- if (!isSupported() || !useCurrentScene && _spatials.size() == 0) {
- return;
- }
-
- final BlendState blend = (BlendState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Blend);
-
- if (sinceLast > throttle) {
- sinceLast = 0;
-
- tRenderer.getCamera().setLocation(cam.getLocation());
- tRenderer.getCamera().setDirection(cam.getDirection());
- tRenderer.getCamera().setUp(cam.getUp());
- tRenderer.getCamera().setLeft(cam.getLeft());
-
- blend.setEnabled(false);
- final TextureState ts = (TextureState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Texture);
-
- // see if we should use the current scene to bloom, or only things added to the pass.
- if (useCurrentScene) {
- // grab backbuffer to texture
- if (screenTexture == null) {
- final DisplaySettings settings = new DisplaySettings(cam.getWidth(), cam.getHeight(), 24, 0, 0, 8,
- 0, 0, false, false);
- fullTRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r,
- ContextManager.getCurrentContext().getCapabilities());
- screenTexture = new Texture2D();
- screenTexture.setWrap(Texture.WrapMode.Clamp);
- screenTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- fullTRenderer.setupTexture(screenTexture);
- }
- fullTRenderer.copyToTexture(screenTexture, 0, 0, cam.getWidth(), cam.getHeight(), 0, 0);
- ts.setTexture(screenTexture, 0);
- } else {
- // Render scene to texture
- tRenderer.render(_spatials, mainTexture, Renderer.BUFFER_COLOR_AND_DEPTH);
- ts.setTexture(mainTexture, 0);
- }
-
- // Extract intensity
- extractionShader.setUniform("exposurePow", getExposurePow());
- extractionShader.setUniform("exposureCutoff", getExposureCutoff());
-
- fullScreenQuad.setRenderState(extractionShader);
- fullScreenQuad.updateWorldRenderStates(false);
- // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = extractionShader;
- tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
-
- if (!useSeparateConvolution) {
- blurShader.setUniform("sampleDist", getBlurSize());
- blurShader.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());
-
- ts.setTexture(secondTexture, 0);
- fullScreenQuad.setRenderState(blurShader);
- fullScreenQuad.updateWorldRenderStates(false);
- // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShader;
- tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
-
- // Extra blur passes
- for (int i = 1; i < getNrBlurPasses(); i++) {
- blurShader.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
- if (i % 2 == 1) {
- ts.setTexture(mainTexture, 0);
- tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
- } else {
- ts.setTexture(secondTexture, 0);
- tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
- }
- }
- if (getNrBlurPasses() % 2 == 1) {
- ts.setTexture(mainTexture, 0);
- } else {
- ts.setTexture(secondTexture, 0);
- tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
- ts.setTexture(mainTexture, 0);
- }
- } else {
- blurShaderVertical.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());
-
- for (int i = 0; i < getNrBlurPasses(); i++) {
- blurShaderHorizontal
- .setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
- blurShaderVertical.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
-
- ts.setTexture(secondTexture, 0);
- fullScreenQuad.setRenderState(blurShaderHorizontal);
- fullScreenQuad.updateWorldRenderStates(false);
- // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderHorizontal;
- tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
- ts.setTexture(mainTexture, 0);
- fullScreenQuad.setRenderState(blurShaderVertical);
- fullScreenQuad.updateWorldRenderStates(false);
- // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderVertical;
- tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
- }
- ts.setTexture(secondTexture, 0);
- }
- }
-
- // Final blend
- blend.setEnabled(true);
-
- fullScreenQuad.setRenderState(finalShader);
- fullScreenQuad.updateWorldRenderStates(false);
- // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = finalShader;
- r.draw((Renderable) fullScreenQuad);
- }
-
- private void doInit(final Renderer r) {
- initialized = true;
-
- cleanUp();
-
- // Test for glsl support
- final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
- if (!caps.isGLSLSupported() || !(caps.isPbufferSupported() || caps.isFBOSupported())) {
- supported = false;
- return;
- }
-
- // Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
- final DisplaySettings settings = new DisplaySettings(cam.getWidth() / renderScale, cam.getHeight()
- / renderScale, 24, 0, 0, 8, 0, 0, false, false);
- tRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r, ContextManager
- .getCurrentContext().getCapabilities());
-
- if (tRenderer == null) {
- supported = false;
- return;
- }
- tRenderer.setMultipleTargets(true);
- tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
- tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
- cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
-
- mainTexture = new Texture2D();
- mainTexture.setWrap(Texture.WrapMode.Clamp);
- mainTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- tRenderer.setupTexture(mainTexture);
-
- secondTexture = new Texture2D();
- secondTexture.setWrap(Texture.WrapMode.Clamp);
- secondTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- tRenderer.setupTexture(secondTexture);
-
- extractionShader = new GLSLShaderObjectsState();
- try {
- extractionShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_extract.vert"));
- extractionShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_extract.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- extractionShader.setUniform("RT", 0);
-
- // Create blur shader
- blurShader = new GLSLShaderObjectsState();
- try {
- blurShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_blur.vert"));
- blurShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_blur.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- blurShader.setUniform("RT", 0);
-
- // Create blur shader horizontal
- blurShaderHorizontal = new GLSLShaderObjectsState();
- try {
- blurShaderHorizontal.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
- BloomRenderPass.class, shaderDirectory + "bloom_blur.vert"));
- blurShaderHorizontal.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
- BloomRenderPass.class, shaderDirectory + "bloom_blur_horizontal7.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- blurShaderHorizontal.setUniform("RT", 0);
-
- // Create blur shader vertical
- blurShaderVertical = new GLSLShaderObjectsState();
- try {
- blurShaderVertical.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_blur.vert"));
- blurShaderVertical.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
- BloomRenderPass.class, shaderDirectory + "bloom_blur_vertical7.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- blurShaderVertical.setUniform("RT", 0);
-
- // Create final shader(basic texturing)
- finalShader = new GLSLShaderObjectsState();
- try {
- finalShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_final.vert"));
- finalShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
- shaderDirectory + "bloom_final.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
-
- // Create fullscreen quad
- fullScreenQuad = new Quad("FullScreenQuad", cam.getWidth() / 4, cam.getHeight() / 4);
- fullScreenQuad.setTranslation(cam.getWidth() / 2, cam.getHeight() / 2, 0);
- fullScreenQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho);
-
- fullScreenQuad.getSceneHints().setCullHint(CullHint.Never);
- fullScreenQuad.getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
- fullScreenQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off);
-
- final TextureState ts = new TextureState();
- ts.setEnabled(true);
- fullScreenQuad.setRenderState(ts);
-
- final BlendState as = new BlendState();
- as.setBlendEnabled(true);
- as.setSourceFunction(BlendState.SourceFunction.One);
- as.setDestinationFunction(BlendState.DestinationFunction.One);
- as.setEnabled(true);
- fullScreenQuad.setRenderState(as);
-
- fullScreenQuad.updateGeometricState(0.0f, true);
- }
-
- /**
- * @return The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
- * updated.
- */
- public double getThrottle() {
- return throttle;
- }
-
- /**
- * @param throttle
- * The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
- * updated.
- */
- public void setThrottle(final float throttle) {
- this.throttle = throttle;
- }
-
- public float getBlurSize() {
- return blurSize;
- }
-
- public void setBlurSize(final float blurSize) {
- this.blurSize = blurSize;
- }
-
- public float getExposurePow() {
- return exposurePow;
- }
-
- public void setExposurePow(final float exposurePow) {
- this.exposurePow = exposurePow;
- }
-
- public float getExposureCutoff() {
- return exposureCutoff;
- }
-
- public void setExposureCutoff(final float exposureCutoff) {
- this.exposureCutoff = exposureCutoff;
- }
-
- public float getBlurIntensityMultiplier() {
- return blurIntensityMultiplier;
- }
-
- public void setBlurIntensityMultiplier(final float blurIntensityMultiplier) {
- this.blurIntensityMultiplier = blurIntensityMultiplier;
- }
-
- public int getNrBlurPasses() {
- return nrBlurPasses;
- }
-
- public void setNrBlurPasses(final int nrBlurPasses) {
- this.nrBlurPasses = nrBlurPasses;
- }
-
- public boolean useCurrentScene() {
- return useCurrentScene;
- }
-
- public void setUseCurrentScene(final boolean useCurrentScene) {
- this.useCurrentScene = useCurrentScene;
- }
-
- public void setUseSeparateConvolution(final boolean useSeparateConvolution) {
- this.useSeparateConvolution = useSeparateConvolution;
- }
-
- public boolean isUseSeparateConvolution() {
- return useSeparateConvolution;
- }
-
- public void markNeedsRefresh() {
- initialized = false;
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.bloom;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.framework.DisplaySettings;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture2D;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRenderer;
+import com.ardor3d.renderer.TextureRendererFactory;
+import com.ardor3d.renderer.pass.Pass;
+import com.ardor3d.renderer.queue.RenderBucketType;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.RenderState;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.scenegraph.Renderable;
+import com.ardor3d.scenegraph.hint.CullHint;
+import com.ardor3d.scenegraph.hint.LightCombineMode;
+import com.ardor3d.scenegraph.hint.TextureCombineMode;
+import com.ardor3d.scenegraph.shape.Quad;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+
+/**
+ * GLSL bloom effect pass. - Render supplied source to a texture - Extract intensity - Blur intensity - Blend with first
+ * pass
+ */
+public class BloomRenderPass extends Pass {
+ /** The Constant logger. */
+ private static final Logger logger = Logger.getLogger(BloomRenderPass.class.getName());
+
+ private static final long serialVersionUID = 1L;
+
+ private double throttle = 0;
+ private double sinceLast = 1;
+
+ private TextureRenderer tRenderer = null;
+ private TextureRenderer fullTRenderer = null;
+ private Texture2D mainTexture = null;
+ private Texture2D secondTexture = null;
+ private Texture2D screenTexture = null;
+
+ private Quad fullScreenQuad = null;
+
+ private GLSLShaderObjectsState extractionShader = null;
+ private GLSLShaderObjectsState blurShader = null;
+ private GLSLShaderObjectsState blurShaderHorizontal = null;
+ private GLSLShaderObjectsState blurShaderVertical = null;
+ private GLSLShaderObjectsState finalShader = null;
+
+ private final Camera cam;
+ private final int renderScale;
+
+ private int nrBlurPasses;
+ private float blurSize;
+ private float blurIntensityMultiplier;
+ private float exposurePow;
+ private float exposureCutoff;
+ private boolean supported = true;
+ private boolean useCurrentScene = false;
+
+ private boolean useSeparateConvolution = false;
+
+ public static String shaderDirectory = "com/ardor3d/extension/effect/bloom/";
+
+ private boolean initialized = false;
+
+ /**
+ * Reset bloom parameters to default
+ */
+ public void resetParameters() {
+ nrBlurPasses = 2;
+ blurSize = 0.02f;
+ blurIntensityMultiplier = 1.3f;
+ exposurePow = 3.0f;
+ exposureCutoff = 0.0f;
+ }
+
+ /**
+ * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
+ */
+ @Override
+ public void cleanUp() {
+ super.cleanUp();
+ if (tRenderer != null) {
+ tRenderer.cleanup();
+ }
+ if (fullTRenderer != null) {
+ fullTRenderer.cleanup();
+ }
+ }
+
+ public boolean isSupported() {
+ return supported;
+ }
+
+ /**
+ * Creates a new bloom renderpass
+ *
+ * @param cam
+ * Camera used for rendering the bloomsource
+ * @param renderScale
+ * Scale of bloom texture
+ */
+ public BloomRenderPass(final Camera cam, final int renderScale) {
+ this.cam = cam;
+ this.renderScale = renderScale;
+ resetParameters();
+ }
+
+ @Override
+ protected void doUpdate(final double tpf) {
+ super.doUpdate(tpf);
+ sinceLast += tpf;
+ }
+
+ @Override
+ public void doRender(final Renderer r) {
+ if (!initialized) {
+ doInit(r);
+ }
+
+ if (!isSupported() || !useCurrentScene && _spatials.size() == 0) {
+ return;
+ }
+
+ final BlendState blend = (BlendState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Blend);
+
+ if (sinceLast > throttle) {
+ sinceLast = 0;
+
+ tRenderer.getCamera().setLocation(cam.getLocation());
+ tRenderer.getCamera().setDirection(cam.getDirection());
+ tRenderer.getCamera().setUp(cam.getUp());
+ tRenderer.getCamera().setLeft(cam.getLeft());
+
+ blend.setEnabled(false);
+ final TextureState ts = (TextureState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Texture);
+
+ // see if we should use the current scene to bloom, or only things added to the pass.
+ if (useCurrentScene) {
+ // grab backbuffer to texture
+ if (screenTexture == null) {
+ final DisplaySettings settings = new DisplaySettings(cam.getWidth(), cam.getHeight(), 24, 0, 0, 8,
+ 0, 0, false, false);
+ fullTRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r,
+ ContextManager.getCurrentContext().getCapabilities());
+ screenTexture = new Texture2D();
+ screenTexture.setWrap(Texture.WrapMode.Clamp);
+ screenTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ fullTRenderer.setupTexture(screenTexture);
+ }
+ fullTRenderer.copyToTexture(screenTexture, 0, 0, cam.getWidth(), cam.getHeight(), 0, 0);
+ ts.setTexture(screenTexture, 0);
+ } else {
+ // Render scene to texture
+ tRenderer.render(_spatials, mainTexture, Renderer.BUFFER_COLOR_AND_DEPTH);
+ ts.setTexture(mainTexture, 0);
+ }
+
+ // Extract intensity
+ extractionShader.setUniform("exposurePow", getExposurePow());
+ extractionShader.setUniform("exposureCutoff", getExposureCutoff());
+
+ fullScreenQuad.setRenderState(extractionShader);
+ fullScreenQuad.updateWorldRenderStates(false);
+ // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = extractionShader;
+ tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
+
+ if (!useSeparateConvolution) {
+ blurShader.setUniform("sampleDist", getBlurSize());
+ blurShader.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());
+
+ ts.setTexture(secondTexture, 0);
+ fullScreenQuad.setRenderState(blurShader);
+ fullScreenQuad.updateWorldRenderStates(false);
+ // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShader;
+ tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
+
+ // Extra blur passes
+ for (int i = 1; i < getNrBlurPasses(); i++) {
+ blurShader.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
+ if (i % 2 == 1) {
+ ts.setTexture(mainTexture, 0);
+ tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
+ } else {
+ ts.setTexture(secondTexture, 0);
+ tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
+ }
+ }
+ if (getNrBlurPasses() % 2 == 1) {
+ ts.setTexture(mainTexture, 0);
+ } else {
+ ts.setTexture(secondTexture, 0);
+ tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
+ ts.setTexture(mainTexture, 0);
+ }
+ } else {
+ blurShaderVertical.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());
+
+ for (int i = 0; i < getNrBlurPasses(); i++) {
+ blurShaderHorizontal
+ .setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
+ blurShaderVertical.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
+
+ ts.setTexture(secondTexture, 0);
+ fullScreenQuad.setRenderState(blurShaderHorizontal);
+ fullScreenQuad.updateWorldRenderStates(false);
+ // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderHorizontal;
+ tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
+ ts.setTexture(mainTexture, 0);
+ fullScreenQuad.setRenderState(blurShaderVertical);
+ fullScreenQuad.updateWorldRenderStates(false);
+ // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderVertical;
+ tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
+ }
+ ts.setTexture(secondTexture, 0);
+ }
+ }
+
+ // Final blend
+ blend.setEnabled(true);
+
+ fullScreenQuad.setRenderState(finalShader);
+ fullScreenQuad.updateWorldRenderStates(false);
+ // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = finalShader;
+ r.draw((Renderable) fullScreenQuad);
+ }
+
+ private void doInit(final Renderer r) {
+ initialized = true;
+
+ cleanUp();
+
+ // Test for glsl support
+ final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
+ if (!caps.isGLSLSupported() || !(caps.isPbufferSupported() || caps.isFBOSupported())) {
+ supported = false;
+ return;
+ }
+
+ // Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
+ final DisplaySettings settings = new DisplaySettings(cam.getWidth() / renderScale, cam.getHeight()
+ / renderScale, 24, 0, 0, 8, 0, 0, false, false);
+ tRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r, ContextManager
+ .getCurrentContext().getCapabilities());
+
+ if (tRenderer == null) {
+ supported = false;
+ return;
+ }
+ tRenderer.setMultipleTargets(true);
+ tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
+ tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
+ cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
+
+ mainTexture = new Texture2D();
+ mainTexture.setWrap(Texture.WrapMode.Clamp);
+ mainTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ tRenderer.setupTexture(mainTexture);
+
+ secondTexture = new Texture2D();
+ secondTexture.setWrap(Texture.WrapMode.Clamp);
+ secondTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ tRenderer.setupTexture(secondTexture);
+
+ extractionShader = new GLSLShaderObjectsState();
+ try {
+ extractionShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_extract.vert"));
+ extractionShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_extract.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ extractionShader.setUniform("RT", 0);
+
+ // Create blur shader
+ blurShader = new GLSLShaderObjectsState();
+ try {
+ blurShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_blur.vert"));
+ blurShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_blur.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ blurShader.setUniform("RT", 0);
+
+ // Create blur shader horizontal
+ blurShaderHorizontal = new GLSLShaderObjectsState();
+ try {
+ blurShaderHorizontal.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ BloomRenderPass.class, shaderDirectory + "bloom_blur.vert"));
+ blurShaderHorizontal.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ BloomRenderPass.class, shaderDirectory + "bloom_blur_horizontal7.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ blurShaderHorizontal.setUniform("RT", 0);
+
+ // Create blur shader vertical
+ blurShaderVertical = new GLSLShaderObjectsState();
+ try {
+ blurShaderVertical.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_blur.vert"));
+ blurShaderVertical.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ BloomRenderPass.class, shaderDirectory + "bloom_blur_vertical7.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ blurShaderVertical.setUniform("RT", 0);
+
+ // Create final shader(basic texturing)
+ finalShader = new GLSLShaderObjectsState();
+ try {
+ finalShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_final.vert"));
+ finalShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
+ shaderDirectory + "bloom_final.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+
+ // Create fullscreen quad
+ fullScreenQuad = new Quad("FullScreenQuad", cam.getWidth() / 4, cam.getHeight() / 4);
+ fullScreenQuad.setTranslation(cam.getWidth() / 2, cam.getHeight() / 2, 0);
+ fullScreenQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho);
+
+ fullScreenQuad.getSceneHints().setCullHint(CullHint.Never);
+ fullScreenQuad.getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
+ fullScreenQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off);
+
+ final TextureState ts = new TextureState();
+ ts.setEnabled(true);
+ fullScreenQuad.setRenderState(ts);
+
+ final BlendState as = new BlendState();
+ as.setBlendEnabled(true);
+ as.setSourceFunction(BlendState.SourceFunction.One);
+ as.setDestinationFunction(BlendState.DestinationFunction.One);
+ as.setEnabled(true);
+ fullScreenQuad.setRenderState(as);
+
+ fullScreenQuad.updateGeometricState(0.0f, true);
+ }
+
+ /**
+ * @return The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
+ * updated.
+ */
+ public double getThrottle() {
+ return throttle;
+ }
+
+ /**
+ * @param throttle
+ * The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
+ * updated.
+ */
+ public void setThrottle(final float throttle) {
+ this.throttle = throttle;
+ }
+
+ public float getBlurSize() {
+ return blurSize;
+ }
+
+ public void setBlurSize(final float blurSize) {
+ this.blurSize = blurSize;
+ }
+
+ public float getExposurePow() {
+ return exposurePow;
+ }
+
+ public void setExposurePow(final float exposurePow) {
+ this.exposurePow = exposurePow;
+ }
+
+ public float getExposureCutoff() {
+ return exposureCutoff;
+ }
+
+ public void setExposureCutoff(final float exposureCutoff) {
+ this.exposureCutoff = exposureCutoff;
+ }
+
+ public float getBlurIntensityMultiplier() {
+ return blurIntensityMultiplier;
+ }
+
+ public void setBlurIntensityMultiplier(final float blurIntensityMultiplier) {
+ this.blurIntensityMultiplier = blurIntensityMultiplier;
+ }
+
+ public int getNrBlurPasses() {
+ return nrBlurPasses;
+ }
+
+ public void setNrBlurPasses(final int nrBlurPasses) {
+ this.nrBlurPasses = nrBlurPasses;
+ }
+
+ public boolean useCurrentScene() {
+ return useCurrentScene;
+ }
+
+ public void setUseCurrentScene(final boolean useCurrentScene) {
+ this.useCurrentScene = useCurrentScene;
+ }
+
+ public void setUseSeparateConvolution(final boolean useSeparateConvolution) {
+ this.useSeparateConvolution = useSeparateConvolution;
+ }
+
+ public boolean isUseSeparateConvolution() {
+ return useSeparateConvolution;
+ }
+
+ public void markNeedsRefresh() {
+ initialized = false;
+ }
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/Particle.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/Particle.java
index 48ff5ff..6917d70 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/Particle.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/Particle.java
@@ -250,9 +250,6 @@ public class Particle implements Savable {
* (interpolating between start and end size), spin (using parent's spin speed) and current age of particle. If this
* particle's age is greater than its lifespan, it is set to status DEAD.
* </p>
- * <p>
- * Note that this only changes the parameters of the Particle, not the geometry the particle is associated with.
- * </p>
*
* @param secondsPassed
* number of seconds passed since last update.
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleControllerListener.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleControllerListener.java
index 1b5b40b..d50e39e 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleControllerListener.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleControllerListener.java
@@ -1,18 +1,18 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.particle;
-
-/**
- * ParticleControllerListener This interface is used to receive key events from ParticleController
- */
-public interface ParticleControllerListener {
- void onDead(ParticleSystem particles);
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.particle;
+
+/**
+ * ParticleControllerListener This interface is used to receive key events from ParticleController
+ */
+public interface ParticleControllerListener {
+ void onDead(ParticleSystem particles);
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleFactory.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleFactory.java
index d212e6b..e0ebd1e 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleFactory.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleFactory.java
@@ -1,47 +1,47 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.particle;
-
-import com.ardor3d.extension.effect.particle.ParticleSystem.ParticleType;
-import com.ardor3d.scenegraph.Mesh;
-
-public class ParticleFactory {
-
- public static ParticleSystem buildParticles(final String name, final int number) {
- return buildParticles(name, number, ParticleSystem.ParticleType.Quad);
- }
-
- public static ParticleSystem buildParticles(final String name, final int number,
- final ParticleSystem.ParticleType particleType) {
- if (particleType == ParticleSystem.ParticleType.GeomMesh) {
- throw new IllegalArgumentException("particleType can not be GeomMesh");
- }
- ParticleSystem system;
- if (particleType == ParticleType.Point) {
- system = new ParticlePoints(name, number);
- } else if (particleType == ParticleType.Line) {
- system = new ParticleLines(name, number);
- } else {
- system = new ParticleMesh(name, number, particleType);
- }
- final ParticleController particleController = new ParticleController();
- system.addController(particleController);
- return system;
- }
-
- public static ParticleMesh buildMeshParticles(final String name, final Mesh mesh) {
- final ParticleMesh particleMesh = new ParticleMesh(name, mesh);
- final ParticleController particleController = new ParticleController();
- particleMesh.addController(particleController);
- return particleMesh;
- }
-
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.particle;
+
+import com.ardor3d.extension.effect.particle.ParticleSystem.ParticleType;
+import com.ardor3d.scenegraph.Mesh;
+
+public class ParticleFactory {
+
+ public static ParticleSystem buildParticles(final String name, final int number) {
+ return buildParticles(name, number, ParticleSystem.ParticleType.Quad);
+ }
+
+ public static ParticleSystem buildParticles(final String name, final int number,
+ final ParticleSystem.ParticleType particleType) {
+ if (particleType == ParticleSystem.ParticleType.GeomMesh) {
+ throw new IllegalArgumentException("particleType can not be GeomMesh");
+ }
+ ParticleSystem system;
+ if (particleType == ParticleType.Point) {
+ system = new ParticlePoints(name, number);
+ } else if (particleType == ParticleType.Line) {
+ system = new ParticleLines(name, number);
+ } else {
+ system = new ParticleMesh(name, number, particleType);
+ }
+ final ParticleController particleController = new ParticleController();
+ system.addController(particleController);
+ return system;
+ }
+
+ public static ParticleMesh buildMeshParticles(final String name, final Mesh mesh) {
+ final ParticleMesh particleMesh = new ParticleMesh(name, mesh);
+ final ParticleController particleController = new ParticleController();
+ particleMesh.addController(particleController);
+ return particleMesh;
+ }
+
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleMesh.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleMesh.java
index c700471..2d70080 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleMesh.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleMesh.java
@@ -126,7 +126,7 @@ public class ParticleMesh extends ParticleSystem {
if (_particleType == ParticleSystem.ParticleType.GeomMesh && _useMeshTexCoords) {
final MeshEmitter source = (MeshEmitter) getParticleEmitter();
final Mesh sourceMesh = source.getSource();
- final int index = sourceMesh.getMeshData().getIndexBuffer() != null ? sourceMesh.getMeshData()
+ final int index = sourceMesh.getMeshData().getIndices() != null ? sourceMesh.getMeshData()
.getIndices().get(ind) : ind;
BufferUtils.populateFromBuffer(temp, sourceMesh.getMeshData().getTextureCoords(0).getBuffer(),
index);
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleSystem.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleSystem.java
index aa41a49..077bed0 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleSystem.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/ParticleSystem.java
@@ -1,1082 +1,1082 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.particle;
-
-import java.io.IOException;
-import java.nio.FloatBuffer;
-import java.util.List;
-import java.util.logging.Logger;
-
-import com.ardor3d.extension.effect.particle.emitter.MeshEmitter;
-import com.ardor3d.extension.effect.particle.emitter.SavableParticleEmitter;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Matrix3;
-import com.ardor3d.math.Transform;
-import com.ardor3d.math.Triangle;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.type.ReadOnlyColorRGBA;
-import com.ardor3d.math.type.ReadOnlyMatrix3;
-import com.ardor3d.math.type.ReadOnlyTransform;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.scenegraph.Mesh;
-import com.ardor3d.scenegraph.MeshData;
-import com.ardor3d.scenegraph.Node;
-import com.ardor3d.scenegraph.Spatial;
-import com.ardor3d.scenegraph.controller.ComplexSpatialController.RepeatType;
-import com.ardor3d.scenegraph.controller.SpatialController;
-import com.ardor3d.scenegraph.event.DirtyType;
-import com.ardor3d.util.export.InputCapsule;
-import com.ardor3d.util.export.OutputCapsule;
-import com.ardor3d.util.geom.BufferUtils;
-
-/**
- * ParticleSystem is an abstract class representing a particle system. A ParticleController must be attached for the
- * effect to be complete.
- */
-public abstract class ParticleSystem extends Node {
- private static final Logger logger = Logger.getLogger(ParticleSystem.class.getName());
-
- public enum ParticleType {
- Quad, Triangle, Point, Line, GeomMesh;
- }
-
- protected static final double DEFAULT_END_SIZE = 4;
- protected static final double DEFAULT_START_SIZE = 20;
- protected static final double DEFAULT_MAX_ANGLE = 0.7853982;
- protected static final double DEFAULT_MAX_LIFE = 3000;
- protected static final double DEFAULT_MIN_LIFE = 2000;
-
- protected static final ReadOnlyColorRGBA DEFAULT_START_COLOR = new ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f);
- protected static final ReadOnlyColorRGBA DEFAULT_END_COLOR = new ColorRGBA(1.0f, 1.0f, 0.0f, 0.0f);
-
- protected ParticleType _particleType;
- protected SavableParticleEmitter _particleEmitter;
- protected boolean _cameraFacing = true;
- protected boolean _velocityAligned = false;
- protected boolean _particlesInWorldCoords = true;
-
- protected double _startSize, _endSize;
- protected final ColorRGBA _startColor = new ColorRGBA(DEFAULT_START_COLOR);
- protected final ColorRGBA _endColor = new ColorRGBA(DEFAULT_END_COLOR);
- protected ParticleAppearanceRamp _ramp = new ParticleAppearanceRamp();
- protected TexAnimation _texAnimation = new TexAnimation();
- protected double _initialVelocity;
- protected double _minimumLifeTime, _maximumLifeTime;
- protected double _minimumAngle, _maximumAngle;
- protected double _startSpin, _endSpin;
- protected double _startMass, _endMass;
- protected int _startTexIndex, _texQuantity;
- protected final Vector3 _emissionDirection = new Vector3(Vector3.UNIT_Y);
- protected final Transform _emitterTransform = new Transform();
- protected final Vector3 _worldEmit = new Vector3();
- protected int _numParticles;
- protected boolean _rotateWithScene = false;
- protected final Matrix3 _rotMatrix = new Matrix3();
- protected double _particleOrientation;
-
- protected FloatBuffer _geometryCoordinates;
- protected FloatBuffer _appearanceColors;
-
- // vectors to prevent repeated object creation:
- protected final Vector3 _upXemit = new Vector3(), _absUpVector = new Vector3(), _abUpMinUp = new Vector3();
- protected final Vector3 _upVector = new Vector3(Vector3.UNIT_Y);
- protected final Vector3 _leftVector = new Vector3(-1, 0, 0);
- protected final Vector3 _invScale = new Vector3();
-
- // These vectors are used for determining particle orientation if you turn off camera facing
- protected final Vector3 _facingUpVector = new Vector3(Vector3.UNIT_Y);
- protected final Vector3 _facingLeftVector = new Vector3(-1, 0, 0);
-
- protected Particle _particles[];
-
- // protected Vector3 particleSpeed;
- protected int _releaseRate; // particles per second
- protected final Vector3 _originOffset = new Vector3();
- protected final Vector3 _originCenter = new Vector3();
-
- protected Mesh _particleMesh;
- protected ParticleController _controller;
-
- protected Vector3 _oldEmit = new Vector3(Float.NaN, Float.NaN, Float.NaN);
- protected double _matData[] = new double[9];
-
- public ParticleSystem() {}
-
- public ParticleSystem(final String name, final int numParticles) {
- this(name, numParticles, ParticleType.Quad);
- }
-
- public ParticleSystem(final String name, final int numParticles, final ParticleType particleType) {
- super(name);
- _numParticles = numParticles;
- _particleType = particleType;
- _minimumLifeTime = DEFAULT_MIN_LIFE;
- _maximumLifeTime = DEFAULT_MAX_LIFE;
- _maximumAngle = DEFAULT_MAX_ANGLE;
- _startSize = DEFAULT_START_SIZE;
- _endSize = DEFAULT_END_SIZE;
- _startSpin = 0;
- _endSpin = 0;
- _startMass = 1;
- _endMass = 1;
- _startTexIndex = 0;
- _texQuantity = 1;
- _releaseRate = numParticles;
- _initialVelocity = 1.0;
-
- initializeParticles(numParticles);
- }
-
- protected abstract void initializeParticles(int numParticles);
-
- public static int getVertsForParticleType(final ParticleType type) {
- if (type == null) {
- throw new NullPointerException("type is null");
- }
- switch (type) {
- case Triangle:
- case GeomMesh:
- return 3;
- case Point:
- return 1;
- case Line:
- return 2;
- case Quad:
- return 4;
- }
- throw new IllegalArgumentException("Invalid ParticleType: " + type);
- }
-
- public void forceRespawn() {
- for (final Particle p : _particles) {
- p.recreateParticle(0);
- p.setStatus(Particle.Status.Alive);
- p.updateAndCheck(1);
- p.setStatus(Particle.Status.Available);
- }
-
- if (_controller != null) {
- _controller.setActive(true);
- }
- }
-
- /**
- * Setup the rotation matrix used to determine initial particle velocity based on emission angle and emission
- * direction. called automatically by the set* methods for those parameters.
- */
- public void updateRotationMatrix() {
-
- if (_oldEmit.equals(_worldEmit)) {
- return;
- }
-
- final double upDotEmit = _upVector.dot(_worldEmit);
- if (Math.abs(upDotEmit) > 1.0 - MathUtils.EPSILON) {
- _absUpVector.setX(_upVector.getX() <= 0.0 ? -_upVector.getX() : _upVector.getX());
- _absUpVector.setY(_upVector.getY() <= 0.0 ? -_upVector.getY() : _upVector.getY());
- _absUpVector.setZ(_upVector.getZ() <= 0.0 ? -_upVector.getZ() : _upVector.getZ());
- if (_absUpVector.getX() < _absUpVector.getY()) {
- if (_absUpVector.getX() < _absUpVector.getZ()) {
- _absUpVector.set(Vector3.UNIT_X);
- } else {
- _absUpVector.set(Vector3.UNIT_Z);
- }
- } else if (_absUpVector.getY() < _absUpVector.getZ()) {
- _absUpVector.set(Vector3.UNIT_Y);
- } else {
- _absUpVector.set(Vector3.UNIT_Z);
- }
- _absUpVector.subtract(_upVector, _abUpMinUp);
- _absUpVector.subtract(_worldEmit, _upXemit);
- final double f4 = 2.0 / _abUpMinUp.dot(_abUpMinUp);
- final double f6 = 2.0 / _upXemit.dot(_upXemit);
- final double f8 = f4 * f6 * _abUpMinUp.dot(_upXemit);
- final double af1[] = { _abUpMinUp.getX(), _abUpMinUp.getY(), _abUpMinUp.getZ() };
- final double af2[] = { _upXemit.getX(), _upXemit.getY(), _upXemit.getZ() };
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- _matData[(i * 3) + j] = (-f4 * af1[i] * af1[j] - f6 * af2[i] * af2[j]) + f8 * af2[i] * af1[j];
-
- }
- _matData[(i * 3) + i]++;
- }
-
- } else {
- _upVector.cross(_worldEmit, _upXemit);
- final double f2 = 1.0 / (1.0 + upDotEmit);
- final double f5 = f2 * _upXemit.getX();
- final double f7 = f2 * _upXemit.getZ();
- final double f9 = f5 * _upXemit.getY();
- final double f10 = f5 * _upXemit.getZ();
- final double f11 = f7 * _upXemit.getY();
- _matData[0] = upDotEmit + f5 * _upXemit.getX();
- _matData[1] = f9 - _upXemit.getZ();
- _matData[2] = f10 + _upXemit.getY();
- _matData[3] = f9 + _upXemit.getZ();
- _matData[4] = upDotEmit + f2 * _upXemit.getY() * _upXemit.getY();
- _matData[5] = f11 - _upXemit.getX();
- _matData[6] = f10 - _upXemit.getY();
- _matData[7] = f11 + _upXemit.getX();
- _matData[8] = upDotEmit + f7 * _upXemit.getZ();
- }
- _rotMatrix.fromArray(_matData);
- _oldEmit.set(_worldEmit);
- }
-
- public abstract Mesh getParticleGeometry();
-
- public ParticleController getParticleController() {
- return _controller;
- }
-
- @Override
- public void addController(final SpatialController<?> c) {
- super.addController(c);
- if (c instanceof ParticleController) {
- _controller = (ParticleController) c;
- }
- }
-
- public Vector3 getEmissionDirection() {
- return _emissionDirection;
- }
-
- public void setEmissionDirection(final ReadOnlyVector3 emissionDirection) {
- _emissionDirection.set(emissionDirection);
- _worldEmit.set(emissionDirection);
- }
-
- public double getEndSize() {
- return _endSize;
- }
-
- public void setEndSize(final double size) {
- _endSize = size >= 0.0 ? size : 0.0;
- }
-
- public double getStartSize() {
- return _startSize;
- }
-
- public void setStartSize(final double size) {
- _startSize = size >= 0.0 ? size : 0.0;
- }
-
- /**
- * Set the start color for particles.
- *
- * @param color
- * The new start color.
- */
- public void setStartColor(final ReadOnlyColorRGBA color) {
- _startColor.set(color);
- }
-
- /**
- * @return The start color.
- */
- public ReadOnlyColorRGBA getStartColor() {
- return _startColor;
- }
-
- /**
- * Set the end color for particles. The base color of the particle will linearly approach this color from the start
- * color over the lifetime of the particle.
- *
- * @param color
- * ColorRGBA The ending color.
- */
- public void setEndColor(final ReadOnlyColorRGBA color) {
- _endColor.set(color);
- }
-
- /**
- * getEndColor returns the ending color.
- *
- * @return The ending color
- */
- public ReadOnlyColorRGBA getEndColor() {
- return _endColor;
- }
-
- /**
- * Set the start and end spinSpeed of particles managed by this manager. Setting it to 0 means no spin.
- *
- * @param speed
- * double
- */
- public void setParticleSpinSpeed(final double speed) {
- _startSpin = speed;
- _endSpin = speed;
- }
-
- public Vector3 getInvScale() {
- return _invScale;
- }
-
- public void setInvScale(final ReadOnlyVector3 invScale) {
- _invScale.set(invScale);
- }
-
- public void updateInvScale() {
- _invScale.set(1.0 / getWorldScale().getX(), 1.0 / getWorldScale().getY(), 1.0 / getWorldScale().getZ());
- }
-
- /**
- * Add an external influence to the particle controller for this mesh.
- *
- * @param influence
- * ParticleInfluence
- */
- public void addInfluence(final ParticleInfluence influence) {
- _controller.addInfluence(influence);
- }
-
- /**
- * Remove an influence from the particle controller for this mesh.
- *
- * @param influence
- * ParticleInfluence
- * @return true if found and removed.
- */
- public boolean removeInfluence(final ParticleInfluence influence) {
- return _controller.removeInfluence(influence);
- }
-
- /**
- * Returns the list of influences acting on this particle controller.
- *
- * @return ArrayList
- */
- public List<ParticleInfluence> getInfluences() {
- return _controller.getInfluences();
- }
-
- public void clearInfluences() {
- _controller.clearInfluences();
- }
-
- public void setParticleMass(final double mass) {
- _startMass = _endMass = mass;
- }
-
- /**
- * Set the minimum angle (in radians) that particles can be emitted away from the emission direction. Any angle less
- * than 0 is trimmed to 0.
- *
- * @param f
- * The new emission minimum angle.
- */
- public void setMinimumAngle(final double f) {
- _minimumAngle = f >= 0.0 ? f : 0.0;
- }
-
- /**
- * getEmissionMinimumAngle returns the minimum emission angle.
- *
- * @return The minimum emission angle.
- */
- public double getMinimumAngle() {
- return _minimumAngle;
- }
-
- /**
- * Set the maximum angle (in radians) that particles can be emitted away from the emission direction. Any angle less
- * than 0 is trimmed to 0.
- *
- * @param f
- * The new emission maximum angle.
- */
- public void setMaximumAngle(final double f) {
- _maximumAngle = f >= 0.0 ? f : 0.0;
- }
-
- /**
- * getEmissionMaximumAngle returns the maximum emission angle.
- *
- * @return The maximum emission angle.
- */
- public double getMaximumAngle() {
- return _maximumAngle;
- }
-
- /**
- * Set the minimum lifespan of new particles (or recreated) managed by this manager. if a value less than zero is
- * given, 1.0 is used.
- *
- * @param lifeSpan
- * in ms
- */
- public void setMinimumLifeTime(final double lifeSpan) {
- _minimumLifeTime = lifeSpan >= 0.0 ? lifeSpan : 1.0;
- }
-
- /**
- * getParticlesMinimumLifeTime returns the minimum life time of a particle.
- *
- * @return The current minimum life time in ms.
- */
- public double getMinimumLifeTime() {
- return _minimumLifeTime;
- }
-
- /**
- * Set the maximum lifespan of new particles (or recreated) managed by this manager. if a value less than zero is
- * given, 1.0 is used.
- *
- * @param lifeSpan
- * in ms
- */
- public void setMaximumLifeTime(final double lifeSpan) {
- _maximumLifeTime = lifeSpan >= 0.0 ? lifeSpan : 1.0;
- }
-
- /**
- * getParticlesMaximumLifeTime returns the maximum life time of a particle.
- *
- * @return The current maximum life time in ms.
- */
- public double getMaximumLifeTime() {
- return _maximumLifeTime;
- }
-
- public ReadOnlyMatrix3 getRotMatrix() {
- return _rotMatrix;
- }
-
- public void setRotMatrix(final ReadOnlyMatrix3 rotMatrix) {
- _rotMatrix.set(rotMatrix);
- }
-
- public ReadOnlyTransform getEmitterTransform() {
- return _emitterTransform;
- }
-
- public void setEmitterTransform(final ReadOnlyTransform emitterTransform) {
- _emitterTransform.set(emitterTransform);
- }
-
- public double getParticleOrientation() {
- return _particleOrientation;
- }
-
- public void setParticleOrientation(final double orient) {
- _particleOrientation = orient;
- }
-
- /**
- * Set the acceleration for any new particles created (or recreated) by this manager.
- *
- * @param velocity
- * particle v0
- */
- public void setInitialVelocity(final double velocity) {
- _initialVelocity = velocity;
- }
-
- /**
- * Get the acceleration set in this manager.
- *
- * @return The initialVelocity
- */
- public double getInitialVelocity() {
- return _initialVelocity;
- }
-
- /**
- * Set the offset for any new particles created (or recreated) by this manager. This is applicable only to managers
- * generating from a point (not a line, rectangle, etc..)
- *
- * @param offset
- * new offset position
- */
- public void setOriginOffset(final ReadOnlyVector3 offset) {
- _originOffset.set(offset);
- }
-
- /**
- * Get the offset point set in this manager.
- *
- * @return origin
- */
- public ReadOnlyVector3 getOriginOffset() {
- return _originOffset;
- }
-
- public ReadOnlyVector3 getWorldEmit() {
- return _worldEmit;
- }
-
- public void setWorldEmit(final ReadOnlyVector3 worldEmit) {
- _worldEmit.set(worldEmit);
- }
-
- /**
- * Get the number of particles the manager should release per second.
- *
- * @return The number of particles that should be released per second.
- */
- public int getReleaseRate() {
- return _releaseRate;
- }
-
- /**
- * Set the number of particles the manager should release per second.
- *
- * @param particlesPerSecond
- * number of particles per second
- */
- public void setReleaseRate(final int particlesPerSecond) {
- final int oldRate = _releaseRate;
- _releaseRate = particlesPerSecond;
- if (_controller != null && !_controller.isActive() && _controller.isControlFlow() && oldRate == 0) {
- _controller.setActive(true);
- }
- }
-
- public double getEndMass() {
- return _endMass;
- }
-
- public void setEndMass(final double endMass) {
- _endMass = endMass;
- }
-
- public double getEndSpin() {
- return _endSpin;
- }
-
- public void setEndSpin(final double endSpin) {
- _endSpin = endSpin;
- }
-
- public double getStartMass() {
- return _startMass;
- }
-
- public void setStartMass(final double startMass) {
- _startMass = startMass;
- }
-
- public double getStartSpin() {
- return _startSpin;
- }
-
- public void setStartSpin(final double startSpin) {
- _startSpin = startSpin;
- }
-
- public int getTexQuantity() {
- return _texQuantity;
- }
-
- public void setTexQuantity(final int quantity) {
- _texQuantity = quantity;
- }
-
- public int getStartTexIndex() {
- return _startTexIndex;
- }
-
- public void setStartTexIndex(final int startTexIndex) {
- _startTexIndex = startTexIndex;
- }
-
- /**
- * Get which emittype method is being used by the underlying system. One of ParticleType.Quad,
- * ParticleType.Triangle, ParticleType.Point, ParticleType.Line, ParticleType.GeomMesh
- *
- * @return An int representing the type of particle we are emitting.
- */
- public ParticleType getParticleType() {
- return _particleType;
- }
-
- /**
- * Set what type of particle to emit from this sytem. Does not have an effect unless recreate is called.
- *
- * @param type
- * particle type to use, should be one of ParticleType.Quad, ParticleType.Triangle, ParticleType.Point,
- * ParticleType.Line, ParticleType.GeomMesh
- */
- public void setParticleType(final ParticleType type) {
- _particleType = type;
- }
-
- /**
- * Set our particle emitter.
- *
- * @param emitter
- * New emitter or null for default point emitter.
- */
- public void setParticleEmitter(final SavableParticleEmitter emitter) {
- _particleEmitter = emitter;
- }
-
- /**
- * @return the set particle emitter, or null if none is set.
- */
- public SavableParticleEmitter getParticleEmitter() {
- return _particleEmitter;
- }
-
- public void initAllParticlesLocation() {
- for (int i = _particles.length; --i >= 0;) {
- initParticleLocation(i);
- _particles[i].updateVerts(null);
- }
- getParticleGeometry().updateModelBound();
- }
-
- @Override
- public void onDraw(final Renderer r) {
- // make sure our particle world bound is correct
- updateWorldBoundManually();
-
- super.onDraw(r);
- };
-
- public void initParticleLocation(final int index) {
- final Particle p = _particles[index];
- if (getParticleType() == ParticleType.GeomMesh && getParticleEmitter() instanceof MeshEmitter) {
- final MeshEmitter emitter = (MeshEmitter) getParticleEmitter();
- final Mesh mesh = emitter.getSource();
-
- // Update the triangle model on each new particle creation.
- final Vector3[] vertices = new Vector3[3];
- final MeshData mData = mesh.getMeshData();
- for (int x = 0; x < 3; x++) {
- vertices[x] = new Vector3();
-
- final int vertIndex = mData.getVertexIndex(index, x, 0);
- BufferUtils.populateFromBuffer(vertices[x], mData.getVertexBuffer(),
- mData.getIndexBuffer() != null ? mData.getIndices().get(vertIndex) : vertIndex);
- }
- Triangle t = p.getTriangleModel();
- if (t == null) {
- t = new Triangle(vertices[0], vertices[1], vertices[2]);
- } else {
- t.setA(vertices[0]);
- t.setB(vertices[1]);
- t.setC(vertices[2]);
- }
- // turn the triangle corners into vector offsets from center
- for (int x = 0; x < 3; x++) {
- vertices[x].subtract(t.getCenter(), vertices[x]);
- t.set(x, vertices[x]);
- }
- p.setTriangleModel(t);
- mesh.localToWorld(t.getCenter(), p.getPosition());
- p.getPosition().multiplyLocal(getInvScale());
-
- } else if (getParticleEmitter() instanceof MeshEmitter) {
- final MeshEmitter emitter = (MeshEmitter) getParticleEmitter();
- final Mesh mesh = emitter.getSource();
- mesh.getMeshData().randomPointOnPrimitives(p.getPosition());
- mesh.localToWorld(p.getPosition(), p.getPosition());
- p.getPosition().multiplyLocal(getInvScale());
- } else {
- if (getParticleEmitter() != null) {
- getParticleEmitter().randomEmissionPoint(p.getPosition());
- } else {
- p.getPosition().set(_originOffset);
- }
-
- _emitterTransform.applyForward(p.getPosition());
- p.getPosition().divideLocal(_emitterTransform.getScale());
- }
- }
-
- public boolean isCameraFacing() {
- return _cameraFacing;
- }
-
- public void setCameraFacing(final boolean cameraFacing) {
- _cameraFacing = cameraFacing;
- }
-
- public boolean isVelocityAligned() {
- return _velocityAligned;
- }
-
- public void setVelocityAligned(final boolean velocityAligned) {
- _velocityAligned = velocityAligned;
- }
-
- public Particle getParticle(final int i) {
- return _particles[i];
- }
-
- public boolean isActive() {
- return _controller.isActive();
- }
-
- public void setSpeed(final double f) {
- _controller.setSpeed(f);
- }
-
- public void setRepeatType(final RepeatType type) {
- _controller.setRepeatType(type);
- }
-
- public void setControlFlow(final boolean b) {
- _controller.setControlFlow(b);
- }
-
- public ReadOnlyVector3 getOriginCenter() {
- return _originCenter;
- }
-
- public ReadOnlyVector3 getUpVector() {
- return _upVector;
- }
-
- public void setUpVector(final ReadOnlyVector3 vector) {
- _upVector.set(vector);
- }
-
- public ReadOnlyVector3 getLeftVector() {
- return _leftVector;
- }
-
- public void setLeftVector(final ReadOnlyVector3 vector) {
- _leftVector.set(vector);
- }
-
- public ReadOnlyVector3 getFacingUpVector() {
- return _facingUpVector;
- }
-
- /**
- * Used to determine particle orientation (only if cameraFacing is false.)
- *
- * @param vector
- */
- public void setFacingUpVector(final ReadOnlyVector3 vector) {
- _facingUpVector.set(vector);
- }
-
- public ReadOnlyVector3 getFacingLeftVector() {
- return _facingLeftVector;
- }
-
- /**
- * Used to determine particle orientation (only if cameraFacing is false.)
- *
- * @param vector
- */
- public void setFacingLeftVector(final ReadOnlyVector3 vector) {
- _facingLeftVector.set(vector);
- }
-
- public boolean isRotateWithScene() {
- return _rotateWithScene;
- }
-
- public void setRotateWithScene(final boolean rotate) {
- _rotateWithScene = rotate;
- }
-
- public void resetParticleVelocity(final int i) {
- getRandomVelocity(_particles[i].getVelocity());
- }
-
- /**
- * Returns a random angle between the min and max angles.
- *
- * @return the random angle.
- */
- public double getRandomAngle() {
- return getMinimumAngle() + MathUtils.nextRandomFloat() * (getMaximumAngle() - getMinimumAngle());
- }
-
- /**
- * generate a random lifespan between the min and max lifespan of the particle system.
- *
- * @return the generated lifespan value
- */
- public double getRandomLifeSpan() {
- return getMinimumLifeTime() + ((getMaximumLifeTime() - getMinimumLifeTime()) * MathUtils.nextRandomFloat());
- }
-
- /**
- * Generate a random velocity within the parameters of max angle and the rotation matrix.
- *
- * @param store
- * a vector to store the results in.
- */
- protected Vector3 getRandomVelocity(final Vector3 store) {
- final double randDir = MathUtils.TWO_PI * MathUtils.nextRandomFloat();
- final double randAngle = getRandomAngle();
- Vector3 result = store;
- if (result == null) {
- result = new Vector3();
- }
- result.setX(MathUtils.cos(randDir) * MathUtils.sin(randAngle));
- result.setY(MathUtils.cos(randAngle));
- result.setZ(MathUtils.sin(randDir) * MathUtils.sin(randAngle));
- rotateVectorSpeed(result);
- result.multiplyLocal(getInitialVelocity());
- return result;
- }
-
- /**
- * Apply the rotation matrix to a given vector representing a particle velocity.
- *
- * @param pSpeed
- * the velocity vector to be modified.
- */
- protected void rotateVectorSpeed(final Vector3 pSpeed) {
-
- final double x = pSpeed.getX(), y = pSpeed.getY(), z = pSpeed.getZ();
-
- pSpeed.setX(-1 * ((_rotMatrix.getM00() * x) + (_rotMatrix.getM10() * y) + (_rotMatrix.getM20() * z)));
- pSpeed.setY((_rotMatrix.getM01() * x) + (_rotMatrix.getM11() * y) + (_rotMatrix.getM21() * z));
- pSpeed.setZ(-1 * ((_rotMatrix.getM02() * x) + (_rotMatrix.getM12() * y) + (_rotMatrix.getM22() * z)));
- }
-
- public void warmUp(final int iterations) {
- if (_controller != null) {
- _controller.warmUp(iterations, this);
- }
- }
-
- public int getNumParticles() {
- return _numParticles;
- }
-
- public void setNumParticles(final int numParticles) {
- _numParticles = numParticles;
- }
-
- public double getReleaseVariance() {
- if (_controller != null) {
- return _controller.getReleaseVariance();
- }
- return 0;
- }
-
- public void setReleaseVariance(final double var) {
- if (_controller != null) {
- _controller.setReleaseVariance(var);
- }
- }
-
- public ParticleAppearanceRamp getRamp() {
- return _ramp;
- }
-
- public void setRamp(final ParticleAppearanceRamp ramp) {
- if (ramp == null) {
- logger.warning("Can not set a null ParticleAppearanceRamp.");
- return;
- }
- _ramp = ramp;
- }
-
- public TexAnimation getTexAnimation() {
- return _texAnimation;
- }
-
- public void setTexAnimation(final TexAnimation texAnimation) {
- if (texAnimation == null) {
- logger.warning("Can not set a null TexAnimation.");
- return;
- }
- _texAnimation = texAnimation;
- }
-
- /**
- * @return true if the particles are already in world coordinate space (default). When true, scene-graph transforms
- * will only affect the emission of particles, not particles that are already living.
- */
- public boolean isParticlesInWorldCoords() {
- return _particlesInWorldCoords;
- }
-
- public void setParticlesInWorldCoords(final boolean particlesInWorldCoords) {
- _particlesInWorldCoords = particlesInWorldCoords;
- }
-
- /**
- * Changes the number of particles in this particle mesh.
- *
- * @param count
- * the desired number of particles to change to.
- */
- public void recreate(final int count) {
- _numParticles = count;
- initializeParticles(_numParticles);
- }
-
- @Override
- public void updateWorldBound(final boolean recurse) {
- ; // ignore this since we want it to happen only when we say it can
- // happen due to world vectors not being used
- }
-
- public void updateWorldBoundManually() {
- super.updateWorldBound(true);
- }
-
- @Override
- public void updateGeometricState(final double time, final boolean initiator) {
- super.updateGeometricState(time, initiator);
- if (isRotateWithScene()) {
- // XXX: Perhaps we can avoid this special case via an addition to the interface?
- if (getParticleEmitter() instanceof MeshEmitter) {
- ((MeshEmitter) getParticleEmitter()).getSource().getWorldRotation()
- .applyPost(_emissionDirection, _worldEmit);
- } else {
- getWorldRotation().applyPost(_emissionDirection, _worldEmit);
- }
- } else {
- _worldEmit.set(_emissionDirection);
- }
-
- if (_particlesInWorldCoords) {
- final Transform t = Transform.fetchTempInstance();
- t.setIdentity();
- t.setTranslation(getWorldTranslation());
- t.setScale(getScale());
- if (getParent() != null) {
- t.setRotation(getParent().getWorldRotation());
- }
- _emitterTransform.set(t);
- Transform.releaseTempInstance(t);
-
- _originCenter.set(getWorldTranslation()).addLocal(_originOffset);
-
- setWorldTranslation(Vector3.ZERO);
- } else {
- _originCenter.set(_originOffset);
- }
-
- setWorldRotation(Matrix3.IDENTITY);
- setWorldScale(getScale());
- markDirty(DirtyType.Transform);
- }
-
- @Override
- public ParticleSystem makeCopy(final boolean shareGeometricData) {
- synchronized (this) {
- // Do not call make copy on the "generated" particle geometry.
- final Spatial geom = getParticleGeometry();
- detachChild(geom);
- final ParticleSystem copy = (ParticleSystem) super.makeCopy(shareGeometricData);
- // Reattach
- attachChild(geom);
- return copy;
- }
- }
-
- @Override
- public void write(final OutputCapsule capsule) throws IOException {
- synchronized (this) {
- // Do not save the "generated" particle geometry.
- final Spatial geom = getParticleGeometry();
- detachChild(geom);
- super.write(capsule);
- // Reattach
- attachChild(geom);
- }
-
- capsule.write(_particleType, "particleType", ParticleType.Quad);
- capsule.write(_particleEmitter, "particleEmitter", null);
- capsule.write(_startSize, "startSize", DEFAULT_START_SIZE);
- capsule.write(_endSize, "endSize", DEFAULT_END_SIZE);
- capsule.write(_startColor, "startColor", new ColorRGBA(DEFAULT_START_COLOR));
- capsule.write(_endColor, "endColor", new ColorRGBA(DEFAULT_END_COLOR));
- capsule.write(_startSpin, "startSpin", 0);
- capsule.write(_endSpin, "endSpin", 0);
- capsule.write(_startMass, "startMass", 0);
- capsule.write(_endMass, "endMass", 0);
- capsule.write(_startTexIndex, "startTexIndex", 0);
- capsule.write(_texQuantity, "texQuantity", 1);
- capsule.write(_initialVelocity, "initialVelocity", 1);
- capsule.write(_minimumLifeTime, "minimumLifeTime", DEFAULT_MIN_LIFE);
- capsule.write(_maximumLifeTime, "maximumLifeTime", DEFAULT_MAX_LIFE);
- capsule.write(_minimumAngle, "minimumAngle", 0);
- capsule.write(_maximumAngle, "maximumAngle", DEFAULT_MAX_ANGLE);
- capsule.write(_emissionDirection, "emissionDirection", new Vector3(Vector3.UNIT_Y));
- capsule.write(_worldEmit, "worldEmit", new Vector3(Vector3.ZERO));
- capsule.write(_upVector, "upVector", new Vector3(Vector3.UNIT_Y));
- capsule.write(_leftVector, "leftVector", new Vector3(-1, 0, 0));
- capsule.write(_facingUpVector, "facingUpVector", new Vector3(Vector3.UNIT_Y));
- capsule.write(_facingLeftVector, "facingLeftVector", new Vector3(-1, 0, 0));
- capsule.write(_numParticles, "numParticles", 0);
- capsule.write(_particleOrientation, "particleOrientation", 0);
- capsule.write(_rotateWithScene, "rotateWithScene", false);
- capsule.write(_geometryCoordinates, "geometryCoordinates", null);
- capsule.write(_appearanceColors, "appearanceColors", null);
- capsule.write(_releaseRate, "releaseRate", _numParticles);
- capsule.write(_originCenter, "originCenter", new Vector3(Vector3.ZERO));
- capsule.write(_originOffset, "originOffset", new Vector3(Vector3.ZERO));
- capsule.write(_controller, "controller", null);
- capsule.write(_cameraFacing, "cameraFacing", true);
- capsule.write(_velocityAligned, "velocityAligned", false);
- capsule.write(_particlesInWorldCoords, "particlesInWorldCoords", true);
- capsule.write(_ramp, "ramp", new ParticleAppearanceRamp());
- capsule.write(_texAnimation, "texAnimation", new TexAnimation());
- }
-
- @Override
- public void read(final InputCapsule capsule) throws IOException {
- super.read(capsule);
- _particleType = capsule.readEnum("particleType", ParticleType.class, ParticleType.Quad);
- _particleEmitter = (SavableParticleEmitter) capsule.readSavable("particleEmitter", null);
- _startSize = capsule.readDouble("startSize", DEFAULT_START_SIZE);
- _endSize = capsule.readDouble("endSize", DEFAULT_END_SIZE);
- _startColor.set((ColorRGBA) capsule.readSavable("startColor", new ColorRGBA(DEFAULT_START_COLOR)));
- _endColor.set((ColorRGBA) capsule.readSavable("endColor", new ColorRGBA(DEFAULT_END_COLOR)));
- _startSpin = capsule.readDouble("startSpin", 0);
- _endSpin = capsule.readDouble("endSpin", 0);
- _startMass = capsule.readDouble("startMass", 0);
- _endMass = capsule.readDouble("endMass", 0);
- _startTexIndex = capsule.readInt("startTexIndex", 0);
- _texQuantity = capsule.readInt("texQuantity", 1);
- _initialVelocity = capsule.readDouble("initialVelocity", 1);
- _minimumLifeTime = capsule.readDouble("minimumLifeTime", DEFAULT_MIN_LIFE);
- _maximumLifeTime = capsule.readDouble("maximumLifeTime", DEFAULT_MAX_LIFE);
- _minimumAngle = capsule.readDouble("minimumAngle", 0);
- _maximumAngle = capsule.readDouble("maximumAngle", DEFAULT_MAX_ANGLE);
- _emissionDirection.set((Vector3) capsule.readSavable("emissionDirection", new Vector3(Vector3.UNIT_Y)));
- _worldEmit.set((Vector3) capsule.readSavable("worldEmit", new Vector3(Vector3.ZERO)));
- _upVector.set((Vector3) capsule.readSavable("upVector", new Vector3(Vector3.UNIT_Y)));
- _leftVector.set((Vector3) capsule.readSavable("leftVector", new Vector3(-1, 0, 0)));
- _facingUpVector.set((Vector3) capsule.readSavable("facingUpVector", new Vector3(Vector3.UNIT_Y)));
- _facingLeftVector.set((Vector3) capsule.readSavable("facingLeftVector", new Vector3(-1, 0, 0)));
- _numParticles = capsule.readInt("numParticles", 0);
- _rotateWithScene = capsule.readBoolean("rotateWithScene", false);
- _geometryCoordinates = capsule.readFloatBuffer("geometryCoordinates", null);
- _appearanceColors = capsule.readFloatBuffer("appearanceColors", null);
-
- _releaseRate = capsule.readInt("releaseRate", _numParticles);
- _particleOrientation = capsule.readDouble("particleOrientation", 0);
- _originCenter.set((Vector3) capsule.readSavable("originCenter", new Vector3()));
- _originOffset.set((Vector3) capsule.readSavable("originOffset", new Vector3()));
- _controller = (ParticleController) capsule.readSavable("controller", null);
- _cameraFacing = capsule.readBoolean("cameraFacing", true);
- _velocityAligned = capsule.readBoolean("velocityAligned", false);
- _particlesInWorldCoords = capsule.readBoolean("particlesInWorldCoords", true);
- _ramp = (ParticleAppearanceRamp) capsule.readSavable("ramp", new ParticleAppearanceRamp());
- _texAnimation = (TexAnimation) capsule.readSavable("texAnimation", new TexAnimation());
-
- _invScale.zero();
- _upXemit.zero();
- _absUpVector.zero();
- _abUpMinUp.zero();
- _rotMatrix.setIdentity();
- initializeParticles(_numParticles);
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.particle;
+
+import java.io.IOException;
+import java.nio.FloatBuffer;
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.ardor3d.extension.effect.particle.emitter.MeshEmitter;
+import com.ardor3d.extension.effect.particle.emitter.SavableParticleEmitter;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.math.Matrix3;
+import com.ardor3d.math.Transform;
+import com.ardor3d.math.Triangle;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.math.type.ReadOnlyMatrix3;
+import com.ardor3d.math.type.ReadOnlyTransform;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.MeshData;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.controller.ComplexSpatialController.RepeatType;
+import com.ardor3d.scenegraph.controller.SpatialController;
+import com.ardor3d.scenegraph.event.DirtyType;
+import com.ardor3d.util.export.InputCapsule;
+import com.ardor3d.util.export.OutputCapsule;
+import com.ardor3d.util.geom.BufferUtils;
+
+/**
+ * ParticleSystem is an abstract class representing a particle system. A ParticleController must be attached for the
+ * effect to be complete.
+ */
+public abstract class ParticleSystem extends Node {
+ private static final Logger logger = Logger.getLogger(ParticleSystem.class.getName());
+
+ public enum ParticleType {
+ Quad, Triangle, Point, Line, GeomMesh;
+ }
+
+ protected static final double DEFAULT_END_SIZE = 4;
+ protected static final double DEFAULT_START_SIZE = 20;
+ protected static final double DEFAULT_MAX_ANGLE = 0.7853982;
+ protected static final double DEFAULT_MAX_LIFE = 3000;
+ protected static final double DEFAULT_MIN_LIFE = 2000;
+
+ protected static final ReadOnlyColorRGBA DEFAULT_START_COLOR = new ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f);
+ protected static final ReadOnlyColorRGBA DEFAULT_END_COLOR = new ColorRGBA(1.0f, 1.0f, 0.0f, 0.0f);
+
+ protected ParticleType _particleType;
+ protected SavableParticleEmitter _particleEmitter;
+ protected boolean _cameraFacing = true;
+ protected boolean _velocityAligned = false;
+ protected boolean _particlesInWorldCoords = true;
+
+ protected double _startSize, _endSize;
+ protected final ColorRGBA _startColor = new ColorRGBA(DEFAULT_START_COLOR);
+ protected final ColorRGBA _endColor = new ColorRGBA(DEFAULT_END_COLOR);
+ protected ParticleAppearanceRamp _ramp = new ParticleAppearanceRamp();
+ protected TexAnimation _texAnimation = new TexAnimation();
+ protected double _initialVelocity;
+ protected double _minimumLifeTime, _maximumLifeTime;
+ protected double _minimumAngle, _maximumAngle;
+ protected double _startSpin, _endSpin;
+ protected double _startMass, _endMass;
+ protected int _startTexIndex, _texQuantity;
+ protected final Vector3 _emissionDirection = new Vector3(Vector3.UNIT_Y);
+ protected final Transform _emitterTransform = new Transform();
+ protected final Vector3 _worldEmit = new Vector3();
+ protected int _numParticles;
+ protected boolean _rotateWithScene = false;
+ protected final Matrix3 _rotMatrix = new Matrix3();
+ protected double _particleOrientation;
+
+ protected FloatBuffer _geometryCoordinates;
+ protected FloatBuffer _appearanceColors;
+
+ // vectors to prevent repeated object creation:
+ protected final Vector3 _upXemit = new Vector3(), _absUpVector = new Vector3(), _abUpMinUp = new Vector3();
+ protected final Vector3 _upVector = new Vector3(Vector3.UNIT_Y);
+ protected final Vector3 _leftVector = new Vector3(-1, 0, 0);
+ protected final Vector3 _invScale = new Vector3();
+
+ // These vectors are used for determining particle orientation if you turn off camera facing
+ protected final Vector3 _facingUpVector = new Vector3(Vector3.UNIT_Y);
+ protected final Vector3 _facingLeftVector = new Vector3(-1, 0, 0);
+
+ protected Particle _particles[];
+
+ // protected Vector3 particleSpeed;
+ protected int _releaseRate; // particles per second
+ protected final Vector3 _originOffset = new Vector3();
+ protected final Vector3 _originCenter = new Vector3();
+
+ protected Mesh _particleMesh;
+ protected ParticleController _controller;
+
+ protected Vector3 _oldEmit = new Vector3(Float.NaN, Float.NaN, Float.NaN);
+ protected double _matData[] = new double[9];
+
+ public ParticleSystem() {}
+
+ public ParticleSystem(final String name, final int numParticles) {
+ this(name, numParticles, ParticleType.Quad);
+ }
+
+ public ParticleSystem(final String name, final int numParticles, final ParticleType particleType) {
+ super(name);
+ _numParticles = numParticles;
+ _particleType = particleType;
+ _minimumLifeTime = DEFAULT_MIN_LIFE;
+ _maximumLifeTime = DEFAULT_MAX_LIFE;
+ _maximumAngle = DEFAULT_MAX_ANGLE;
+ _startSize = DEFAULT_START_SIZE;
+ _endSize = DEFAULT_END_SIZE;
+ _startSpin = 0;
+ _endSpin = 0;
+ _startMass = 1;
+ _endMass = 1;
+ _startTexIndex = 0;
+ _texQuantity = 1;
+ _releaseRate = numParticles;
+ _initialVelocity = 1.0;
+
+ initializeParticles(numParticles);
+ }
+
+ protected abstract void initializeParticles(int numParticles);
+
+ public static int getVertsForParticleType(final ParticleType type) {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+ switch (type) {
+ case Triangle:
+ case GeomMesh:
+ return 3;
+ case Point:
+ return 1;
+ case Line:
+ return 2;
+ case Quad:
+ return 4;
+ }
+ throw new IllegalArgumentException("Invalid ParticleType: " + type);
+ }
+
+ public void forceRespawn() {
+ for (final Particle p : _particles) {
+ p.recreateParticle(0);
+ p.setStatus(Particle.Status.Alive);
+ p.updateAndCheck(1);
+ p.setStatus(Particle.Status.Available);
+ }
+
+ if (_controller != null) {
+ _controller.setActive(true);
+ }
+ }
+
+ /**
+ * Setup the rotation matrix used to determine initial particle velocity based on emission angle and emission
+ * direction. called automatically by the set* methods for those parameters.
+ */
+ public void updateRotationMatrix() {
+
+ if (_oldEmit.equals(_worldEmit)) {
+ return;
+ }
+
+ final double upDotEmit = _upVector.dot(_worldEmit);
+ if (Math.abs(upDotEmit) > 1.0 - MathUtils.EPSILON) {
+ _absUpVector.setX(_upVector.getX() <= 0.0 ? -_upVector.getX() : _upVector.getX());
+ _absUpVector.setY(_upVector.getY() <= 0.0 ? -_upVector.getY() : _upVector.getY());
+ _absUpVector.setZ(_upVector.getZ() <= 0.0 ? -_upVector.getZ() : _upVector.getZ());
+ if (_absUpVector.getX() < _absUpVector.getY()) {
+ if (_absUpVector.getX() < _absUpVector.getZ()) {
+ _absUpVector.set(Vector3.UNIT_X);
+ } else {
+ _absUpVector.set(Vector3.UNIT_Z);
+ }
+ } else if (_absUpVector.getY() < _absUpVector.getZ()) {
+ _absUpVector.set(Vector3.UNIT_Y);
+ } else {
+ _absUpVector.set(Vector3.UNIT_Z);
+ }
+ _absUpVector.subtract(_upVector, _abUpMinUp);
+ _absUpVector.subtract(_worldEmit, _upXemit);
+ final double f4 = 2.0 / _abUpMinUp.dot(_abUpMinUp);
+ final double f6 = 2.0 / _upXemit.dot(_upXemit);
+ final double f8 = f4 * f6 * _abUpMinUp.dot(_upXemit);
+ final double af1[] = { _abUpMinUp.getX(), _abUpMinUp.getY(), _abUpMinUp.getZ() };
+ final double af2[] = { _upXemit.getX(), _upXemit.getY(), _upXemit.getZ() };
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ _matData[(i * 3) + j] = (-f4 * af1[i] * af1[j] - f6 * af2[i] * af2[j]) + f8 * af2[i] * af1[j];
+
+ }
+ _matData[(i * 3) + i]++;
+ }
+
+ } else {
+ _upVector.cross(_worldEmit, _upXemit);
+ final double f2 = 1.0 / (1.0 + upDotEmit);
+ final double f5 = f2 * _upXemit.getX();
+ final double f7 = f2 * _upXemit.getZ();
+ final double f9 = f5 * _upXemit.getY();
+ final double f10 = f5 * _upXemit.getZ();
+ final double f11 = f7 * _upXemit.getY();
+ _matData[0] = upDotEmit + f5 * _upXemit.getX();
+ _matData[1] = f9 - _upXemit.getZ();
+ _matData[2] = f10 + _upXemit.getY();
+ _matData[3] = f9 + _upXemit.getZ();
+ _matData[4] = upDotEmit + f2 * _upXemit.getY() * _upXemit.getY();
+ _matData[5] = f11 - _upXemit.getX();
+ _matData[6] = f10 - _upXemit.getY();
+ _matData[7] = f11 + _upXemit.getX();
+ _matData[8] = upDotEmit + f7 * _upXemit.getZ();
+ }
+ _rotMatrix.fromArray(_matData);
+ _oldEmit.set(_worldEmit);
+ }
+
+ public abstract Mesh getParticleGeometry();
+
+ public ParticleController getParticleController() {
+ return _controller;
+ }
+
+ @Override
+ public void addController(final SpatialController<?> c) {
+ super.addController(c);
+ if (c instanceof ParticleController) {
+ _controller = (ParticleController) c;
+ }
+ }
+
+ public Vector3 getEmissionDirection() {
+ return _emissionDirection;
+ }
+
+ public void setEmissionDirection(final ReadOnlyVector3 emissionDirection) {
+ _emissionDirection.set(emissionDirection);
+ _worldEmit.set(emissionDirection);
+ }
+
+ public double getEndSize() {
+ return _endSize;
+ }
+
+ public void setEndSize(final double size) {
+ _endSize = size >= 0.0 ? size : 0.0;
+ }
+
+ public double getStartSize() {
+ return _startSize;
+ }
+
+ public void setStartSize(final double size) {
+ _startSize = size >= 0.0 ? size : 0.0;
+ }
+
+ /**
+ * Set the start color for particles.
+ *
+ * @param color
+ * The new start color.
+ */
+ public void setStartColor(final ReadOnlyColorRGBA color) {
+ _startColor.set(color);
+ }
+
+ /**
+ * @return The start color.
+ */
+ public ReadOnlyColorRGBA getStartColor() {
+ return _startColor;
+ }
+
+ /**
+ * Set the end color for particles. The base color of the particle will linearly approach this color from the start
+ * color over the lifetime of the particle.
+ *
+ * @param color
+ * ColorRGBA The ending color.
+ */
+ public void setEndColor(final ReadOnlyColorRGBA color) {
+ _endColor.set(color);
+ }
+
+ /**
+ * getEndColor returns the ending color.
+ *
+ * @return The ending color
+ */
+ public ReadOnlyColorRGBA getEndColor() {
+ return _endColor;
+ }
+
+ /**
+ * Set the start and end spinSpeed of particles managed by this manager. Setting it to 0 means no spin.
+ *
+ * @param speed
+ * double
+ */
+ public void setParticleSpinSpeed(final double speed) {
+ _startSpin = speed;
+ _endSpin = speed;
+ }
+
+ public Vector3 getInvScale() {
+ return _invScale;
+ }
+
+ public void setInvScale(final ReadOnlyVector3 invScale) {
+ _invScale.set(invScale);
+ }
+
+ public void updateInvScale() {
+ _invScale.set(1.0 / getWorldScale().getX(), 1.0 / getWorldScale().getY(), 1.0 / getWorldScale().getZ());
+ }
+
+ /**
+ * Add an external influence to the particle controller for this mesh.
+ *
+ * @param influence
+ * ParticleInfluence
+ */
+ public void addInfluence(final ParticleInfluence influence) {
+ _controller.addInfluence(influence);
+ }
+
+ /**
+ * Remove an influence from the particle controller for this mesh.
+ *
+ * @param influence
+ * ParticleInfluence
+ * @return true if found and removed.
+ */
+ public boolean removeInfluence(final ParticleInfluence influence) {
+ return _controller.removeInfluence(influence);
+ }
+
+ /**
+ * Returns the list of influences acting on this particle controller.
+ *
+ * @return ArrayList
+ */
+ public List<ParticleInfluence> getInfluences() {
+ return _controller.getInfluences();
+ }
+
+ public void clearInfluences() {
+ _controller.clearInfluences();
+ }
+
+ public void setParticleMass(final double mass) {
+ _startMass = _endMass = mass;
+ }
+
+ /**
+ * Set the minimum angle (in radians) that particles can be emitted away from the emission direction. Any angle less
+ * than 0 is trimmed to 0.
+ *
+ * @param f
+ * The new emission minimum angle.
+ */
+ public void setMinimumAngle(final double f) {
+ _minimumAngle = f >= 0.0 ? f : 0.0;
+ }
+
+ /**
+ * getEmissionMinimumAngle returns the minimum emission angle.
+ *
+ * @return The minimum emission angle.
+ */
+ public double getMinimumAngle() {
+ return _minimumAngle;
+ }
+
+ /**
+ * Set the maximum angle (in radians) that particles can be emitted away from the emission direction. Any angle less
+ * than 0 is trimmed to 0.
+ *
+ * @param f
+ * The new emission maximum angle.
+ */
+ public void setMaximumAngle(final double f) {
+ _maximumAngle = f >= 0.0 ? f : 0.0;
+ }
+
+ /**
+ * getEmissionMaximumAngle returns the maximum emission angle.
+ *
+ * @return The maximum emission angle.
+ */
+ public double getMaximumAngle() {
+ return _maximumAngle;
+ }
+
+ /**
+ * Set the minimum lifespan of new particles (or recreated) managed by this manager. if a value less than zero is
+ * given, 1.0 is used.
+ *
+ * @param lifeSpan
+ * in ms
+ */
+ public void setMinimumLifeTime(final double lifeSpan) {
+ _minimumLifeTime = lifeSpan >= 0.0 ? lifeSpan : 1.0;
+ }
+
+ /**
+ * getParticlesMinimumLifeTime returns the minimum life time of a particle.
+ *
+ * @return The current minimum life time in ms.
+ */
+ public double getMinimumLifeTime() {
+ return _minimumLifeTime;
+ }
+
+ /**
+ * Set the maximum lifespan of new particles (or recreated) managed by this manager. if a value less than zero is
+ * given, 1.0 is used.
+ *
+ * @param lifeSpan
+ * in ms
+ */
+ public void setMaximumLifeTime(final double lifeSpan) {
+ _maximumLifeTime = lifeSpan >= 0.0 ? lifeSpan : 1.0;
+ }
+
+ /**
+ * getParticlesMaximumLifeTime returns the maximum life time of a particle.
+ *
+ * @return The current maximum life time in ms.
+ */
+ public double getMaximumLifeTime() {
+ return _maximumLifeTime;
+ }
+
+ public ReadOnlyMatrix3 getRotMatrix() {
+ return _rotMatrix;
+ }
+
+ public void setRotMatrix(final ReadOnlyMatrix3 rotMatrix) {
+ _rotMatrix.set(rotMatrix);
+ }
+
+ public ReadOnlyTransform getEmitterTransform() {
+ return _emitterTransform;
+ }
+
+ public void setEmitterTransform(final ReadOnlyTransform emitterTransform) {
+ _emitterTransform.set(emitterTransform);
+ }
+
+ public double getParticleOrientation() {
+ return _particleOrientation;
+ }
+
+ public void setParticleOrientation(final double orient) {
+ _particleOrientation = orient;
+ }
+
+ /**
+ * Set the acceleration for any new particles created (or recreated) by this manager.
+ *
+ * @param velocity
+ * particle v0
+ */
+ public void setInitialVelocity(final double velocity) {
+ _initialVelocity = velocity;
+ }
+
+ /**
+ * Get the acceleration set in this manager.
+ *
+ * @return The initialVelocity
+ */
+ public double getInitialVelocity() {
+ return _initialVelocity;
+ }
+
+ /**
+ * Set the offset for any new particles created (or recreated) by this manager. This is applicable only to managers
+ * generating from a point (not a line, rectangle, etc..)
+ *
+ * @param offset
+ * new offset position
+ */
+ public void setOriginOffset(final ReadOnlyVector3 offset) {
+ _originOffset.set(offset);
+ }
+
+ /**
+ * Get the offset point set in this manager.
+ *
+ * @return origin
+ */
+ public ReadOnlyVector3 getOriginOffset() {
+ return _originOffset;
+ }
+
+ public ReadOnlyVector3 getWorldEmit() {
+ return _worldEmit;
+ }
+
+ public void setWorldEmit(final ReadOnlyVector3 worldEmit) {
+ _worldEmit.set(worldEmit);
+ }
+
+ /**
+ * Get the number of particles the manager should release per second.
+ *
+ * @return The number of particles that should be released per second.
+ */
+ public int getReleaseRate() {
+ return _releaseRate;
+ }
+
+ /**
+ * Set the number of particles the manager should release per second.
+ *
+ * @param particlesPerSecond
+ * number of particles per second
+ */
+ public void setReleaseRate(final int particlesPerSecond) {
+ final int oldRate = _releaseRate;
+ _releaseRate = particlesPerSecond;
+ if (_controller != null && !_controller.isActive() && _controller.isControlFlow() && oldRate == 0) {
+ _controller.setActive(true);
+ }
+ }
+
+ public double getEndMass() {
+ return _endMass;
+ }
+
+ public void setEndMass(final double endMass) {
+ _endMass = endMass;
+ }
+
+ public double getEndSpin() {
+ return _endSpin;
+ }
+
+ public void setEndSpin(final double endSpin) {
+ _endSpin = endSpin;
+ }
+
+ public double getStartMass() {
+ return _startMass;
+ }
+
+ public void setStartMass(final double startMass) {
+ _startMass = startMass;
+ }
+
+ public double getStartSpin() {
+ return _startSpin;
+ }
+
+ public void setStartSpin(final double startSpin) {
+ _startSpin = startSpin;
+ }
+
+ public int getTexQuantity() {
+ return _texQuantity;
+ }
+
+ public void setTexQuantity(final int quantity) {
+ _texQuantity = quantity;
+ }
+
+ public int getStartTexIndex() {
+ return _startTexIndex;
+ }
+
+ public void setStartTexIndex(final int startTexIndex) {
+ _startTexIndex = startTexIndex;
+ }
+
+ /**
+ * Get which emittype method is being used by the underlying system. One of ParticleType.Quad,
+ * ParticleType.Triangle, ParticleType.Point, ParticleType.Line, ParticleType.GeomMesh
+ *
+ * @return An int representing the type of particle we are emitting.
+ */
+ public ParticleType getParticleType() {
+ return _particleType;
+ }
+
+ /**
+ * Set what type of particle to emit from this sytem. Does not have an effect unless recreate is called.
+ *
+ * @param type
+ * particle type to use, should be one of ParticleType.Quad, ParticleType.Triangle, ParticleType.Point,
+ * ParticleType.Line, ParticleType.GeomMesh
+ */
+ public void setParticleType(final ParticleType type) {
+ _particleType = type;
+ }
+
+ /**
+ * Set our particle emitter.
+ *
+ * @param emitter
+ * New emitter or null for default point emitter.
+ */
+ public void setParticleEmitter(final SavableParticleEmitter emitter) {
+ _particleEmitter = emitter;
+ }
+
+ /**
+ * @return the set particle emitter, or null if none is set.
+ */
+ public SavableParticleEmitter getParticleEmitter() {
+ return _particleEmitter;
+ }
+
+ public void initAllParticlesLocation() {
+ for (int i = _particles.length; --i >= 0;) {
+ initParticleLocation(i);
+ _particles[i].updateVerts(null);
+ }
+ getParticleGeometry().updateModelBound();
+ }
+
+ @Override
+ public void onDraw(final Renderer r) {
+ // make sure our particle world bound is correct
+ updateWorldBoundManually();
+
+ super.onDraw(r);
+ };
+
+ public void initParticleLocation(final int index) {
+ final Particle p = _particles[index];
+ if (getParticleType() == ParticleType.GeomMesh && getParticleEmitter() instanceof MeshEmitter) {
+ final MeshEmitter emitter = (MeshEmitter) getParticleEmitter();
+ final Mesh mesh = emitter.getSource();
+
+ // Update the triangle model on each new particle creation.
+ final Vector3[] vertices = new Vector3[3];
+ final MeshData mData = mesh.getMeshData();
+ for (int x = 0; x < 3; x++) {
+ vertices[x] = new Vector3();
+
+ final int vertIndex = mData.getVertexIndex(index, x, 0);
+ BufferUtils.populateFromBuffer(vertices[x], mData.getVertexBuffer(), mData.getIndices() != null ? mData
+ .getIndices().get(vertIndex) : vertIndex);
+ }
+ Triangle t = p.getTriangleModel();
+ if (t == null) {
+ t = new Triangle(vertices[0], vertices[1], vertices[2]);
+ } else {
+ t.setA(vertices[0]);
+ t.setB(vertices[1]);
+ t.setC(vertices[2]);
+ }
+ // turn the triangle corners into vector offsets from center
+ for (int x = 0; x < 3; x++) {
+ vertices[x].subtract(t.getCenter(), vertices[x]);
+ t.set(x, vertices[x]);
+ }
+ p.setTriangleModel(t);
+ mesh.localToWorld(t.getCenter(), p.getPosition());
+ p.getPosition().multiplyLocal(getInvScale());
+
+ } else if (getParticleEmitter() instanceof MeshEmitter) {
+ final MeshEmitter emitter = (MeshEmitter) getParticleEmitter();
+ final Mesh mesh = emitter.getSource();
+ mesh.getMeshData().randomPointOnPrimitives(p.getPosition());
+ mesh.localToWorld(p.getPosition(), p.getPosition());
+ p.getPosition().multiplyLocal(getInvScale());
+ } else {
+ if (getParticleEmitter() != null) {
+ getParticleEmitter().randomEmissionPoint(p.getPosition());
+ } else {
+ p.getPosition().set(_originOffset);
+ }
+
+ _emitterTransform.applyForward(p.getPosition());
+ p.getPosition().divideLocal(_emitterTransform.getScale());
+ }
+ }
+
+ public boolean isCameraFacing() {
+ return _cameraFacing;
+ }
+
+ public void setCameraFacing(final boolean cameraFacing) {
+ _cameraFacing = cameraFacing;
+ }
+
+ public boolean isVelocityAligned() {
+ return _velocityAligned;
+ }
+
+ public void setVelocityAligned(final boolean velocityAligned) {
+ _velocityAligned = velocityAligned;
+ }
+
+ public Particle getParticle(final int i) {
+ return _particles[i];
+ }
+
+ public boolean isActive() {
+ return _controller.isActive();
+ }
+
+ public void setSpeed(final double f) {
+ _controller.setSpeed(f);
+ }
+
+ public void setRepeatType(final RepeatType type) {
+ _controller.setRepeatType(type);
+ }
+
+ public void setControlFlow(final boolean b) {
+ _controller.setControlFlow(b);
+ }
+
+ public ReadOnlyVector3 getOriginCenter() {
+ return _originCenter;
+ }
+
+ public ReadOnlyVector3 getUpVector() {
+ return _upVector;
+ }
+
+ public void setUpVector(final ReadOnlyVector3 vector) {
+ _upVector.set(vector);
+ }
+
+ public ReadOnlyVector3 getLeftVector() {
+ return _leftVector;
+ }
+
+ public void setLeftVector(final ReadOnlyVector3 vector) {
+ _leftVector.set(vector);
+ }
+
+ public ReadOnlyVector3 getFacingUpVector() {
+ return _facingUpVector;
+ }
+
+ /**
+ * Used to determine particle orientation (only if cameraFacing is false.)
+ *
+ * @param vector
+ */
+ public void setFacingUpVector(final ReadOnlyVector3 vector) {
+ _facingUpVector.set(vector);
+ }
+
+ public ReadOnlyVector3 getFacingLeftVector() {
+ return _facingLeftVector;
+ }
+
+ /**
+ * Used to determine particle orientation (only if cameraFacing is false.)
+ *
+ * @param vector
+ */
+ public void setFacingLeftVector(final ReadOnlyVector3 vector) {
+ _facingLeftVector.set(vector);
+ }
+
+ public boolean isRotateWithScene() {
+ return _rotateWithScene;
+ }
+
+ public void setRotateWithScene(final boolean rotate) {
+ _rotateWithScene = rotate;
+ }
+
+ public void resetParticleVelocity(final int i) {
+ getRandomVelocity(_particles[i].getVelocity());
+ }
+
+ /**
+ * Returns a random angle between the min and max angles.
+ *
+ * @return the random angle.
+ */
+ public double getRandomAngle() {
+ return getMinimumAngle() + MathUtils.nextRandomFloat() * (getMaximumAngle() - getMinimumAngle());
+ }
+
+ /**
+ * generate a random lifespan between the min and max lifespan of the particle system.
+ *
+ * @return the generated lifespan value
+ */
+ public double getRandomLifeSpan() {
+ return getMinimumLifeTime() + ((getMaximumLifeTime() - getMinimumLifeTime()) * MathUtils.nextRandomFloat());
+ }
+
+ /**
+ * Generate a random velocity within the parameters of max angle and the rotation matrix.
+ *
+ * @param store
+ * a vector to store the results in.
+ */
+ protected Vector3 getRandomVelocity(final Vector3 store) {
+ final double randDir = MathUtils.TWO_PI * MathUtils.nextRandomFloat();
+ final double randAngle = getRandomAngle();
+ Vector3 result = store;
+ if (result == null) {
+ result = new Vector3();
+ }
+ result.setX(MathUtils.cos(randDir) * MathUtils.sin(randAngle));
+ result.setY(MathUtils.cos(randAngle));
+ result.setZ(MathUtils.sin(randDir) * MathUtils.sin(randAngle));
+ rotateVectorSpeed(result);
+ result.multiplyLocal(getInitialVelocity());
+ return result;
+ }
+
+ /**
+ * Apply the rotation matrix to a given vector representing a particle velocity.
+ *
+ * @param pSpeed
+ * the velocity vector to be modified.
+ */
+ protected void rotateVectorSpeed(final Vector3 pSpeed) {
+
+ final double x = pSpeed.getX(), y = pSpeed.getY(), z = pSpeed.getZ();
+
+ pSpeed.setX(-1 * ((_rotMatrix.getM00() * x) + (_rotMatrix.getM10() * y) + (_rotMatrix.getM20() * z)));
+ pSpeed.setY((_rotMatrix.getM01() * x) + (_rotMatrix.getM11() * y) + (_rotMatrix.getM21() * z));
+ pSpeed.setZ(-1 * ((_rotMatrix.getM02() * x) + (_rotMatrix.getM12() * y) + (_rotMatrix.getM22() * z)));
+ }
+
+ public void warmUp(final int iterations) {
+ if (_controller != null) {
+ _controller.warmUp(iterations, this);
+ }
+ }
+
+ public int getNumParticles() {
+ return _numParticles;
+ }
+
+ public void setNumParticles(final int numParticles) {
+ _numParticles = numParticles;
+ }
+
+ public double getReleaseVariance() {
+ if (_controller != null) {
+ return _controller.getReleaseVariance();
+ }
+ return 0;
+ }
+
+ public void setReleaseVariance(final double var) {
+ if (_controller != null) {
+ _controller.setReleaseVariance(var);
+ }
+ }
+
+ public ParticleAppearanceRamp getRamp() {
+ return _ramp;
+ }
+
+ public void setRamp(final ParticleAppearanceRamp ramp) {
+ if (ramp == null) {
+ logger.warning("Can not set a null ParticleAppearanceRamp.");
+ return;
+ }
+ _ramp = ramp;
+ }
+
+ public TexAnimation getTexAnimation() {
+ return _texAnimation;
+ }
+
+ public void setTexAnimation(final TexAnimation texAnimation) {
+ if (texAnimation == null) {
+ logger.warning("Can not set a null TexAnimation.");
+ return;
+ }
+ _texAnimation = texAnimation;
+ }
+
+ /**
+ * @return true if the particles are already in world coordinate space (default). When true, scene-graph transforms
+ * will only affect the emission of particles, not particles that are already living.
+ */
+ public boolean isParticlesInWorldCoords() {
+ return _particlesInWorldCoords;
+ }
+
+ public void setParticlesInWorldCoords(final boolean particlesInWorldCoords) {
+ _particlesInWorldCoords = particlesInWorldCoords;
+ }
+
+ /**
+ * Changes the number of particles in this particle mesh.
+ *
+ * @param count
+ * the desired number of particles to change to.
+ */
+ public void recreate(final int count) {
+ _numParticles = count;
+ initializeParticles(_numParticles);
+ }
+
+ @Override
+ public void updateWorldBound(final boolean recurse) {
+ ; // ignore this since we want it to happen only when we say it can
+ // happen due to world vectors not being used
+ }
+
+ public void updateWorldBoundManually() {
+ super.updateWorldBound(true);
+ }
+
+ @Override
+ public void updateGeometricState(final double time, final boolean initiator) {
+ super.updateGeometricState(time, initiator);
+ if (isRotateWithScene()) {
+ // XXX: Perhaps we can avoid this special case via an addition to the interface?
+ if (getParticleEmitter() instanceof MeshEmitter) {
+ ((MeshEmitter) getParticleEmitter()).getSource().getWorldRotation()
+ .applyPost(_emissionDirection, _worldEmit);
+ } else {
+ getWorldRotation().applyPost(_emissionDirection, _worldEmit);
+ }
+ } else {
+ _worldEmit.set(_emissionDirection);
+ }
+
+ if (_particlesInWorldCoords) {
+ final Transform t = Transform.fetchTempInstance();
+ t.setIdentity();
+ t.setTranslation(getWorldTranslation());
+ t.setScale(getScale());
+ if (getParent() != null) {
+ t.setRotation(getParent().getWorldRotation());
+ }
+ _emitterTransform.set(t);
+ Transform.releaseTempInstance(t);
+
+ _originCenter.set(getWorldTranslation()).addLocal(_originOffset);
+
+ setWorldTranslation(Vector3.ZERO);
+ } else {
+ _originCenter.set(_originOffset);
+ }
+
+ setWorldRotation(Matrix3.IDENTITY);
+ setWorldScale(getScale());
+ markDirty(DirtyType.Transform);
+ }
+
+ @Override
+ public ParticleSystem makeCopy(final boolean shareGeometricData) {
+ synchronized (this) {
+ // Do not call make copy on the "generated" particle geometry.
+ final Spatial geom = getParticleGeometry();
+ detachChild(geom);
+ final ParticleSystem copy = (ParticleSystem) super.makeCopy(shareGeometricData);
+ // Reattach
+ attachChild(geom);
+ return copy;
+ }
+ }
+
+ @Override
+ public void write(final OutputCapsule capsule) throws IOException {
+ synchronized (this) {
+ // Do not save the "generated" particle geometry.
+ final Spatial geom = getParticleGeometry();
+ detachChild(geom);
+ super.write(capsule);
+ // Reattach
+ attachChild(geom);
+ }
+
+ capsule.write(_particleType, "particleType", ParticleType.Quad);
+ capsule.write(_particleEmitter, "particleEmitter", null);
+ capsule.write(_startSize, "startSize", DEFAULT_START_SIZE);
+ capsule.write(_endSize, "endSize", DEFAULT_END_SIZE);
+ capsule.write(_startColor, "startColor", new ColorRGBA(DEFAULT_START_COLOR));
+ capsule.write(_endColor, "endColor", new ColorRGBA(DEFAULT_END_COLOR));
+ capsule.write(_startSpin, "startSpin", 0);
+ capsule.write(_endSpin, "endSpin", 0);
+ capsule.write(_startMass, "startMass", 0);
+ capsule.write(_endMass, "endMass", 0);
+ capsule.write(_startTexIndex, "startTexIndex", 0);
+ capsule.write(_texQuantity, "texQuantity", 1);
+ capsule.write(_initialVelocity, "initialVelocity", 1);
+ capsule.write(_minimumLifeTime, "minimumLifeTime", DEFAULT_MIN_LIFE);
+ capsule.write(_maximumLifeTime, "maximumLifeTime", DEFAULT_MAX_LIFE);
+ capsule.write(_minimumAngle, "minimumAngle", 0);
+ capsule.write(_maximumAngle, "maximumAngle", DEFAULT_MAX_ANGLE);
+ capsule.write(_emissionDirection, "emissionDirection", new Vector3(Vector3.UNIT_Y));
+ capsule.write(_worldEmit, "worldEmit", new Vector3(Vector3.ZERO));
+ capsule.write(_upVector, "upVector", new Vector3(Vector3.UNIT_Y));
+ capsule.write(_leftVector, "leftVector", new Vector3(-1, 0, 0));
+ capsule.write(_facingUpVector, "facingUpVector", new Vector3(Vector3.UNIT_Y));
+ capsule.write(_facingLeftVector, "facingLeftVector", new Vector3(-1, 0, 0));
+ capsule.write(_numParticles, "numParticles", 0);
+ capsule.write(_particleOrientation, "particleOrientation", 0);
+ capsule.write(_rotateWithScene, "rotateWithScene", false);
+ capsule.write(_geometryCoordinates, "geometryCoordinates", null);
+ capsule.write(_appearanceColors, "appearanceColors", null);
+ capsule.write(_releaseRate, "releaseRate", _numParticles);
+ capsule.write(_originCenter, "originCenter", new Vector3(Vector3.ZERO));
+ capsule.write(_originOffset, "originOffset", new Vector3(Vector3.ZERO));
+ capsule.write(_controller, "controller", null);
+ capsule.write(_cameraFacing, "cameraFacing", true);
+ capsule.write(_velocityAligned, "velocityAligned", false);
+ capsule.write(_particlesInWorldCoords, "particlesInWorldCoords", true);
+ capsule.write(_ramp, "ramp", new ParticleAppearanceRamp());
+ capsule.write(_texAnimation, "texAnimation", new TexAnimation());
+ }
+
+ @Override
+ public void read(final InputCapsule capsule) throws IOException {
+ super.read(capsule);
+ _particleType = capsule.readEnum("particleType", ParticleType.class, ParticleType.Quad);
+ _particleEmitter = (SavableParticleEmitter) capsule.readSavable("particleEmitter", null);
+ _startSize = capsule.readDouble("startSize", DEFAULT_START_SIZE);
+ _endSize = capsule.readDouble("endSize", DEFAULT_END_SIZE);
+ _startColor.set((ColorRGBA) capsule.readSavable("startColor", new ColorRGBA(DEFAULT_START_COLOR)));
+ _endColor.set((ColorRGBA) capsule.readSavable("endColor", new ColorRGBA(DEFAULT_END_COLOR)));
+ _startSpin = capsule.readDouble("startSpin", 0);
+ _endSpin = capsule.readDouble("endSpin", 0);
+ _startMass = capsule.readDouble("startMass", 0);
+ _endMass = capsule.readDouble("endMass", 0);
+ _startTexIndex = capsule.readInt("startTexIndex", 0);
+ _texQuantity = capsule.readInt("texQuantity", 1);
+ _initialVelocity = capsule.readDouble("initialVelocity", 1);
+ _minimumLifeTime = capsule.readDouble("minimumLifeTime", DEFAULT_MIN_LIFE);
+ _maximumLifeTime = capsule.readDouble("maximumLifeTime", DEFAULT_MAX_LIFE);
+ _minimumAngle = capsule.readDouble("minimumAngle", 0);
+ _maximumAngle = capsule.readDouble("maximumAngle", DEFAULT_MAX_ANGLE);
+ _emissionDirection.set((Vector3) capsule.readSavable("emissionDirection", new Vector3(Vector3.UNIT_Y)));
+ _worldEmit.set((Vector3) capsule.readSavable("worldEmit", new Vector3(Vector3.ZERO)));
+ _upVector.set((Vector3) capsule.readSavable("upVector", new Vector3(Vector3.UNIT_Y)));
+ _leftVector.set((Vector3) capsule.readSavable("leftVector", new Vector3(-1, 0, 0)));
+ _facingUpVector.set((Vector3) capsule.readSavable("facingUpVector", new Vector3(Vector3.UNIT_Y)));
+ _facingLeftVector.set((Vector3) capsule.readSavable("facingLeftVector", new Vector3(-1, 0, 0)));
+ _numParticles = capsule.readInt("numParticles", 0);
+ _rotateWithScene = capsule.readBoolean("rotateWithScene", false);
+ _geometryCoordinates = capsule.readFloatBuffer("geometryCoordinates", null);
+ _appearanceColors = capsule.readFloatBuffer("appearanceColors", null);
+
+ _releaseRate = capsule.readInt("releaseRate", _numParticles);
+ _particleOrientation = capsule.readDouble("particleOrientation", 0);
+ _originCenter.set((Vector3) capsule.readSavable("originCenter", new Vector3()));
+ _originOffset.set((Vector3) capsule.readSavable("originOffset", new Vector3()));
+ _controller = (ParticleController) capsule.readSavable("controller", null);
+ _cameraFacing = capsule.readBoolean("cameraFacing", true);
+ _velocityAligned = capsule.readBoolean("velocityAligned", false);
+ _particlesInWorldCoords = capsule.readBoolean("particlesInWorldCoords", true);
+ _ramp = (ParticleAppearanceRamp) capsule.readSavable("ramp", new ParticleAppearanceRamp());
+ _texAnimation = (TexAnimation) capsule.readSavable("texAnimation", new TexAnimation());
+
+ _invScale.zero();
+ _upXemit.zero();
+ _absUpVector.zero();
+ _abUpMinUp.zero();
+ _rotMatrix.setIdentity();
+ initializeParticles(_numParticles);
+ }
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/HeightGenerator.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/HeightGenerator.java
index 7df9833..38a894f 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/HeightGenerator.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/HeightGenerator.java
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2008 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.water;
-
-/**
- * <code>HeightGenerator</code> Base interface for all waterheight generators used by the projected grid mesh.
- */
-public interface HeightGenerator {
- /**
- * How to animate/set heights on a grid
- *
- * @param x
- * x position to get height for
- * @param z
- * z position to get height for
- * @param time
- * time to get height for
- * @return height for specified position
- */
- public double getHeight(double x, double z, double time);
-
- public double getMaximumHeight();
-}
+/**
+ * Copyright (c) 2008 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.water;
+
+/**
+ * <code>HeightGenerator</code> Base interface for all waterheight generators used by the projected grid mesh.
+ */
+public interface HeightGenerator {
+ /**
+ * How to animate/set heights on a grid
+ *
+ * @param x
+ * x position to get height for
+ * @param z
+ * z position to get height for
+ * @param time
+ * time to get height for
+ * @return height for specified position
+ */
+ public double getHeight(double x, double z, double time);
+
+ public double getMaximumHeight();
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ImprovedNoise.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ImprovedNoise.java
index 9599306..85cad35 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ImprovedNoise.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ImprovedNoise.java
@@ -1,76 +1,76 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.water;
-
-import com.ardor3d.math.MathUtils;
-
-/**
- * <code>ImprovedNoise</code> Fast perlin noise.
- *
- * @author Ken Perlin
- */
-public final class ImprovedNoise {
- public static double noise(double x, double y, double z) {
- final int X = (int) MathUtils.floor(x) & 255, // FIND UNIT CUBE THAT
- Y = (int) MathUtils.floor(y) & 255, // CONTAINS POINT.
- Z = (int) MathUtils.floor(z) & 255;
- x -= MathUtils.floor(x); // FIND RELATIVE X,Y,Z
- y -= MathUtils.floor(y); // OF POINT IN CUBE.
- z -= MathUtils.floor(z);
- final double u = fade(x), // COMPUTE FADE CURVES
- v = fade(y), // FOR EACH OF X,Y,Z.
- w = fade(z);
- final int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF
- B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS,
-
- return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD
- grad(p[BA], x - 1, y, z)), // BLENDED
- lerp(u, grad(p[AB], x, y - 1, z), // RESULTS
- grad(p[BB], x - 1, y - 1, z))),// FROM 8
- lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS
- grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE
- lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
- }
-
- private static double fade(final double t) {
- return t * t * t * (t * (t * 6 - 15) + 10);
- }
-
- private static double lerp(final double t, final double a, final double b) {
- return a + t * (b - a);
- }
-
- private static double grad(final int hash, final double x, final double y, final double z) {
- final int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
- final double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
- v = h < 4 ? y : h == 12 || h == 14 ? x : z;
- return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
- }
-
- private static final int p[] = new int[512], permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53,
- 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0,
- 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171,
- 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230,
- 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187,
- 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226,
- 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189,
- 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129,
- 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193,
- 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199,
- 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24,
- 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };
-
- static {
- for (int i = 0; i < 256; i++) {
- p[256 + i] = p[i] = permutation[i];
- }
- }
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.water;
+
+import com.ardor3d.math.MathUtils;
+
+/**
+ * <code>ImprovedNoise</code> Fast perlin noise.
+ *
+ * @author Ken Perlin
+ */
+public final class ImprovedNoise {
+ public static double noise(double x, double y, double z) {
+ final int X = (int) MathUtils.floor(x) & 255, // FIND UNIT CUBE THAT
+ Y = (int) MathUtils.floor(y) & 255, // CONTAINS POINT.
+ Z = (int) MathUtils.floor(z) & 255;
+ x -= MathUtils.floor(x); // FIND RELATIVE X,Y,Z
+ y -= MathUtils.floor(y); // OF POINT IN CUBE.
+ z -= MathUtils.floor(z);
+ final double u = fade(x), // COMPUTE FADE CURVES
+ v = fade(y), // FOR EACH OF X,Y,Z.
+ w = fade(z);
+ final int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF
+ B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS,
+
+ return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD
+ grad(p[BA], x - 1, y, z)), // BLENDED
+ lerp(u, grad(p[AB], x, y - 1, z), // RESULTS
+ grad(p[BB], x - 1, y - 1, z))),// FROM 8
+ lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS
+ grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE
+ lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
+ }
+
+ private static double fade(final double t) {
+ return t * t * t * (t * (t * 6 - 15) + 10);
+ }
+
+ private static double lerp(final double t, final double a, final double b) {
+ return a + t * (b - a);
+ }
+
+ private static double grad(final int hash, final double x, final double y, final double z) {
+ final int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
+ final double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
+ v = h < 4 ? y : h == 12 || h == 14 ? x : z;
+ return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
+ }
+
+ private static final int p[] = new int[512], permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53,
+ 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0,
+ 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171,
+ 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230,
+ 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187,
+ 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226,
+ 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189,
+ 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129,
+ 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193,
+ 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199,
+ 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24,
+ 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };
+
+ static {
+ for (int i = 0; i < 256; i++) {
+ p[256 + i] = p[i] = permutation[i];
+ }
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ProjectedGrid.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ProjectedGrid.java
index 9667b81..bfe48d5 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ProjectedGrid.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/ProjectedGrid.java
@@ -1,662 +1,661 @@
-/**
- * Copyright (c) 2008 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.water;
-
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.util.Stack;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.math.Matrix4;
-import com.ardor3d.math.Vector2;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.Vector4;
-import com.ardor3d.math.type.ReadOnlyMatrix4;
-import com.ardor3d.math.type.ReadOnlyVector2;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.scenegraph.Mesh;
-import com.ardor3d.util.ExtendedCamera;
-import com.ardor3d.util.Timer;
-import com.ardor3d.util.geom.BufferUtils;
-import com.ardor3d.util.geom.Debugger;
-
-/**
- * <code>ProjectedGrid</code> Projected grid mesh
- */
-public class ProjectedGrid extends Mesh {
- /** The Constant logger. */
- private static final Logger logger = Logger.getLogger(ProjectedGrid.class.getName());
-
- private final int sizeX;
- private final int sizeY;
-
- private FloatBuffer vertBuf;
- private final FloatBuffer normBuf;
- private final FloatBuffer texs;
- private IntBuffer indexBuffer;
-
- private final ExtendedCamera mainCamera = new ExtendedCamera();
- private final Camera projectorCamera = new Camera();
-
- private final Vector4 origin = new Vector4();
- private final Vector4 direction = new Vector4();
- private final Vector2 source = new Vector2();
- private final Matrix4 rangeMatrix = new Matrix4();
-
- private final Vector4 intersectBottomLeft = new Vector4();
- private final Vector4 intersectTopLeft = new Vector4();
- private final Vector4 intersectTopRight = new Vector4();
- private final Vector4 intersectBottomRight = new Vector4();
-
- private final Vector3 planeIntersection = new Vector3();
-
- public boolean freezeProjector = false;
- private final Timer timer;
- private final Camera camera;
-
- private final HeightGenerator heightGenerator;
- private final float textureScale;
-
- private double projectorMinHeight = 100.0;
- private final Vector3[] intersections = new Vector3[24];
-
- private final float[] vertBufArray;
- private final float[] normBufArray;
- private final float[] texBufArray;
-
- private int nrUpdateThreads = 1;
- private final ExecutorService executorService = Executors.newCachedThreadPool(new DeamonThreadFactory());
- private final Stack<Future<?>> futureStack = new Stack<Future<?>>();
-
- private final int connections[] = { 0, 1, 2, 3, 0, 4, 1, 5, 2, 6, 3, 7, 4, 5, 6, 7, };
-
- // Debug drawing
- private boolean drawDebug = false;
-
- public ProjectedGrid(final String name, final Camera camera, final int sizeX, final int sizeY,
- final float textureScale, final HeightGenerator heightGenerator, final Timer timer) {
- super(name);
- this.sizeX = sizeX;
- this.sizeY = sizeY;
- this.textureScale = textureScale;
- this.heightGenerator = heightGenerator;
- this.camera = camera;
- this.timer = timer;
-
- buildVertices(sizeX * sizeY);
- texs = BufferUtils.createVector2Buffer(_meshData.getVertexCount());
- _meshData.setTextureBuffer(texs, 0);
- normBuf = BufferUtils.createVector3Buffer(_meshData.getVertexCount());
- _meshData.setNormalBuffer(normBuf);
-
- vertBufArray = new float[_meshData.getVertexCount() * 3];
- normBufArray = new float[_meshData.getVertexCount() * 3];
- texBufArray = new float[_meshData.getVertexCount() * 2];
-
- for (int i = 0; i < 24; i++) {
- intersections[i] = new Vector3();
- }
- }
-
- public void setNrUpdateThreads(final int nrUpdateThreads) {
- this.nrUpdateThreads = nrUpdateThreads;
- if (this.nrUpdateThreads < 1) {
- this.nrUpdateThreads = 1;
- }
- }
-
- public int getNrUpdateThreads() {
- return nrUpdateThreads;
- }
-
- public void setFreezeUpdate(final boolean freeze) {
- freezeProjector = freeze;
- }
-
- public boolean isFreezeUpdate() {
- return freezeProjector;
- }
-
- @Override
- public void render(final Renderer renderer) {
- final boolean doDraw = update();
- if (doDraw) {
- super.render(renderer);
- }
-
- if (drawDebug) {
- Debugger.drawCameraFrustum(renderer, mainCamera, new ColorRGBA(1, 0, 0, 1), (short) 0xFFFF, true);
- Debugger.drawCameraFrustum(renderer, projectorCamera, new ColorRGBA(0, 1, 1, 1), (short) 0xFFFF, true);
- }
- }
-
- public boolean update() {
- final double upperBound = heightGenerator.getMaximumHeight();
-
- if (!freezeProjector) {
- mainCamera.set(camera);
-
- final Vector3 tmp = new Vector3();
- getWorldTransform().applyInverse(mainCamera.getLocation(), tmp);
- mainCamera.setLocation(tmp);
- getWorldTransform().applyInverseVector(mainCamera.getLeft(), tmp);
- mainCamera.setLeft(tmp);
- getWorldTransform().applyInverseVector(mainCamera.getUp(), tmp);
- mainCamera.setUp(tmp);
- getWorldTransform().applyInverseVector(mainCamera.getDirection(), tmp);
- mainCamera.setDirection(tmp);
- }
-
- final ReadOnlyVector3 mainCameraLocation = mainCamera.getLocation();
- if (mainCameraLocation.getY() > 0.0 && mainCameraLocation.getY() < upperBound + mainCamera.getFrustumNear()) {
- mainCamera.setLocation(mainCameraLocation.getX(), upperBound + mainCamera.getFrustumNear(),
- mainCameraLocation.getZ());
- } else if (mainCameraLocation.getY() < 0.0
- && mainCameraLocation.getY() > -upperBound - mainCamera.getFrustumNear()) {
- mainCamera.setLocation(mainCameraLocation.getX(), -upperBound - mainCamera.getFrustumNear(),
- mainCameraLocation.getZ());
- }
- mainCamera.calculateFrustum();
- final Vector3[] corners = mainCamera.getCorners();
-
- int nrPoints = 0;
-
- // check intersections of frustum connections with upper and lower bound
- final Vector3 tmpStorage = Vector3.fetchTempInstance();
- for (int i = 0; i < 8; i++) {
- final int source = connections[i * 2];
- final int destination = connections[i * 2 + 1];
-
- if (corners[source].getY() > upperBound && corners[destination].getY() < upperBound
- || corners[source].getY() < upperBound && corners[destination].getY() > upperBound) {
- getWorldIntersection(upperBound, corners[source], corners[destination], intersections[nrPoints++],
- tmpStorage);
- }
- if (corners[source].getY() > -upperBound && corners[destination].getY() < -upperBound
- || corners[source].getY() < -upperBound && corners[destination].getY() > -upperBound) {
- getWorldIntersection(-upperBound, corners[source], corners[destination], intersections[nrPoints++],
- tmpStorage);
- }
- }
- // check if any of the frustums corner vertices lie between the upper and lower bound planes
- for (int i = 0; i < 8; i++) {
- if (corners[i].getY() < upperBound && corners[i].getY() > -upperBound) {
- intersections[nrPoints++].set(corners[i]);
- }
- }
-
- if (nrPoints == 0) {
- // No intersection, grid not visible
- return false;
- }
-
- // set projector
- projectorCamera.set(mainCamera);
-
- // force the projector to point at the plane
- if (projectorCamera.getLocation().getY() > 0.0 && projectorCamera.getDirection().getY() > 0.0
- || projectorCamera.getLocation().getY() < 0.0 && projectorCamera.getDirection().getY() < 0.0) {
- projectorCamera.setDirection(new Vector3(projectorCamera.getDirection().getX(), -projectorCamera
- .getDirection().getY(), projectorCamera.getDirection().getZ()));
- projectorCamera.setUp(projectorCamera.getDirection().cross(projectorCamera.getLeft(), null)
- .normalizeLocal());
- }
-
- // find the plane intersection point
- source.set(0.5, 0.5);
- getWorldIntersection(0.0, source, projectorCamera.getModelViewProjectionInverseMatrix(), planeIntersection);
-
- // force the projector to be a certain distance above the plane
- final ReadOnlyVector3 cameraLocation = projectorCamera.getLocation();
- if (cameraLocation.getY() > 0.0 && cameraLocation.getY() < projectorMinHeight * 2) {
- final double delta = (projectorMinHeight * 2 - cameraLocation.getY()) / (projectorMinHeight * 2);
-
- projectorCamera.setLocation(cameraLocation.getX(), projectorMinHeight * 2 - projectorMinHeight * delta,
- cameraLocation.getZ());
- } else if (cameraLocation.getY() < 0.0 && cameraLocation.getY() > -projectorMinHeight * 2) {
- final double delta = (-projectorMinHeight * 2 - cameraLocation.getY()) / (-projectorMinHeight * 2);
-
- projectorCamera.setLocation(cameraLocation.getX(), -projectorMinHeight * 2 + projectorMinHeight * delta,
- cameraLocation.getZ());
- }
-
- // restrict the intersection point to be a certain distance from the camera in plane coords
- planeIntersection.subtractLocal(projectorCamera.getLocation());
- planeIntersection.setY(0.0);
- final double length = planeIntersection.length();
- if (length > Math.abs(projectorCamera.getLocation().getY())) {
- planeIntersection.normalizeLocal();
- planeIntersection.multiplyLocal(Math.abs(projectorCamera.getLocation().getY()));
- } else if (length < MathUtils.EPSILON) {
- planeIntersection.addLocal(projectorCamera.getUp());
- planeIntersection.setY(0.0);
- planeIntersection.normalizeLocal();
- planeIntersection.multiplyLocal(0.1); // TODO: magic number
- }
- planeIntersection.addLocal(projectorCamera.getLocation());
- planeIntersection.setY(0.0);
-
- // point projector at the new intersection point
- projectorCamera.lookAt(planeIntersection, Vector3.UNIT_Y);
-
- // transform points to projector space
- final ReadOnlyMatrix4 modelViewProjectionMatrix = projectorCamera.getModelViewProjectionMatrix();
- final Vector4 spaceTransformation = new Vector4();
- for (int i = 0; i < nrPoints; i++) {
- spaceTransformation.set(intersections[i].getX(), 0.0, intersections[i].getZ(), 1.0);
- modelViewProjectionMatrix.applyPre(spaceTransformation, spaceTransformation);
- intersections[i].set(spaceTransformation.getX(), spaceTransformation.getY(), 0);
- intersections[i].divideLocal(spaceTransformation.getW());
- }
-
- // find min/max in projector space
- double minX = Double.MAX_VALUE;
- double maxX = -Double.MAX_VALUE;
- double minY = Double.MAX_VALUE;
- double maxY = -Double.MAX_VALUE;
- for (int i = 0; i < nrPoints; i++) {
- if (intersections[i].getX() < minX) {
- minX = intersections[i].getX();
- }
- if (intersections[i].getX() > maxX) {
- maxX = intersections[i].getX();
- }
- if (intersections[i].getY() < minY) {
- minY = intersections[i].getY();
- }
- if (intersections[i].getY() > maxY) {
- maxY = intersections[i].getY();
- }
- }
-
- // create range matrix
- rangeMatrix.setIdentity();
- rangeMatrix.setM00(maxX - minX);
- rangeMatrix.setM11(maxY - minY);
- rangeMatrix.setM30(minX);
- rangeMatrix.setM31(minY);
-
- final ReadOnlyMatrix4 modelViewProjectionInverseMatrix = projectorCamera.getModelViewProjectionInverseMatrix();
- rangeMatrix.multiplyLocal(modelViewProjectionInverseMatrix);
-
- // convert screen coords to homogenous world coords with new range matrix
- source.set(0.5, 0.5);
- getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectBottomLeft);
- source.set(0.5, 1);
- getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectTopLeft);
- source.set(1, 1);
- getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectTopRight);
- source.set(1, 0.5);
- getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectBottomRight);
-
- // update data
- if (nrUpdateThreads <= 1) {
- updateGrid(0, sizeY);
- } else {
- for (int i = 0; i < nrUpdateThreads; i++) {
- final int from = sizeY * i / (nrUpdateThreads);
- final int to = sizeY * (i + 1) / (nrUpdateThreads);
- final Future<?> future = executorService.submit(new Runnable() {
- public void run() {
- updateGrid(from, to);
- }
- });
- futureStack.push(future);
- }
- try {
- while (!futureStack.isEmpty()) {
- futureStack.pop().get();
- }
- } catch (final InterruptedException ex) {
- logger.log(Level.SEVERE, "InterruptedException in thread execution", ex);
- } catch (final ExecutionException ex) {
- logger.log(Level.SEVERE, "ExecutionException in thread execution", ex);
- }
- }
-
- vertBuf.rewind();
- vertBuf.put(vertBufArray);
-
- texs.rewind();
- texs.put(texBufArray);
-
- normBuf.rewind();
- normBuf.put(normBufArray);
-
- return true;
- }
-
- private boolean getWorldIntersection(final double planeHeight, final Vector3 source, final Vector3 destination,
- final Vector3 store, final Vector3 tmpStorage) {
- final Vector3 origin = store.set(source);
- final Vector3 direction = tmpStorage.set(destination).subtractLocal(origin);
-
- final double t = (planeHeight - origin.getY()) / (direction.getY());
-
- direction.multiplyLocal(t);
- origin.addLocal(direction);
-
- return t >= 0.0 && t <= 1.0;
- }
-
- private void updateGrid(final int from, final int to) {
- final double time = timer.getTimeInSeconds();
- final double du = 1.0f / (double) (sizeX - 1);
- final double dv = 1.0f / (double) (sizeY - 1);
-
- final Vector4 pointTop = Vector4.fetchTempInstance();
- final Vector4 pointFinal = Vector4.fetchTempInstance();
- final Vector4 pointBottom = Vector4.fetchTempInstance();
-
- int smallerFrom = from;
- if (smallerFrom > 0) {
- smallerFrom--;
- }
- int biggerTo = to;
- if (biggerTo < sizeY) {
- biggerTo++;
- }
- double u = 0, v = smallerFrom * dv;
- int index = smallerFrom * sizeX * 3;
- for (int y = smallerFrom; y < biggerTo; y++) {
- for (int x = 0; x < sizeX; x++) {
- pointTop.lerpLocal(intersectTopLeft, intersectTopRight, u);
- pointBottom.lerpLocal(intersectBottomLeft, intersectBottomRight, u);
- pointFinal.lerpLocal(pointTop, pointBottom, v);
-
- pointFinal.setX(pointFinal.getX() / pointFinal.getW());
- pointFinal.setZ(pointFinal.getZ() / pointFinal.getW());
- pointFinal.setY(heightGenerator.getHeight(pointFinal.getX(), pointFinal.getZ(), time));
-
- vertBufArray[index++] = pointFinal.getXf();
- vertBufArray[index++] = pointFinal.getYf();
- vertBufArray[index++] = pointFinal.getZf();
-
- u += du;
- }
- v += dv;
- u = 0;
- }
-
- Vector4.releaseTempInstance(pointTop);
- Vector4.releaseTempInstance(pointFinal);
- Vector4.releaseTempInstance(pointBottom);
-
- final Vector3 oppositePoint = Vector3.fetchTempInstance();
- final Vector3 adjacentPoint = Vector3.fetchTempInstance();
- final Vector3 rootPoint = Vector3.fetchTempInstance();
-
- int adj = 0, opp = 0;
- int normalIndex = from * sizeX;
- for (int row = from; row < to; row++) {
- for (int col = 0; col < sizeX; col++) {
- if (row == sizeY - 1) {
- if (col == sizeX - 1) { // last row, last col
- // up cross left
- adj = normalIndex - sizeX;
- opp = normalIndex - 1;
- } else { // last row, except for last col
- // right cross up
- adj = normalIndex + 1;
- opp = normalIndex - sizeX;
- }
- } else {
- if (col == sizeX - 1) { // last column except for last row
- // left cross down
- adj = normalIndex - 1;
- opp = normalIndex + sizeX;
- } else { // most cases
- // down cross right
- adj = normalIndex + sizeX;
- opp = normalIndex + 1;
- }
- }
-
- final float x = vertBufArray[normalIndex * 3];
- final float y = vertBufArray[normalIndex * 3 + 1];
- final float z = vertBufArray[normalIndex * 3 + 2];
-
- texBufArray[normalIndex * 2] = x * textureScale;
- texBufArray[normalIndex * 2 + 1] = z * textureScale;
-
- rootPoint.set(x, y, z);
- adjacentPoint.set(vertBufArray[adj * 3], vertBufArray[adj * 3 + 1], vertBufArray[adj * 3 + 2]);
- adjacentPoint.subtractLocal(rootPoint);
- oppositePoint.set(vertBufArray[opp * 3], vertBufArray[opp * 3 + 1], vertBufArray[opp * 3 + 2]);
- oppositePoint.subtractLocal(rootPoint);
-
- adjacentPoint.crossLocal(oppositePoint).normalizeLocal();
-
- normBufArray[normalIndex * 3] = adjacentPoint.getXf();
- normBufArray[normalIndex * 3 + 1] = adjacentPoint.getYf();
- normBufArray[normalIndex * 3 + 2] = adjacentPoint.getZf();
-
- normalIndex++;
- }
- }
-
- Vector3.releaseTempInstance(oppositePoint);
- Vector3.releaseTempInstance(adjacentPoint);
- Vector3.releaseTempInstance(rootPoint);
- }
-
- private void getWorldIntersectionHomogenous(final double planeHeight, final ReadOnlyVector2 screenPosition,
- final ReadOnlyMatrix4 modelViewProjectionInverseMatrix, final Vector4 store) {
- calculateIntersection(planeHeight, screenPosition, modelViewProjectionInverseMatrix);
- store.set(origin);
- }
-
- private void getWorldIntersection(final double planeHeight, final ReadOnlyVector2 screenPosition,
- final ReadOnlyMatrix4 modelViewProjectionInverseMatrix, final Vector3 store) {
- calculateIntersection(planeHeight, screenPosition, modelViewProjectionInverseMatrix);
- store.set(origin.getX(), origin.getY(), origin.getZ()).divideLocal(origin.getW());
- }
-
- private void calculateIntersection(final double planeHeight, final ReadOnlyVector2 screenPosition,
- final ReadOnlyMatrix4 modelViewProjectionInverseMatrix) {
- origin.set(screenPosition.getX() * 2 - 1, screenPosition.getY() * 2 - 1, -1, 1);
- direction.set(screenPosition.getX() * 2 - 1, screenPosition.getY() * 2 - 1, 1, 1);
-
- modelViewProjectionInverseMatrix.applyPre(origin, origin);
- modelViewProjectionInverseMatrix.applyPre(direction, direction);
-
- direction.subtractLocal(origin);
-
- // final double t = (planeHeight * origin.getW() - origin.getY())
- // / (direction.getY() - planeHeight * direction.getW());
-
- if (Math.abs(direction.getY()) > MathUtils.EPSILON) {
- final double t = (planeHeight - origin.getY()) / direction.getY();
- direction.multiplyLocal(t);
- } else {
- direction.normalizeLocal();
- direction.multiplyLocal(mainCamera.getFrustumFar());
- }
-
- origin.addLocal(direction);
- }
-
- /**
- * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
- * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
- * the height map, null is returned.
- *
- * @param position
- * the vector representing the location to find a normal at.
- * @param store
- * the Vector3 object to store the result in. If null, a new one is created.
- * @return the normal vector at the provided location.
- */
- public Vector3 getSurfaceNormal(final Vector2 position, final Vector3 store) {
- return getSurfaceNormal(position.getX(), position.getY(), store);
- }
-
- /**
- * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
- * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
- * the height map, null is returned.
- *
- * @param position
- * the vector representing the location to find a normal at. Only the x and z values are used.
- * @param store
- * the Vector3 object to store the result in. If null, a new one is created.
- * @return the normal vector at the provided location.
- */
- public Vector3 getSurfaceNormal(final Vector3 position, final Vector3 store) {
- return getSurfaceNormal(position.getX(), position.getZ(), store);
- }
-
- /**
- * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
- * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
- * the height map, null is returned.
- *
- * @param x
- * the x coordinate to check.
- * @param z
- * the z coordinate to check.
- * @param store
- * the Vector3 object to store the result in. If null, a new one is created.
- * @return the normal unit vector at the provided location.
- */
- public Vector3 getSurfaceNormal(final double x, final double z, Vector3 store) {
- final double col = MathUtils.floor(x);
- final double row = MathUtils.floor(z);
-
- if (col < 0 || row < 0 || col >= sizeX - 1 || row >= sizeY - 1) {
- return null;
- }
- final double intOnX = x - col, intOnZ = z - row;
-
- if (store == null) {
- store = new Vector3();
- }
-
- final Vector3 topLeft = store, topRight = new Vector3(), bottomLeft = new Vector3(), bottomRight = new Vector3();
-
- final int focalSpot = (int) (col + row * sizeX);
-
- // find the heightmap point closest to this position (but will always
- // be to the left ( < x) and above (< z) of the spot.
- BufferUtils.populateFromBuffer(topLeft, normBuf, focalSpot);
-
- // now find the next point to the right of topLeft's position...
- BufferUtils.populateFromBuffer(topRight, normBuf, focalSpot + 1);
-
- // now find the next point below topLeft's position...
- BufferUtils.populateFromBuffer(bottomLeft, normBuf, focalSpot + sizeX);
-
- // now find the next point below and to the right of topLeft's
- // position...
- BufferUtils.populateFromBuffer(bottomRight, normBuf, focalSpot + sizeX + 1);
-
- // Use linear interpolation to find the height.
- topLeft.lerpLocal(topRight, intOnX);
- bottomLeft.lerpLocal(bottomRight, intOnX);
- topLeft.lerpLocal(bottomLeft, intOnZ);
- return topLeft.normalizeLocal();
- }
-
- /**
- * <code>buildVertices</code> sets up the vertex and index arrays of the TriMesh.
- */
- private void buildVertices(final int vertexCount) {
- vertBuf = BufferUtils.createVector3Buffer(vertBuf, vertexCount);
- _meshData.setVertexBuffer(vertBuf);
-
- final Vector3 point = new Vector3();
- for (int x = 0; x < sizeX; x++) {
- for (int y = 0; y < sizeY; y++) {
- point.set(x, 0, y);
- BufferUtils.setInBuffer(point, vertBuf, (x + (y * sizeX)));
- }
- }
-
- // set up the indices
- final int triangleQuantity = ((sizeX - 1) * (sizeY - 1)) * 2;
- indexBuffer = BufferUtils.createIntBuffer(triangleQuantity * 3);
- _meshData.setIndexBuffer(indexBuffer);
-
- // go through entire array up to the second to last column.
- for (int i = 0; i < (sizeX * (sizeY - 1)); i++) {
- // we want to skip the top row.
- if (i % ((sizeX * (i / sizeX + 1)) - 1) == 0 && i != 0) {
- // logger.info("skip row: "+i+" cause: "+((sizeY * (i / sizeX + 1)) - 1));
- continue;
- } else {
- // logger.info("i: "+i);
- }
- // set the top left corner.
- indexBuffer.put(i);
- // set the bottom right corner.
- indexBuffer.put((1 + sizeX) + i);
- // set the top right corner.
- indexBuffer.put(1 + i);
- // set the top left corner
- indexBuffer.put(i);
- // set the bottom left corner
- indexBuffer.put(sizeX + i);
- // set the bottom right corner
- indexBuffer.put((1 + sizeX) + i);
- }
- }
-
- static class DeamonThreadFactory implements ThreadFactory {
- static final AtomicInteger poolNumber = new AtomicInteger(1);
- final ThreadGroup group;
- final AtomicInteger threadNumber = new AtomicInteger(1);
- final String namePrefix;
-
- DeamonThreadFactory() {
- final SecurityManager s = System.getSecurityManager();
- group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
- namePrefix = "ProjectedGrid Pool-" + poolNumber.getAndIncrement() + "-thread-";
- }
-
- public Thread newThread(final Runnable r) {
- final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
- if (!t.isDaemon()) {
- t.setDaemon(true);
- }
- if (t.getPriority() != Thread.NORM_PRIORITY) {
- t.setPriority(Thread.NORM_PRIORITY);
- }
- return t;
- }
- }
-
- public double getProjectorMinHeight() {
- return projectorMinHeight;
- }
-
- public void setProjectorMinHeight(final double projectorMinHeight) {
- this.projectorMinHeight = projectorMinHeight;
- }
-
- public boolean isDrawDebug() {
- return drawDebug;
- }
-
- public void setDrawDebug(final boolean drawDebug) {
- this.drawDebug = drawDebug;
- }
-}
+/**
+ * Copyright (c) 2008 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.water;
+
+import java.nio.FloatBuffer;
+import java.util.Stack;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.math.Matrix4;
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.Vector4;
+import com.ardor3d.math.type.ReadOnlyMatrix4;
+import com.ardor3d.math.type.ReadOnlyVector2;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.scenegraph.IndexBufferData;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.util.ExtendedCamera;
+import com.ardor3d.util.Timer;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.geom.Debugger;
+
+/**
+ * <code>ProjectedGrid</code> Projected grid mesh
+ */
+public class ProjectedGrid extends Mesh {
+ /** The Constant logger. */
+ private static final Logger logger = Logger.getLogger(ProjectedGrid.class.getName());
+
+ private final int sizeX;
+ private final int sizeY;
+
+ private FloatBuffer vertBuf;
+ private final FloatBuffer normBuf;
+ private final FloatBuffer texs;
+
+ private final ExtendedCamera mainCamera = new ExtendedCamera();
+ private final Camera projectorCamera = new Camera();
+
+ private final Vector4 origin = new Vector4();
+ private final Vector4 direction = new Vector4();
+ private final Vector2 source = new Vector2();
+ private final Matrix4 rangeMatrix = new Matrix4();
+
+ private final Vector4 intersectBottomLeft = new Vector4();
+ private final Vector4 intersectTopLeft = new Vector4();
+ private final Vector4 intersectTopRight = new Vector4();
+ private final Vector4 intersectBottomRight = new Vector4();
+
+ private final Vector3 planeIntersection = new Vector3();
+
+ public boolean freezeProjector = false;
+ private final Timer timer;
+ private final Camera camera;
+
+ private final HeightGenerator heightGenerator;
+ private final float textureScale;
+
+ private double projectorMinHeight = 100.0;
+ private final Vector3[] intersections = new Vector3[24];
+
+ private final float[] vertBufArray;
+ private final float[] normBufArray;
+ private final float[] texBufArray;
+
+ private int nrUpdateThreads = 1;
+ private final ExecutorService executorService = Executors.newCachedThreadPool(new DeamonThreadFactory());
+ private final Stack<Future<?>> futureStack = new Stack<Future<?>>();
+
+ private final int connections[] = { 0, 1, 2, 3, 0, 4, 1, 5, 2, 6, 3, 7, 4, 5, 6, 7, };
+
+ // Debug drawing
+ private boolean drawDebug = false;
+
+ public ProjectedGrid(final String name, final Camera camera, final int sizeX, final int sizeY,
+ final float textureScale, final HeightGenerator heightGenerator, final Timer timer) {
+ super(name);
+ this.sizeX = sizeX;
+ this.sizeY = sizeY;
+ this.textureScale = textureScale;
+ this.heightGenerator = heightGenerator;
+ this.camera = camera;
+ this.timer = timer;
+
+ buildVertices(sizeX * sizeY);
+ texs = BufferUtils.createVector2Buffer(_meshData.getVertexCount());
+ _meshData.setTextureBuffer(texs, 0);
+ normBuf = BufferUtils.createVector3Buffer(_meshData.getVertexCount());
+ _meshData.setNormalBuffer(normBuf);
+
+ vertBufArray = new float[_meshData.getVertexCount() * 3];
+ normBufArray = new float[_meshData.getVertexCount() * 3];
+ texBufArray = new float[_meshData.getVertexCount() * 2];
+
+ for (int i = 0; i < 24; i++) {
+ intersections[i] = new Vector3();
+ }
+ }
+
+ public void setNrUpdateThreads(final int nrUpdateThreads) {
+ this.nrUpdateThreads = nrUpdateThreads;
+ if (this.nrUpdateThreads < 1) {
+ this.nrUpdateThreads = 1;
+ }
+ }
+
+ public int getNrUpdateThreads() {
+ return nrUpdateThreads;
+ }
+
+ public void setFreezeUpdate(final boolean freeze) {
+ freezeProjector = freeze;
+ }
+
+ public boolean isFreezeUpdate() {
+ return freezeProjector;
+ }
+
+ @Override
+ public void render(final Renderer renderer) {
+ final boolean doDraw = update();
+ if (doDraw) {
+ super.render(renderer);
+ }
+
+ if (drawDebug) {
+ Debugger.drawCameraFrustum(renderer, mainCamera, new ColorRGBA(1, 0, 0, 1), (short) 0xFFFF, true);
+ Debugger.drawCameraFrustum(renderer, projectorCamera, new ColorRGBA(0, 1, 1, 1), (short) 0xFFFF, true);
+ }
+ }
+
+ public boolean update() {
+ final double upperBound = heightGenerator.getMaximumHeight();
+
+ if (!freezeProjector) {
+ mainCamera.set(camera);
+
+ final Vector3 tmp = new Vector3();
+ getWorldTransform().applyInverse(mainCamera.getLocation(), tmp);
+ mainCamera.setLocation(tmp);
+ getWorldTransform().applyInverseVector(mainCamera.getLeft(), tmp);
+ mainCamera.setLeft(tmp);
+ getWorldTransform().applyInverseVector(mainCamera.getUp(), tmp);
+ mainCamera.setUp(tmp);
+ getWorldTransform().applyInverseVector(mainCamera.getDirection(), tmp);
+ mainCamera.setDirection(tmp);
+ }
+
+ final ReadOnlyVector3 mainCameraLocation = mainCamera.getLocation();
+ if (mainCameraLocation.getY() > 0.0 && mainCameraLocation.getY() < upperBound + mainCamera.getFrustumNear()) {
+ mainCamera.setLocation(mainCameraLocation.getX(), upperBound + mainCamera.getFrustumNear(),
+ mainCameraLocation.getZ());
+ } else if (mainCameraLocation.getY() < 0.0
+ && mainCameraLocation.getY() > -upperBound - mainCamera.getFrustumNear()) {
+ mainCamera.setLocation(mainCameraLocation.getX(), -upperBound - mainCamera.getFrustumNear(),
+ mainCameraLocation.getZ());
+ }
+ mainCamera.calculateFrustum();
+ final Vector3[] corners = mainCamera.getCorners();
+
+ int nrPoints = 0;
+
+ // check intersections of frustum connections with upper and lower bound
+ final Vector3 tmpStorage = Vector3.fetchTempInstance();
+ for (int i = 0; i < 8; i++) {
+ final int source = connections[i * 2];
+ final int destination = connections[i * 2 + 1];
+
+ if (corners[source].getY() > upperBound && corners[destination].getY() < upperBound
+ || corners[source].getY() < upperBound && corners[destination].getY() > upperBound) {
+ getWorldIntersection(upperBound, corners[source], corners[destination], intersections[nrPoints++],
+ tmpStorage);
+ }
+ if (corners[source].getY() > -upperBound && corners[destination].getY() < -upperBound
+ || corners[source].getY() < -upperBound && corners[destination].getY() > -upperBound) {
+ getWorldIntersection(-upperBound, corners[source], corners[destination], intersections[nrPoints++],
+ tmpStorage);
+ }
+ }
+ // check if any of the frustums corner vertices lie between the upper and lower bound planes
+ for (int i = 0; i < 8; i++) {
+ if (corners[i].getY() < upperBound && corners[i].getY() > -upperBound) {
+ intersections[nrPoints++].set(corners[i]);
+ }
+ }
+
+ if (nrPoints == 0) {
+ // No intersection, grid not visible
+ return false;
+ }
+
+ // set projector
+ projectorCamera.set(mainCamera);
+
+ // force the projector to point at the plane
+ if (projectorCamera.getLocation().getY() > 0.0 && projectorCamera.getDirection().getY() > 0.0
+ || projectorCamera.getLocation().getY() < 0.0 && projectorCamera.getDirection().getY() < 0.0) {
+ projectorCamera.setDirection(new Vector3(projectorCamera.getDirection().getX(), -projectorCamera
+ .getDirection().getY(), projectorCamera.getDirection().getZ()));
+ projectorCamera.setUp(projectorCamera.getDirection().cross(projectorCamera.getLeft(), null)
+ .normalizeLocal());
+ }
+
+ // find the plane intersection point
+ source.set(0.5, 0.5);
+ getWorldIntersection(0.0, source, projectorCamera.getModelViewProjectionInverseMatrix(), planeIntersection);
+
+ // force the projector to be a certain distance above the plane
+ final ReadOnlyVector3 cameraLocation = projectorCamera.getLocation();
+ if (cameraLocation.getY() > 0.0 && cameraLocation.getY() < projectorMinHeight * 2) {
+ final double delta = (projectorMinHeight * 2 - cameraLocation.getY()) / (projectorMinHeight * 2);
+
+ projectorCamera.setLocation(cameraLocation.getX(), projectorMinHeight * 2 - projectorMinHeight * delta,
+ cameraLocation.getZ());
+ } else if (cameraLocation.getY() < 0.0 && cameraLocation.getY() > -projectorMinHeight * 2) {
+ final double delta = (-projectorMinHeight * 2 - cameraLocation.getY()) / (-projectorMinHeight * 2);
+
+ projectorCamera.setLocation(cameraLocation.getX(), -projectorMinHeight * 2 + projectorMinHeight * delta,
+ cameraLocation.getZ());
+ }
+
+ // restrict the intersection point to be a certain distance from the camera in plane coords
+ planeIntersection.subtractLocal(projectorCamera.getLocation());
+ planeIntersection.setY(0.0);
+ final double length = planeIntersection.length();
+ if (length > Math.abs(projectorCamera.getLocation().getY())) {
+ planeIntersection.normalizeLocal();
+ planeIntersection.multiplyLocal(Math.abs(projectorCamera.getLocation().getY()));
+ } else if (length < MathUtils.EPSILON) {
+ planeIntersection.addLocal(projectorCamera.getUp());
+ planeIntersection.setY(0.0);
+ planeIntersection.normalizeLocal();
+ planeIntersection.multiplyLocal(0.1); // TODO: magic number
+ }
+ planeIntersection.addLocal(projectorCamera.getLocation());
+ planeIntersection.setY(0.0);
+
+ // point projector at the new intersection point
+ projectorCamera.lookAt(planeIntersection, Vector3.UNIT_Y);
+
+ // transform points to projector space
+ final ReadOnlyMatrix4 modelViewProjectionMatrix = projectorCamera.getModelViewProjectionMatrix();
+ final Vector4 spaceTransformation = new Vector4();
+ for (int i = 0; i < nrPoints; i++) {
+ spaceTransformation.set(intersections[i].getX(), 0.0, intersections[i].getZ(), 1.0);
+ modelViewProjectionMatrix.applyPre(spaceTransformation, spaceTransformation);
+ intersections[i].set(spaceTransformation.getX(), spaceTransformation.getY(), 0);
+ intersections[i].divideLocal(spaceTransformation.getW());
+ }
+
+ // find min/max in projector space
+ double minX = Double.MAX_VALUE;
+ double maxX = -Double.MAX_VALUE;
+ double minY = Double.MAX_VALUE;
+ double maxY = -Double.MAX_VALUE;
+ for (int i = 0; i < nrPoints; i++) {
+ if (intersections[i].getX() < minX) {
+ minX = intersections[i].getX();
+ }
+ if (intersections[i].getX() > maxX) {
+ maxX = intersections[i].getX();
+ }
+ if (intersections[i].getY() < minY) {
+ minY = intersections[i].getY();
+ }
+ if (intersections[i].getY() > maxY) {
+ maxY = intersections[i].getY();
+ }
+ }
+
+ // create range matrix
+ rangeMatrix.setIdentity();
+ rangeMatrix.setM00(maxX - minX);
+ rangeMatrix.setM11(maxY - minY);
+ rangeMatrix.setM30(minX);
+ rangeMatrix.setM31(minY);
+
+ final ReadOnlyMatrix4 modelViewProjectionInverseMatrix = projectorCamera.getModelViewProjectionInverseMatrix();
+ rangeMatrix.multiplyLocal(modelViewProjectionInverseMatrix);
+
+ // convert screen coords to homogenous world coords with new range matrix
+ source.set(0.5, 0.5);
+ getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectBottomLeft);
+ source.set(0.5, 1);
+ getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectTopLeft);
+ source.set(1, 1);
+ getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectTopRight);
+ source.set(1, 0.5);
+ getWorldIntersectionHomogenous(0.0, source, rangeMatrix, intersectBottomRight);
+
+ // update data
+ if (nrUpdateThreads <= 1) {
+ updateGrid(0, sizeY);
+ } else {
+ for (int i = 0; i < nrUpdateThreads; i++) {
+ final int from = sizeY * i / (nrUpdateThreads);
+ final int to = sizeY * (i + 1) / (nrUpdateThreads);
+ final Future<?> future = executorService.submit(new Runnable() {
+ public void run() {
+ updateGrid(from, to);
+ }
+ });
+ futureStack.push(future);
+ }
+ try {
+ while (!futureStack.isEmpty()) {
+ futureStack.pop().get();
+ }
+ } catch (final InterruptedException ex) {
+ logger.log(Level.SEVERE, "InterruptedException in thread execution", ex);
+ } catch (final ExecutionException ex) {
+ logger.log(Level.SEVERE, "ExecutionException in thread execution", ex);
+ }
+ }
+
+ vertBuf.rewind();
+ vertBuf.put(vertBufArray);
+
+ texs.rewind();
+ texs.put(texBufArray);
+
+ normBuf.rewind();
+ normBuf.put(normBufArray);
+
+ return true;
+ }
+
+ private boolean getWorldIntersection(final double planeHeight, final Vector3 source, final Vector3 destination,
+ final Vector3 store, final Vector3 tmpStorage) {
+ final Vector3 origin = store.set(source);
+ final Vector3 direction = tmpStorage.set(destination).subtractLocal(origin);
+
+ final double t = (planeHeight - origin.getY()) / (direction.getY());
+
+ direction.multiplyLocal(t);
+ origin.addLocal(direction);
+
+ return t >= 0.0 && t <= 1.0;
+ }
+
+ private void updateGrid(final int from, final int to) {
+ final double time = timer.getTimeInSeconds();
+ final double du = 1.0f / (double) (sizeX - 1);
+ final double dv = 1.0f / (double) (sizeY - 1);
+
+ final Vector4 pointTop = Vector4.fetchTempInstance();
+ final Vector4 pointFinal = Vector4.fetchTempInstance();
+ final Vector4 pointBottom = Vector4.fetchTempInstance();
+
+ int smallerFrom = from;
+ if (smallerFrom > 0) {
+ smallerFrom--;
+ }
+ int biggerTo = to;
+ if (biggerTo < sizeY) {
+ biggerTo++;
+ }
+ double u = 0, v = smallerFrom * dv;
+ int index = smallerFrom * sizeX * 3;
+ for (int y = smallerFrom; y < biggerTo; y++) {
+ for (int x = 0; x < sizeX; x++) {
+ pointTop.lerpLocal(intersectTopLeft, intersectTopRight, u);
+ pointBottom.lerpLocal(intersectBottomLeft, intersectBottomRight, u);
+ pointFinal.lerpLocal(pointTop, pointBottom, v);
+
+ pointFinal.setX(pointFinal.getX() / pointFinal.getW());
+ pointFinal.setZ(pointFinal.getZ() / pointFinal.getW());
+ pointFinal.setY(heightGenerator.getHeight(pointFinal.getX(), pointFinal.getZ(), time));
+
+ vertBufArray[index++] = pointFinal.getXf();
+ vertBufArray[index++] = pointFinal.getYf();
+ vertBufArray[index++] = pointFinal.getZf();
+
+ u += du;
+ }
+ v += dv;
+ u = 0;
+ }
+
+ Vector4.releaseTempInstance(pointTop);
+ Vector4.releaseTempInstance(pointFinal);
+ Vector4.releaseTempInstance(pointBottom);
+
+ final Vector3 oppositePoint = Vector3.fetchTempInstance();
+ final Vector3 adjacentPoint = Vector3.fetchTempInstance();
+ final Vector3 rootPoint = Vector3.fetchTempInstance();
+
+ int adj = 0, opp = 0;
+ int normalIndex = from * sizeX;
+ for (int row = from; row < to; row++) {
+ for (int col = 0; col < sizeX; col++) {
+ if (row == sizeY - 1) {
+ if (col == sizeX - 1) { // last row, last col
+ // up cross left
+ adj = normalIndex - sizeX;
+ opp = normalIndex - 1;
+ } else { // last row, except for last col
+ // right cross up
+ adj = normalIndex + 1;
+ opp = normalIndex - sizeX;
+ }
+ } else {
+ if (col == sizeX - 1) { // last column except for last row
+ // left cross down
+ adj = normalIndex - 1;
+ opp = normalIndex + sizeX;
+ } else { // most cases
+ // down cross right
+ adj = normalIndex + sizeX;
+ opp = normalIndex + 1;
+ }
+ }
+
+ final float x = vertBufArray[normalIndex * 3];
+ final float y = vertBufArray[normalIndex * 3 + 1];
+ final float z = vertBufArray[normalIndex * 3 + 2];
+
+ texBufArray[normalIndex * 2] = x * textureScale;
+ texBufArray[normalIndex * 2 + 1] = z * textureScale;
+
+ rootPoint.set(x, y, z);
+ adjacentPoint.set(vertBufArray[adj * 3], vertBufArray[adj * 3 + 1], vertBufArray[adj * 3 + 2]);
+ adjacentPoint.subtractLocal(rootPoint);
+ oppositePoint.set(vertBufArray[opp * 3], vertBufArray[opp * 3 + 1], vertBufArray[opp * 3 + 2]);
+ oppositePoint.subtractLocal(rootPoint);
+
+ adjacentPoint.crossLocal(oppositePoint).normalizeLocal();
+
+ normBufArray[normalIndex * 3] = adjacentPoint.getXf();
+ normBufArray[normalIndex * 3 + 1] = adjacentPoint.getYf();
+ normBufArray[normalIndex * 3 + 2] = adjacentPoint.getZf();
+
+ normalIndex++;
+ }
+ }
+
+ Vector3.releaseTempInstance(oppositePoint);
+ Vector3.releaseTempInstance(adjacentPoint);
+ Vector3.releaseTempInstance(rootPoint);
+ }
+
+ private void getWorldIntersectionHomogenous(final double planeHeight, final ReadOnlyVector2 screenPosition,
+ final ReadOnlyMatrix4 modelViewProjectionInverseMatrix, final Vector4 store) {
+ calculateIntersection(planeHeight, screenPosition, modelViewProjectionInverseMatrix);
+ store.set(origin);
+ }
+
+ private void getWorldIntersection(final double planeHeight, final ReadOnlyVector2 screenPosition,
+ final ReadOnlyMatrix4 modelViewProjectionInverseMatrix, final Vector3 store) {
+ calculateIntersection(planeHeight, screenPosition, modelViewProjectionInverseMatrix);
+ store.set(origin.getX(), origin.getY(), origin.getZ()).divideLocal(origin.getW());
+ }
+
+ private void calculateIntersection(final double planeHeight, final ReadOnlyVector2 screenPosition,
+ final ReadOnlyMatrix4 modelViewProjectionInverseMatrix) {
+ origin.set(screenPosition.getX() * 2 - 1, screenPosition.getY() * 2 - 1, -1, 1);
+ direction.set(screenPosition.getX() * 2 - 1, screenPosition.getY() * 2 - 1, 1, 1);
+
+ modelViewProjectionInverseMatrix.applyPre(origin, origin);
+ modelViewProjectionInverseMatrix.applyPre(direction, direction);
+
+ direction.subtractLocal(origin);
+
+ // final double t = (planeHeight * origin.getW() - origin.getY())
+ // / (direction.getY() - planeHeight * direction.getW());
+
+ if (Math.abs(direction.getY()) > MathUtils.EPSILON) {
+ final double t = (planeHeight - origin.getY()) / direction.getY();
+ direction.multiplyLocal(t);
+ } else {
+ direction.normalizeLocal();
+ direction.multiplyLocal(mainCamera.getFrustumFar());
+ }
+
+ origin.addLocal(direction);
+ }
+
+ /**
+ * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
+ * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
+ * the height map, null is returned.
+ *
+ * @param position
+ * the vector representing the location to find a normal at.
+ * @param store
+ * the Vector3 object to store the result in. If null, a new one is created.
+ * @return the normal vector at the provided location.
+ */
+ public Vector3 getSurfaceNormal(final Vector2 position, final Vector3 store) {
+ return getSurfaceNormal(position.getX(), position.getY(), store);
+ }
+
+ /**
+ * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
+ * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
+ * the height map, null is returned.
+ *
+ * @param position
+ * the vector representing the location to find a normal at. Only the x and z values are used.
+ * @param store
+ * the Vector3 object to store the result in. If null, a new one is created.
+ * @return the normal vector at the provided location.
+ */
+ public Vector3 getSurfaceNormal(final Vector3 position, final Vector3 store) {
+ return getSurfaceNormal(position.getX(), position.getZ(), store);
+ }
+
+ /**
+ * <code>getSurfaceNormal</code> returns the normal of an arbitrary point on the terrain. The normal is linearly
+ * interpreted from the normals of the 4 nearest defined points. If the point provided is not within the bounds of
+ * the height map, null is returned.
+ *
+ * @param x
+ * the x coordinate to check.
+ * @param z
+ * the z coordinate to check.
+ * @param store
+ * the Vector3 object to store the result in. If null, a new one is created.
+ * @return the normal unit vector at the provided location.
+ */
+ public Vector3 getSurfaceNormal(final double x, final double z, Vector3 store) {
+ final double col = MathUtils.floor(x);
+ final double row = MathUtils.floor(z);
+
+ if (col < 0 || row < 0 || col >= sizeX - 1 || row >= sizeY - 1) {
+ return null;
+ }
+ final double intOnX = x - col, intOnZ = z - row;
+
+ if (store == null) {
+ store = new Vector3();
+ }
+
+ final Vector3 topLeft = store, topRight = new Vector3(), bottomLeft = new Vector3(), bottomRight = new Vector3();
+
+ final int focalSpot = (int) (col + row * sizeX);
+
+ // find the heightmap point closest to this position (but will always
+ // be to the left ( < x) and above (< z) of the spot.
+ BufferUtils.populateFromBuffer(topLeft, normBuf, focalSpot);
+
+ // now find the next point to the right of topLeft's position...
+ BufferUtils.populateFromBuffer(topRight, normBuf, focalSpot + 1);
+
+ // now find the next point below topLeft's position...
+ BufferUtils.populateFromBuffer(bottomLeft, normBuf, focalSpot + sizeX);
+
+ // now find the next point below and to the right of topLeft's
+ // position...
+ BufferUtils.populateFromBuffer(bottomRight, normBuf, focalSpot + sizeX + 1);
+
+ // Use linear interpolation to find the height.
+ topLeft.lerpLocal(topRight, intOnX);
+ bottomLeft.lerpLocal(bottomRight, intOnX);
+ topLeft.lerpLocal(bottomLeft, intOnZ);
+ return topLeft.normalizeLocal();
+ }
+
+ /**
+ * <code>buildVertices</code> sets up the vertex and index arrays of the TriMesh.
+ */
+ private void buildVertices(final int vertexCount) {
+ vertBuf = BufferUtils.createVector3Buffer(vertBuf, vertexCount);
+ _meshData.setVertexBuffer(vertBuf);
+
+ final Vector3 point = new Vector3();
+ for (int x = 0; x < sizeX; x++) {
+ for (int y = 0; y < sizeY; y++) {
+ point.set(x, 0, y);
+ BufferUtils.setInBuffer(point, vertBuf, (x + (y * sizeX)));
+ }
+ }
+
+ // set up the indices
+ final int triangleQuantity = ((sizeX - 1) * (sizeY - 1)) * 2;
+ final IndexBufferData<?> indices = BufferUtils.createIndexBufferData(triangleQuantity * 3, vertexCount - 1);
+ _meshData.setIndices(indices);
+
+ // go through entire array up to the second to last column.
+ for (int i = 0; i < (sizeX * (sizeY - 1)); i++) {
+ // we want to skip the top row.
+ if (i % ((sizeX * (i / sizeX + 1)) - 1) == 0 && i != 0) {
+ // logger.info("skip row: "+i+" cause: "+((sizeY * (i / sizeX + 1)) - 1));
+ continue;
+ } else {
+ // logger.info("i: "+i);
+ }
+ // set the top left corner.
+ indices.put(i);
+ // set the bottom right corner.
+ indices.put((1 + sizeX) + i);
+ // set the top right corner.
+ indices.put(1 + i);
+ // set the top left corner
+ indices.put(i);
+ // set the bottom left corner
+ indices.put(sizeX + i);
+ // set the bottom right corner
+ indices.put((1 + sizeX) + i);
+ }
+ }
+
+ static class DeamonThreadFactory implements ThreadFactory {
+ static final AtomicInteger poolNumber = new AtomicInteger(1);
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final String namePrefix;
+
+ DeamonThreadFactory() {
+ final SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+ namePrefix = "ProjectedGrid Pool-" + poolNumber.getAndIncrement() + "-thread-";
+ }
+
+ public Thread newThread(final Runnable r) {
+ final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
+ if (!t.isDaemon()) {
+ t.setDaemon(true);
+ }
+ if (t.getPriority() != Thread.NORM_PRIORITY) {
+ t.setPriority(Thread.NORM_PRIORITY);
+ }
+ return t;
+ }
+ }
+
+ public double getProjectorMinHeight() {
+ return projectorMinHeight;
+ }
+
+ public void setProjectorMinHeight(final double projectorMinHeight) {
+ this.projectorMinHeight = projectorMinHeight;
+ }
+
+ public boolean isDrawDebug() {
+ return drawDebug;
+ }
+
+ public void setDrawDebug(final boolean drawDebug) {
+ this.drawDebug = drawDebug;
+ }
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterHeightGenerator.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterHeightGenerator.java
index 46c348a..b7e86ef 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterHeightGenerator.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterHeightGenerator.java
@@ -1,127 +1,127 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.water;
-
-/**
- * Sample implementation of a water height generator.
- */
-public class WaterHeightGenerator implements HeightGenerator {
- private double scalexsmall = 0.04;
- private double scaleysmall = 0.02;
- private double scalexbig = 0.015;
- private double scaleybig = 0.01;
- private double heightsmall = 3.0;
- private double heightbig = 10.0;
- private double speedsmall = 1.0;
- private double speedbig = 0.5;
- private int octaves = 2;
-
- public double getHeight(final double x, final double z, final double time) {
- final double zval = z * scaleybig * 4 + time * speedbig * 4;
- double height = Math.sin(zval);
- height *= heightbig;
-
- if (octaves > 0) {
- final double height2 = ImprovedNoise.noise(x * scaleybig, z * scalexbig, time * speedbig) * heightbig;
- height = height * 0.4 + height2 * 0.6;
- }
- if (octaves > 1) {
- height += ImprovedNoise.noise(x * scaleysmall, z * scalexsmall, time * speedsmall) * heightsmall;
- }
- if (octaves > 2) {
- height += ImprovedNoise.noise(x * scaleysmall * 2.0, z * scalexsmall * 2.0, time * speedsmall * 1.5)
- * heightsmall * 0.5;
- }
- if (octaves > 3) {
- height += ImprovedNoise.noise(x * scaleysmall * 4.0, z * scalexsmall * 4.0, time * speedsmall * 2.0)
- * heightsmall * 0.25;
- }
-
- return height; // + waterHeight
- }
-
- public double getScalexsmall() {
- return scalexsmall;
- }
-
- public void setScalexsmall(final double scalexsmall) {
- this.scalexsmall = scalexsmall;
- }
-
- public double getScaleysmall() {
- return scaleysmall;
- }
-
- public void setScaleysmall(final double scaleysmall) {
- this.scaleysmall = scaleysmall;
- }
-
- public double getScalexbig() {
- return scalexbig;
- }
-
- public void setScalexbig(final double scalexbig) {
- this.scalexbig = scalexbig;
- }
-
- public double getScaleybig() {
- return scaleybig;
- }
-
- public void setScaleybig(final double scaleybig) {
- this.scaleybig = scaleybig;
- }
-
- public double getHeightsmall() {
- return heightsmall;
- }
-
- public void setHeightsmall(final double heightsmall) {
- this.heightsmall = heightsmall;
- }
-
- public double getHeightbig() {
- return heightbig;
- }
-
- public void setHeightbig(final double heightbig) {
- this.heightbig = heightbig;
- }
-
- public double getSpeedsmall() {
- return speedsmall;
- }
-
- public void setSpeedsmall(final double speedsmall) {
- this.speedsmall = speedsmall;
- }
-
- public double getSpeedbig() {
- return speedbig;
- }
-
- public void setSpeedbig(final double speedbig) {
- this.speedbig = speedbig;
- }
-
- public int getOctaves() {
- return octaves;
- }
-
- public void setOctaves(final int octaves) {
- this.octaves = octaves;
- }
-
- @Override
- public double getMaximumHeight() {
- return 15.0;
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.water;
+
+/**
+ * Sample implementation of a water height generator.
+ */
+public class WaterHeightGenerator implements HeightGenerator {
+ private double scalexsmall = 0.04;
+ private double scaleysmall = 0.02;
+ private double scalexbig = 0.015;
+ private double scaleybig = 0.01;
+ private double heightsmall = 3.0;
+ private double heightbig = 10.0;
+ private double speedsmall = 1.0;
+ private double speedbig = 0.5;
+ private int octaves = 2;
+
+ public double getHeight(final double x, final double z, final double time) {
+ final double zval = z * scaleybig * 4 + time * speedbig * 4;
+ double height = Math.sin(zval);
+ height *= heightbig;
+
+ if (octaves > 0) {
+ final double height2 = ImprovedNoise.noise(x * scaleybig, z * scalexbig, time * speedbig) * heightbig;
+ height = height * 0.4 + height2 * 0.6;
+ }
+ if (octaves > 1) {
+ height += ImprovedNoise.noise(x * scaleysmall, z * scalexsmall, time * speedsmall) * heightsmall;
+ }
+ if (octaves > 2) {
+ height += ImprovedNoise.noise(x * scaleysmall * 2.0, z * scalexsmall * 2.0, time * speedsmall * 1.5)
+ * heightsmall * 0.5;
+ }
+ if (octaves > 3) {
+ height += ImprovedNoise.noise(x * scaleysmall * 4.0, z * scalexsmall * 4.0, time * speedsmall * 2.0)
+ * heightsmall * 0.25;
+ }
+
+ return height; // + waterHeight
+ }
+
+ public double getScalexsmall() {
+ return scalexsmall;
+ }
+
+ public void setScalexsmall(final double scalexsmall) {
+ this.scalexsmall = scalexsmall;
+ }
+
+ public double getScaleysmall() {
+ return scaleysmall;
+ }
+
+ public void setScaleysmall(final double scaleysmall) {
+ this.scaleysmall = scaleysmall;
+ }
+
+ public double getScalexbig() {
+ return scalexbig;
+ }
+
+ public void setScalexbig(final double scalexbig) {
+ this.scalexbig = scalexbig;
+ }
+
+ public double getScaleybig() {
+ return scaleybig;
+ }
+
+ public void setScaleybig(final double scaleybig) {
+ this.scaleybig = scaleybig;
+ }
+
+ public double getHeightsmall() {
+ return heightsmall;
+ }
+
+ public void setHeightsmall(final double heightsmall) {
+ this.heightsmall = heightsmall;
+ }
+
+ public double getHeightbig() {
+ return heightbig;
+ }
+
+ public void setHeightbig(final double heightbig) {
+ this.heightbig = heightbig;
+ }
+
+ public double getSpeedsmall() {
+ return speedsmall;
+ }
+
+ public void setSpeedsmall(final double speedsmall) {
+ this.speedsmall = speedsmall;
+ }
+
+ public double getSpeedbig() {
+ return speedbig;
+ }
+
+ public void setSpeedbig(final double speedbig) {
+ this.speedbig = speedbig;
+ }
+
+ public int getOctaves() {
+ return octaves;
+ }
+
+ public void setOctaves(final int octaves) {
+ this.octaves = octaves;
+ }
+
+ @Override
+ public double getMaximumHeight() {
+ return 15.0;
+ }
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterNode.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterNode.java
index 1db0cdb..3d82ca9 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterNode.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/water/WaterNode.java
@@ -1,1085 +1,1085 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.effect.water;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.ardor3d.image.Texture;
-import com.ardor3d.image.Texture2D;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.Matrix4;
-import com.ardor3d.math.Plane;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.Vector4;
-import com.ardor3d.math.type.ReadOnlyMatrix4;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.Camera.ProjectionMode;
-import com.ardor3d.renderer.ContextCapabilities;
-import com.ardor3d.renderer.ContextManager;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.renderer.TextureRenderer;
-import com.ardor3d.renderer.TextureRendererFactory;
-import com.ardor3d.renderer.queue.RenderBucketType;
-import com.ardor3d.renderer.state.BlendState;
-import com.ardor3d.renderer.state.ClipState;
-import com.ardor3d.renderer.state.CullState;
-import com.ardor3d.renderer.state.FogState;
-import com.ardor3d.renderer.state.GLSLShaderObjectsState;
-import com.ardor3d.renderer.state.TextureState;
-import com.ardor3d.scenegraph.Node;
-import com.ardor3d.scenegraph.Spatial;
-import com.ardor3d.scenegraph.hint.CullHint;
-import com.ardor3d.scenegraph.hint.LightCombineMode;
-import com.ardor3d.scenegraph.hint.TextureCombineMode;
-import com.ardor3d.scenegraph.shape.Quad;
-import com.ardor3d.util.TextureManager;
-import com.ardor3d.util.resource.ResourceLocatorTool;
-import com.google.common.collect.Lists;
-
-/**
- * The WaterNode handles rendering of a water effect on all of it's children. What is reflected in the water is
- * controlled through setReflectedScene/addReflectedScene. The skybox (if any) needs to be explicitly set through
- * setSkybox since it needs to be relocated when rendering the reflection. The water is treated as a plane no matter
- * what the geometry is, which is controlled through the water node plane equation settings.
- */
-public class WaterNode extends Node {
- private static final Logger logger = Logger.getLogger(WaterNode.class.getName());
-
- protected Camera cam;
- protected double tpf;
- protected double reflectionThrottle = 0f, refractionThrottle = 0f;
- protected double reflectionTime = 0, refractionTime = 0;
- protected boolean useFadeToFogColor = false;
-
- protected TextureRenderer tRenderer;
- protected Texture2D textureReflect;
- protected Texture2D textureReflectBlur;
- protected Texture2D textureRefract;
- protected Texture2D textureDepth;
-
- protected ArrayList<Spatial> renderList = Lists.newArrayList();
- protected ArrayList<Texture> texArray = Lists.newArrayList();
- protected Node skyBox;
-
- protected GLSLShaderObjectsState waterShader;
- protected CullState cullBackFace;
- protected TextureState textureState;
- protected TextureState fallbackTextureState;
-
- private Texture normalmapTexture;
- private Texture dudvTexture;
- private Texture foamTexture;
- private Texture fallbackTexture;
- private Matrix4 fallbackTextureStateMatrix;
-
- protected BlendState as1;
- protected FogState noFog;
-
- protected Plane waterPlane;
- protected Vector3 tangent;
- protected Vector3 binormal;
- protected Vector3 calcVect = new Vector3();
- protected double clipBias;
- protected ColorRGBA waterColorStart;
- protected ColorRGBA waterColorEnd;
- protected double heightFalloffStart;
- protected double heightFalloffSpeed;
- protected double waterMaxAmplitude;
- protected double speedReflection;
- protected double speedRefraction;
-
- protected boolean aboveWater;
- protected double normalTranslation = 0.0;
- protected double refractionTranslation = 0.0;
- protected boolean supported = true;
- protected boolean useProjectedShader = false;
- protected boolean useRefraction = false;
- protected boolean useReflection = true;
- protected int renderScale;
-
- protected String simpleShaderStr = "com/ardor3d/extension/effect/water/flatwatershader";
- protected String simpleShaderRefractionStr = "com/ardor3d/extension/effect/water/flatwatershader_refraction";
- protected String projectedShaderStr = "com/ardor3d/extension/effect/water/projectedwatershader";
- protected String projectedShaderRefractionStr = "com/ardor3d/extension/effect/water/projectedwatershader_refraction";
- protected String currentShaderStr;
-
- protected String normalMapTextureString = "";
- protected String dudvMapTextureString = "";
- protected String foamMapTextureString = "";
- protected String fallbackMapTextureString = "";
-
- private GLSLShaderObjectsState blurShaderVertical = null;
- private float blurSampleDistance = 0.002f;
- private Quad fullScreenQuad = null;
- private boolean doBlurReflection = true;
-
- private boolean initialized;
-
- /**
- * Resets water parameters to default values
- *
- */
- public void resetParameters() {
- waterPlane = new Plane(new Vector3(0.0, 1.0, 0.0), 0.0);
- tangent = new Vector3(1.0, 0.0, 0.0);
- binormal = new Vector3(0.0, 0.0, 1.0);
-
- waterMaxAmplitude = 0.0;
- clipBias = 1.0;
- waterColorStart = new ColorRGBA(0.0f, 0.0f, 0.1f, 1.0f);
- waterColorEnd = new ColorRGBA(0.0f, 0.3f, 0.1f, 1.0f);
- heightFalloffStart = 400.0;
- heightFalloffSpeed = 500.0;
- speedReflection = 0.1;
- speedRefraction = -0.05;
- }
-
- /**
- * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
- */
- public void cleanup() {
- if (isSupported() && tRenderer != null) {
- tRenderer.cleanup();
- }
- }
-
- public boolean isSupported() {
- return supported;
- }
-
- /**
- * Creates a new WaterRenderPass
- *
- * @param cam
- * main rendercam to use for reflection settings etc
- * @param renderScale
- * how many times smaller the reflection/refraction textures should be compared to the main display
- * @param useProjectedShader
- * true - use the projected setup for variable height water meshes, false - use the flast shader setup
- * @param useRefraction
- * enable/disable rendering of refraction textures
- */
- public WaterNode(final Camera cam, final int renderScale, final boolean useProjectedShader,
- final boolean useRefraction) {
- this.cam = cam;
- this.useProjectedShader = useProjectedShader;
- this.useRefraction = useRefraction;
- this.renderScale = renderScale;
- resetParameters();
-
- waterShader = new GLSLShaderObjectsState();
- blurShaderVertical = new GLSLShaderObjectsState();
-
- cullBackFace = new CullState();
- cullBackFace.setEnabled(true);
- cullBackFace.setCullFace(CullState.Face.None);
- }
-
- /**
- * Initialize texture renderers. Load water textures. Create shaders.
- *
- * @param r
- */
- private void initialize(final Renderer r) {
- if (cam == null || initialized) {
- return;
- }
- initialized = true;
-
- final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
-
- if (useRefraction && useProjectedShader && caps.getNumberOfFragmentTextureUnits() < 6 || useRefraction
- && caps.getNumberOfFragmentTextureUnits() < 5) {
- useRefraction = false;
- logger.info("Not enough textureunits, falling back to non refraction water");
- }
-
- if (!caps.isGLSLSupported()) {
- supported = false;
- }
- if (!(caps.isPbufferSupported() || caps.isFBOSupported())) {
- supported = false;
- }
-
- if (isSupported()) {
- tRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer( //
- cam.getWidth() / renderScale, // width
- cam.getHeight() / renderScale, // height
- 8, // Depth bits... TODO: Make configurable?
- 0, // Samples... TODO: Make configurable?
- r, caps);
-
- // blurSampleDistance = 1f / ((float) cam.getHeight() / renderScale);
-
- tRenderer.setMultipleTargets(true);
- tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
- tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
- cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
-
- textureState = new TextureState();
- textureState.setEnabled(true);
-
- setupTextures();
-
- fullScreenQuad = new Quad("FullScreenQuad", cam.getWidth() / 4, cam.getHeight() / 4);
- fullScreenQuad.setTranslation(cam.getWidth() / 2, cam.getHeight() / 2, 0);
- fullScreenQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho);
- fullScreenQuad.getSceneHints().setCullHint(CullHint.Never);
- fullScreenQuad.getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
- fullScreenQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off);
- final TextureState ts = new TextureState();
- ts.setTexture(textureReflect);
- fullScreenQuad.setRenderState(ts);
- fullScreenQuad.setRenderState(blurShaderVertical);
- fullScreenQuad.updateWorldRenderStates(false);
- }
-
- if (!isSupported()) {
- createFallbackData();
- } else {
- noFog = new FogState();
- noFog.setEnabled(false);
- }
-
- getSceneHints().setCullHint(CullHint.Never);
-
- setWaterEffectOnSpatial(this);
- }
-
- /**
- * Load water textures.
- */
- protected void setupTextures() {
- textureReflect = new Texture2D();
- textureReflect.setWrap(Texture.WrapMode.EdgeClamp);
- textureReflect.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- Matrix4 matrix = new Matrix4();
- matrix.setM00(-1.0);
- matrix.setM30(1.0);
- textureReflect.setTextureMatrix(matrix);
- tRenderer.setupTexture(textureReflect);
-
- normalmapTexture = TextureManager.load(normalMapTextureString, Texture.MinificationFilter.Trilinear,
- TextureStoreFormat.GuessCompressedFormat, true);
- textureState.setTexture(normalmapTexture, 0);
- normalmapTexture.setWrap(Texture.WrapMode.Repeat);
-
- textureReflectBlur = new Texture2D();
- textureReflectBlur.setWrap(Texture.WrapMode.EdgeClamp);
- textureReflectBlur.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- textureReflectBlur.setTextureMatrix(matrix);
- tRenderer.setupTexture(textureReflectBlur);
-
- textureState.setTexture(textureReflectBlur, 1);
-
- dudvTexture = TextureManager.load(dudvMapTextureString, Texture.MinificationFilter.Trilinear,
- TextureStoreFormat.GuessNoCompressedFormat, true);
- matrix = new Matrix4();
- matrix.setM00(0.8);
- matrix.setM11(0.8);
- dudvTexture.setTextureMatrix(matrix);
- textureState.setTexture(dudvTexture, 2);
- dudvTexture.setWrap(Texture.WrapMode.Repeat);
-
- if (useRefraction) {
- textureRefract = new Texture2D();
- textureRefract.setWrap(Texture.WrapMode.EdgeClamp);
- textureRefract.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- tRenderer.setupTexture(textureRefract);
-
- textureDepth = new Texture2D();
- textureDepth.setWrap(Texture.WrapMode.EdgeClamp);
- textureDepth.setMagnificationFilter(Texture.MagnificationFilter.NearestNeighbor);
- textureDepth.setTextureStoreFormat(TextureStoreFormat.Depth24);
- tRenderer.setupTexture(textureDepth);
-
- textureState.setTexture(textureRefract, 3);
- textureState.setTexture(textureDepth, 4);
- }
-
- if (useProjectedShader) {
- foamTexture = TextureManager.load(foamMapTextureString, Texture.MinificationFilter.Trilinear,
- TextureStoreFormat.GuessCompressedFormat, true);
- if (useRefraction) {
- textureState.setTexture(foamTexture, 5);
- } else {
- textureState.setTexture(foamTexture, 3);
- }
- foamTexture.setWrap(Texture.WrapMode.Repeat);
- }
-
- reloadShader();
- }
-
- /**
- * Create setup to use as fallback if fancy water is not supported.
- */
- private void createFallbackData() {
- fallbackTextureState = new TextureState();
- fallbackTextureState.setEnabled(true);
-
- fallbackTexture = TextureManager.load(fallbackMapTextureString, Texture.MinificationFilter.Trilinear,
- TextureStoreFormat.GuessCompressedFormat, true);
- fallbackTextureState.setTexture(fallbackTexture, 0);
- fallbackTexture.setWrap(Texture.WrapMode.Repeat);
-
- fallbackTextureStateMatrix = new Matrix4();
-
- as1 = new BlendState();
- as1.setBlendEnabled(true);
- as1.setTestEnabled(true);
- as1.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
- as1.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
- as1.setEnabled(true);
- }
-
- public void update(final double tpf) {
- this.tpf = tpf;
- }
-
- @Override
- public void draw(final Renderer r) {
- initialize(r);
-
- updateTranslations();
-
- final double camWaterDist = waterPlane.pseudoDistance(cam.getLocation());
- aboveWater = camWaterDist >= 0;
-
- if (isSupported()) {
- waterShader.setUniform("tangent", tangent);
- waterShader.setUniform("binormal", binormal);
- waterShader.setUniform("useFadeToFogColor", useFadeToFogColor);
- waterShader.setUniform("waterColor", waterColorStart);
- waterShader.setUniform("waterColorEnd", waterColorEnd);
- waterShader.setUniform("normalTranslation", (float) normalTranslation);
- waterShader.setUniform("refractionTranslation", (float) refractionTranslation);
- waterShader.setUniform("abovewater", aboveWater);
- if (useProjectedShader) {
- waterShader.setUniform("cameraPos", cam.getLocation());
- waterShader.setUniform("waterHeight", (float) waterPlane.getConstant());
- waterShader.setUniform("amplitude", (float) waterMaxAmplitude);
- waterShader.setUniform("heightFalloffStart", (float) heightFalloffStart);
- waterShader.setUniform("heightFalloffSpeed", (float) heightFalloffSpeed);
- }
-
- final double heightTotal = clipBias + waterMaxAmplitude - waterPlane.getConstant();
- final Vector4 clipPlane = Vector4.fetchTempInstance();
-
- if (useReflection) {
- clipPlane.set(waterPlane.getNormal().getX(), waterPlane.getNormal().getY(), waterPlane.getNormal()
- .getZ(), heightTotal);
- renderReflection(clipPlane);
- }
-
- if (useRefraction && aboveWater) {
- clipPlane.set(-waterPlane.getNormal().getX(), -waterPlane.getNormal().getY(), -waterPlane.getNormal()
- .getZ(), -waterPlane.getConstant());
- renderRefraction(clipPlane);
- }
- }
-
- if (fallbackTextureState != null) {
- fallbackTextureStateMatrix.setM31(normalTranslation);
- fallbackTexture.setTextureMatrix(fallbackTextureStateMatrix);
- }
-
- super.draw(r);
- }
-
- protected void updateTranslations() {
- normalTranslation += speedReflection * tpf;
- refractionTranslation += speedRefraction * tpf;
- }
-
- public void reloadShader() {
- if (useProjectedShader) {
- if (useRefraction) {
- currentShaderStr = projectedShaderRefractionStr;
- } else {
- currentShaderStr = projectedShaderStr;
- }
- } else {
- if (useRefraction) {
- currentShaderStr = simpleShaderRefractionStr;
- } else {
- currentShaderStr = simpleShaderStr;
- }
- }
-
- try {
- logger.info("loading " + currentShaderStr);
- waterShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
- currentShaderStr + ".vert"));
- waterShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
- currentShaderStr + ".frag"));
- } catch (final IOException e) {
- logger.log(Level.WARNING, "Error loading shader", e);
- return;
- }
-
- waterShader.setUniform("normalMap", 0);
- waterShader.setUniform("reflection", 1);
- waterShader.setUniform("dudvMap", 2);
- if (useRefraction) {
- waterShader.setUniform("refraction", 3);
- waterShader.setUniform("depthMap", 4);
- }
- if (useProjectedShader) {
- if (useRefraction) {
- waterShader.setUniform("foamMap", 5);
- } else {
- waterShader.setUniform("foamMap", 3);
- }
- }
-
- waterShader._needSendShader = true;
-
- try {
- blurShaderVertical.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
- "com/ardor3d/extension/effect/bloom/bloom_blur.vert"));
- blurShaderVertical.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
- "com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- blurShaderVertical.setUniform("RT", 0);
- blurShaderVertical.setUniform("sampleDist", blurSampleDistance);
- blurShaderVertical._needSendShader = true;
-
- logger.info("Shader reloaded...");
- }
-
- /**
- * Sets a spatial up for being rendered with the watereffect
- *
- * @param spatial
- * Spatial to use as base for the watereffect
- */
- public void setWaterEffectOnSpatial(final Spatial spatial) {
- spatial.setRenderState(cullBackFace);
- if (isSupported()) {
- // spatial.setRenderBucketType(RenderBucketType.Skip);
- spatial.setRenderState(waterShader);
- spatial.setRenderState(textureState);
- } else {
- spatial.getSceneHints().setRenderBucketType(RenderBucketType.Transparent);
- spatial.getSceneHints().setLightCombineMode(LightCombineMode.Off);
- spatial.setRenderState(fallbackTextureState);
- spatial.setRenderState(as1);
- }
- }
-
- // temporary vectors for mem opt.
- private final Vector3 tmpLocation = new Vector3();
- private final Vector3 camReflectPos = new Vector3();
- private final Vector3 camReflectDir = new Vector3();
- private final Vector3 camReflectUp = new Vector3();
- private final Vector3 camReflectLeft = new Vector3();
- private final Vector3 camLocation = new Vector3();
-
- /**
- * Render water reflection RTT
- */
- private void renderReflection(final Vector4 clipPlane) {
- if (renderList.isEmpty()) {
- return;
- }
-
- reflectionTime += tpf;
- if (reflectionTime < reflectionThrottle) {
- return;
- }
- reflectionTime = 0;
-
- if (aboveWater) {
- camLocation.set(cam.getLocation());
-
- double planeDistance = waterPlane.pseudoDistance(camLocation);
- calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
- camReflectPos.set(camLocation.subtractLocal(calcVect));
-
- camLocation.set(cam.getLocation()).addLocal(cam.getDirection());
- planeDistance = waterPlane.pseudoDistance(camLocation);
- calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
- camReflectDir.set(camLocation.subtractLocal(calcVect)).subtractLocal(camReflectPos).normalizeLocal();
-
- camLocation.set(cam.getLocation()).addLocal(cam.getUp());
- planeDistance = waterPlane.pseudoDistance(camLocation);
- calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
- camReflectUp.set(camLocation.subtractLocal(calcVect)).subtractLocal(camReflectPos).normalizeLocal();
-
- camReflectLeft.set(camReflectUp).crossLocal(camReflectDir).normalizeLocal();
-
- tRenderer.getCamera().setLocation(camReflectPos);
- tRenderer.getCamera().setDirection(camReflectDir);
- tRenderer.getCamera().setUp(camReflectUp);
- tRenderer.getCamera().setLeft(camReflectLeft);
- } else {
- tRenderer.getCamera().setLocation(cam.getLocation());
- tRenderer.getCamera().setDirection(cam.getDirection());
- tRenderer.getCamera().setUp(cam.getUp());
- tRenderer.getCamera().setLeft(cam.getLeft());
- }
-
- if (skyBox != null) {
- tmpLocation.set(skyBox.getTranslation());
- skyBox.setTranslation(tRenderer.getCamera().getLocation());
- skyBox.updateGeometricState(0.0f);
- skyBox.getSceneHints().setCullHint(CullHint.Never);
- }
-
- texArray.clear();
- if (doBlurReflection) {
- texArray.add(textureReflect);
- } else {
- texArray.add(textureReflectBlur);
- }
-
- tRenderer.getCamera().setProjectionMode(ProjectionMode.Custom);
- tRenderer.getCamera().setProjectionMatrix(cam.getProjectionMatrix());
- tRenderer.render(skyBox, texArray, Renderer.BUFFER_COLOR_AND_DEPTH);
-
- if (skyBox != null) {
- skyBox.getSceneHints().setCullHint(CullHint.Always);
- }
-
- modifyProjectionMatrix(clipPlane);
-
- tRenderer.render(renderList, texArray, Renderer.BUFFER_NONE);
-
- if (doBlurReflection) {
- blurReflectionTexture();
- }
-
- if (skyBox != null) {
- skyBox.setTranslation(tmpLocation);
- skyBox.updateGeometricState(0.0f);
- skyBox.getSceneHints().setCullHint(CullHint.Never);
- }
- }
-
- private void blurReflectionTexture() {
- tRenderer.render(fullScreenQuad, textureReflectBlur, Renderer.BUFFER_NONE);
- }
-
- /**
- * Render water refraction RTT
- */
- private void renderRefraction(final Vector4 clipPlane) {
- if (renderList.isEmpty()) {
- return;
- }
-
- refractionTime += tpf;
- if (refractionTime < refractionThrottle) {
- return;
- }
- refractionTime = 0;
-
- // tRenderer.getCamera().set(cam);
- tRenderer.getCamera().setLocation(cam.getLocation());
- tRenderer.getCamera().setDirection(cam.getDirection());
- tRenderer.getCamera().setUp(cam.getUp());
- tRenderer.getCamera().setLeft(cam.getLeft());
-
- CullHint cullMode = CullHint.Dynamic;
- if (skyBox != null) {
- cullMode = skyBox.getSceneHints().getCullHint();
- skyBox.getSceneHints().setCullHint(CullHint.Always);
- }
-
- tRenderer.getCamera().setProjectionMatrix(cam.getProjectionMatrix());
-
- texArray.clear();
- texArray.add(textureRefract);
- texArray.add(textureDepth);
-
- tRenderer.getCamera().update();
- tRenderer.getCamera().getModelViewMatrix();
- tRenderer.getCamera().getProjectionMatrix();
-
- tRenderer.render(renderList, texArray, Renderer.BUFFER_COLOR_AND_DEPTH);
-
- if (skyBox != null) {
- skyBox.getSceneHints().setCullHint(cullMode);
- }
- }
-
- private double sign(final double a) {
- if (a > 0.0) {
- return 1.0;
- }
- if (a < 0.0) {
- return -1.0;
- }
- return 0.0;
- }
-
- private double projectionMatrix[] = new double[16];
- private final Vector4 cornerPoint = new Vector4();
- private final Matrix4 tmpMatrix = new Matrix4();
-
- private void modifyProjectionMatrix(final Vector4 clipPlane) {
- // Get the current projection matrix
- projectionMatrix = cam.getProjectionMatrix().toArray(projectionMatrix);
-
- // Get the inverse transpose of the current modelview matrix
- final ReadOnlyMatrix4 modelViewMatrixInvTrans = tRenderer.getCamera().getModelViewMatrix().invert(tmpMatrix)
- .transposeLocal();
- modelViewMatrixInvTrans.applyPre(clipPlane, clipPlane);
-
- // Calculate the clip-space corner point opposite the clipping plane
- // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
- // transform it into camera space by multiplying it
- // by the inverse of the projection matrix
- cornerPoint.setX((sign(clipPlane.getX()) + projectionMatrix[8]) / projectionMatrix[0]);
- cornerPoint.setY((sign(clipPlane.getY()) + projectionMatrix[9]) / projectionMatrix[5]);
- cornerPoint.setZ(-1.0);
- cornerPoint.setW((1.0 + projectionMatrix[10]) / projectionMatrix[14]);
-
- // Calculate the scaled plane vector
- final Vector4 scaledPlaneVector = clipPlane.multiply((2.0 / clipPlane.dot(cornerPoint)), cornerPoint);
-
- // Replace the third row of the projection matrix
- projectionMatrix[2] = scaledPlaneVector.getX();
- projectionMatrix[6] = scaledPlaneVector.getY();
- projectionMatrix[10] = scaledPlaneVector.getZ() + 1.0;
- projectionMatrix[14] = scaledPlaneVector.getW();
-
- // Load it back into OpenGL
- final Matrix4 newProjectionMatrix = tmpMatrix.fromArray(projectionMatrix);
- tRenderer.getCamera().setProjectionMatrix(newProjectionMatrix);
- }
-
- public void removeReflectedScene(final Spatial renderNode) {
- if (logger.isLoggable(Level.INFO)) {
- logger.info("Removed reflected scene: " + renderList.remove(renderNode));
- }
- }
-
- public void clearReflectedScene() {
- renderList.clear();
- }
-
- /**
- * Adds a spatial to the list of spatials used as reflection in the water
- *
- * @param renderNode
- * Spatial to add to the list of objects used as reflection in the water
- */
- public void addReflectedScene(final Spatial renderNode) {
- if (renderNode == null) {
- return;
- }
-
- if (!renderList.contains(renderNode)) {
- renderList.add(renderNode);
- }
- }
-
- /**
- * Sets up a node to be transformed and clipped for skybox usage
- *
- * @param skyBox
- * Handle to a node to use as skybox
- */
- public void setSkybox(final Node skyBox) {
- if (skyBox != null) {
- final ClipState skyboxClipState = new ClipState();
- skyboxClipState.setEnabled(false);
- skyBox.setRenderState(skyboxClipState);
- }
-
- this.skyBox = skyBox;
- }
-
- public Camera getCam() {
- return cam;
- }
-
- public void setCam(final Camera cam) {
- this.cam = cam;
- }
-
- public ColorRGBA getWaterColorStart() {
- return waterColorStart;
- }
-
- /**
- * Color to use when the incident angle to the surface is low
- */
- public void setWaterColorStart(final ColorRGBA waterColorStart) {
- this.waterColorStart = waterColorStart;
- }
-
- public ColorRGBA getWaterColorEnd() {
- return waterColorEnd;
- }
-
- /**
- * Color to use when the incident angle to the surface is high
- */
- public void setWaterColorEnd(final ColorRGBA waterColorEnd) {
- this.waterColorEnd = waterColorEnd;
- }
-
- public double getHeightFalloffStart() {
- return heightFalloffStart;
- }
-
- /**
- * Set at what distance the waveheights should start to fade out(for projected water only)
- *
- * @param heightFalloffStart
- */
- public void setHeightFalloffStart(final double heightFalloffStart) {
- this.heightFalloffStart = heightFalloffStart;
- }
-
- public double getHeightFalloffSpeed() {
- return heightFalloffSpeed;
- }
-
- /**
- * Set the fadeout length of the waveheights, when over falloff start(for projected water only)
- *
- * @param heightFalloffStart
- */
- public void setHeightFalloffSpeed(final double heightFalloffSpeed) {
- this.heightFalloffSpeed = heightFalloffSpeed;
- }
-
- public double getWaterHeight() {
- return waterPlane.getConstant();
- }
-
- /**
- * Set base height of the waterplane(Used for reflecting the camera for rendering reflection)
- *
- * @param waterHeight
- * Waterplane height
- */
- public void setWaterHeight(final double waterHeight) {
- waterPlane.setConstant(waterHeight);
- }
-
- public ReadOnlyVector3 getNormal() {
- return waterPlane.getNormal();
- }
-
- /**
- * Set the normal of the waterplane(Used for reflecting the camera for rendering reflection)
- *
- * @param normal
- * Waterplane normal
- */
- public void setNormal(final Vector3 normal) {
- waterPlane.setNormal(normal);
- }
-
- public double getSpeedReflection() {
- return speedReflection;
- }
-
- /**
- * Set the movement speed of the reflectiontexture
- *
- * @param speedReflection
- * Speed of reflectiontexture
- */
- public void setSpeedReflection(final double speedReflection) {
- this.speedReflection = speedReflection;
- }
-
- public double getSpeedRefraction() {
- return speedRefraction;
- }
-
- /**
- * Set the movement speed of the refractiontexture
- *
- * @param speedRefraction
- * Speed of refractiontexture
- */
- public void setSpeedRefraction(final double speedRefraction) {
- this.speedRefraction = speedRefraction;
- }
-
- public double getWaterMaxAmplitude() {
- return waterMaxAmplitude;
- }
-
- /**
- * Maximum amplitude of the water, used for clipping correctly(projected water only)
- *
- * @param waterMaxAmplitude
- * Maximum amplitude
- */
- public void setWaterMaxAmplitude(final double waterMaxAmplitude) {
- this.waterMaxAmplitude = waterMaxAmplitude;
- }
-
- public double getClipBias() {
- return clipBias;
- }
-
- public void setClipBias(final double clipBias) {
- this.clipBias = clipBias;
- }
-
- public Plane getWaterPlane() {
- return waterPlane;
- }
-
- public void setWaterPlane(final Plane waterPlane) {
- this.waterPlane = waterPlane;
- }
-
- public Vector3 getTangent() {
- return tangent;
- }
-
- public void setTangent(final Vector3 tangent) {
- this.tangent = tangent;
- }
-
- public Vector3 getBinormal() {
- return binormal;
- }
-
- public void setBinormal(final Vector3 binormal) {
- this.binormal = binormal;
- }
-
- public Texture getTextureReflect() {
- return textureReflect;
- }
-
- public Texture getTextureRefract() {
- return textureRefract;
- }
-
- public Texture getTextureDepth() {
- return textureDepth;
- }
-
- /**
- * If true, fade to fogcolor. If false, fade to 100% reflective surface
- *
- * @param value
- */
- public void useFadeToFogColor(final boolean value) {
- useFadeToFogColor = value;
- }
-
- public boolean isUseFadeToFogColor() {
- return useFadeToFogColor;
- }
-
- public boolean isUseReflection() {
- return useReflection;
- }
-
- /**
- * Turn reflection on and off
- *
- * @param useReflection
- */
- public void setUseReflection(final boolean useReflection) {
- if (useReflection == this.useReflection) {
- return;
- }
- this.useReflection = useReflection;
- reloadShader();
- }
-
- public boolean isUseRefraction() {
- return useRefraction;
- }
-
- /**
- * Turn refraction on and off
- *
- * @param useRefraction
- */
- public void setUseRefraction(final boolean useRefraction) {
- if (useRefraction == this.useRefraction) {
- return;
- }
- this.useRefraction = useRefraction;
- reloadShader();
- }
-
- public int getRenderScale() {
- return renderScale;
- }
-
- public void setRenderScale(final int renderScale) {
- this.renderScale = renderScale;
- }
-
- public boolean isUseProjectedShader() {
- return useProjectedShader;
- }
-
- public void setUseProjectedShader(final boolean useProjectedShader) {
- if (useProjectedShader == this.useProjectedShader) {
- return;
- }
- this.useProjectedShader = useProjectedShader;
- reloadShader();
- }
-
- public double getReflectionThrottle() {
- return reflectionThrottle;
- }
-
- public void setReflectionThrottle(final double reflectionThrottle) {
- this.reflectionThrottle = reflectionThrottle;
- }
-
- public double getRefractionThrottle() {
- return refractionThrottle;
- }
-
- public void setRefractionThrottle(final double refractionThrottle) {
- this.refractionThrottle = refractionThrottle;
- }
-
- public TextureState getTextureState() {
- return textureState;
- }
-
- public void setTextureState(final TextureState textureState) {
- this.textureState = textureState;
- }
-
- public void updateCamera() {
- if (isSupported()) {
- tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
- cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
- }
- }
-
- public void setFallbackTexture(final Texture fallbackTexture) {
- this.fallbackTexture = fallbackTexture;
- }
-
- public Texture getFallbackTexture() {
- return fallbackTexture;
- }
-
- public void setNormalmapTexture(final Texture normalmapTexture) {
- this.normalmapTexture = normalmapTexture;
- }
-
- public Texture getNormalmapTexture() {
- return normalmapTexture;
- }
-
- public void setDudvTexture(final Texture dudvTexture) {
- this.dudvTexture = dudvTexture;
- }
-
- public Texture getDudvTexture() {
- return dudvTexture;
- }
-
- public void setFoamTexture(final Texture foamTexture) {
- this.foamTexture = foamTexture;
- }
-
- public Texture getFoamTexture() {
- return foamTexture;
- }
-
- /**
- * @return the normalMapTextureString
- */
- public String getNormalMapTextureString() {
- return normalMapTextureString;
- }
-
- /**
- * @param normalMapTextureString
- * the normalMapTextureString to set
- */
- public void setNormalMapTextureString(final String normalMapTextureString) {
- this.normalMapTextureString = normalMapTextureString;
- }
-
- /**
- * @return the dudvMapTextureString
- */
- public String getDudvMapTextureString() {
- return dudvMapTextureString;
- }
-
- /**
- * @param dudvMapTextureString
- * the dudvMapTextureString to set
- */
- public void setDudvMapTextureString(final String dudvMapTextureString) {
- this.dudvMapTextureString = dudvMapTextureString;
- }
-
- /**
- * @return the foamMapTextureString
- */
- public String getFoamMapTextureString() {
- return foamMapTextureString;
- }
-
- /**
- * @param foamMapTextureString
- * the foamMapTextureString to set
- */
- public void setFoamMapTextureString(final String foamMapTextureString) {
- this.foamMapTextureString = foamMapTextureString;
- }
-
- /**
- * @return the fallbackMapTextureString
- */
- public String getFallbackMapTextureString() {
- return fallbackMapTextureString;
- }
-
- /**
- * @param fallbackMapTextureString
- * the fallbackMapTextureString to set
- */
- public void setFallbackMapTextureString(final String fallbackMapTextureString) {
- this.fallbackMapTextureString = fallbackMapTextureString;
- }
-
- public boolean isDoBlurReflection() {
- return doBlurReflection;
- }
-
- public void setDoBlurReflection(final boolean doBlurReflection) {
- this.doBlurReflection = doBlurReflection;
- }
-
- public float getBlurSampleDistance() {
- return blurSampleDistance;
- }
-
- public void setBlurSampleDistance(final float blurSampleDistance) {
- this.blurSampleDistance = blurSampleDistance;
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.effect.water;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture2D;
+import com.ardor3d.image.TextureStoreFormat;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Matrix4;
+import com.ardor3d.math.Plane;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.Vector4;
+import com.ardor3d.math.type.ReadOnlyMatrix4;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Camera.ProjectionMode;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRenderer;
+import com.ardor3d.renderer.TextureRendererFactory;
+import com.ardor3d.renderer.queue.RenderBucketType;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.ClipState;
+import com.ardor3d.renderer.state.CullState;
+import com.ardor3d.renderer.state.FogState;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.hint.CullHint;
+import com.ardor3d.scenegraph.hint.LightCombineMode;
+import com.ardor3d.scenegraph.hint.TextureCombineMode;
+import com.ardor3d.scenegraph.shape.Quad;
+import com.ardor3d.util.TextureManager;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.google.common.collect.Lists;
+
+/**
+ * The WaterNode handles rendering of a water effect on all of it's children. What is reflected in the water is
+ * controlled through setReflectedScene/addReflectedScene. The skybox (if any) needs to be explicitly set through
+ * setSkybox since it needs to be relocated when rendering the reflection. The water is treated as a plane no matter
+ * what the geometry is, which is controlled through the water node plane equation settings.
+ */
+public class WaterNode extends Node {
+ private static final Logger logger = Logger.getLogger(WaterNode.class.getName());
+
+ protected Camera cam;
+ protected double tpf;
+ protected double reflectionThrottle = 0f, refractionThrottle = 0f;
+ protected double reflectionTime = 0, refractionTime = 0;
+ protected boolean useFadeToFogColor = false;
+
+ protected TextureRenderer tRenderer;
+ protected Texture2D textureReflect;
+ protected Texture2D textureReflectBlur;
+ protected Texture2D textureRefract;
+ protected Texture2D textureDepth;
+
+ protected ArrayList<Spatial> renderList = Lists.newArrayList();
+ protected ArrayList<Texture> texArray = Lists.newArrayList();
+ protected Node skyBox;
+
+ protected GLSLShaderObjectsState waterShader;
+ protected CullState cullBackFace;
+ protected TextureState textureState;
+ protected TextureState fallbackTextureState;
+
+ private Texture normalmapTexture;
+ private Texture dudvTexture;
+ private Texture foamTexture;
+ private Texture fallbackTexture;
+ private Matrix4 fallbackTextureStateMatrix;
+
+ protected BlendState as1;
+ protected FogState noFog;
+
+ protected Plane waterPlane;
+ protected Vector3 tangent;
+ protected Vector3 binormal;
+ protected Vector3 calcVect = new Vector3();
+ protected double clipBias;
+ protected ColorRGBA waterColorStart;
+ protected ColorRGBA waterColorEnd;
+ protected double heightFalloffStart;
+ protected double heightFalloffSpeed;
+ protected double waterMaxAmplitude;
+ protected double speedReflection;
+ protected double speedRefraction;
+
+ protected boolean aboveWater;
+ protected double normalTranslation = 0.0;
+ protected double refractionTranslation = 0.0;
+ protected boolean supported = true;
+ protected boolean useProjectedShader = false;
+ protected boolean useRefraction = false;
+ protected boolean useReflection = true;
+ protected int renderScale;
+
+ protected String simpleShaderStr = "com/ardor3d/extension/effect/water/flatwatershader";
+ protected String simpleShaderRefractionStr = "com/ardor3d/extension/effect/water/flatwatershader_refraction";
+ protected String projectedShaderStr = "com/ardor3d/extension/effect/water/projectedwatershader";
+ protected String projectedShaderRefractionStr = "com/ardor3d/extension/effect/water/projectedwatershader_refraction";
+ protected String currentShaderStr;
+
+ protected String normalMapTextureString = "";
+ protected String dudvMapTextureString = "";
+ protected String foamMapTextureString = "";
+ protected String fallbackMapTextureString = "";
+
+ private GLSLShaderObjectsState blurShaderVertical = null;
+ private float blurSampleDistance = 0.002f;
+ private Quad fullScreenQuad = null;
+ private boolean doBlurReflection = true;
+
+ private boolean initialized;
+
+ /**
+ * Resets water parameters to default values
+ *
+ */
+ public void resetParameters() {
+ waterPlane = new Plane(new Vector3(0.0, 1.0, 0.0), 0.0);
+ tangent = new Vector3(1.0, 0.0, 0.0);
+ binormal = new Vector3(0.0, 0.0, 1.0);
+
+ waterMaxAmplitude = 0.0;
+ clipBias = 1.0;
+ waterColorStart = new ColorRGBA(0.0f, 0.0f, 0.1f, 1.0f);
+ waterColorEnd = new ColorRGBA(0.0f, 0.3f, 0.1f, 1.0f);
+ heightFalloffStart = 400.0;
+ heightFalloffSpeed = 500.0;
+ speedReflection = 0.1;
+ speedRefraction = -0.05;
+ }
+
+ /**
+ * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
+ */
+ public void cleanup() {
+ if (isSupported() && tRenderer != null) {
+ tRenderer.cleanup();
+ }
+ }
+
+ public boolean isSupported() {
+ return supported;
+ }
+
+ /**
+ * Creates a new WaterRenderPass
+ *
+ * @param cam
+ * main rendercam to use for reflection settings etc
+ * @param renderScale
+ * how many times smaller the reflection/refraction textures should be compared to the main display
+ * @param useProjectedShader
+ * true - use the projected setup for variable height water meshes, false - use the flast shader setup
+ * @param useRefraction
+ * enable/disable rendering of refraction textures
+ */
+ public WaterNode(final Camera cam, final int renderScale, final boolean useProjectedShader,
+ final boolean useRefraction) {
+ this.cam = cam;
+ this.useProjectedShader = useProjectedShader;
+ this.useRefraction = useRefraction;
+ this.renderScale = renderScale;
+ resetParameters();
+
+ waterShader = new GLSLShaderObjectsState();
+ blurShaderVertical = new GLSLShaderObjectsState();
+
+ cullBackFace = new CullState();
+ cullBackFace.setEnabled(true);
+ cullBackFace.setCullFace(CullState.Face.None);
+ }
+
+ /**
+ * Initialize texture renderers. Load water textures. Create shaders.
+ *
+ * @param r
+ */
+ private void initialize(final Renderer r) {
+ if (cam == null || initialized) {
+ return;
+ }
+ initialized = true;
+
+ final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
+
+ if (useRefraction && useProjectedShader && caps.getNumberOfFragmentTextureUnits() < 6 || useRefraction
+ && caps.getNumberOfFragmentTextureUnits() < 5) {
+ useRefraction = false;
+ logger.info("Not enough textureunits, falling back to non refraction water");
+ }
+
+ if (!caps.isGLSLSupported()) {
+ supported = false;
+ }
+ if (!(caps.isPbufferSupported() || caps.isFBOSupported())) {
+ supported = false;
+ }
+
+ if (isSupported()) {
+ tRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer( //
+ cam.getWidth() / renderScale, // width
+ cam.getHeight() / renderScale, // height
+ 8, // Depth bits... TODO: Make configurable?
+ 0, // Samples... TODO: Make configurable?
+ r, caps);
+
+ // blurSampleDistance = 1f / ((float) cam.getHeight() / renderScale);
+
+ tRenderer.setMultipleTargets(true);
+ tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
+ tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
+ cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
+
+ textureState = new TextureState();
+ textureState.setEnabled(true);
+
+ setupTextures();
+
+ fullScreenQuad = new Quad("FullScreenQuad", cam.getWidth() / 4, cam.getHeight() / 4);
+ fullScreenQuad.setTranslation(cam.getWidth() / 2, cam.getHeight() / 2, 0);
+ fullScreenQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho);
+ fullScreenQuad.getSceneHints().setCullHint(CullHint.Never);
+ fullScreenQuad.getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
+ fullScreenQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off);
+ final TextureState ts = new TextureState();
+ ts.setTexture(textureReflect);
+ fullScreenQuad.setRenderState(ts);
+ fullScreenQuad.setRenderState(blurShaderVertical);
+ fullScreenQuad.updateWorldRenderStates(false);
+ }
+
+ if (!isSupported()) {
+ createFallbackData();
+ } else {
+ noFog = new FogState();
+ noFog.setEnabled(false);
+ }
+
+ getSceneHints().setCullHint(CullHint.Never);
+
+ setWaterEffectOnSpatial(this);
+ }
+
+ /**
+ * Load water textures.
+ */
+ protected void setupTextures() {
+ textureReflect = new Texture2D();
+ textureReflect.setWrap(Texture.WrapMode.EdgeClamp);
+ textureReflect.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ Matrix4 matrix = new Matrix4();
+ matrix.setM00(-1.0);
+ matrix.setM30(1.0);
+ textureReflect.setTextureMatrix(matrix);
+ tRenderer.setupTexture(textureReflect);
+
+ normalmapTexture = TextureManager.load(normalMapTextureString, Texture.MinificationFilter.Trilinear,
+ TextureStoreFormat.GuessCompressedFormat, true);
+ textureState.setTexture(normalmapTexture, 0);
+ normalmapTexture.setWrap(Texture.WrapMode.Repeat);
+
+ textureReflectBlur = new Texture2D();
+ textureReflectBlur.setWrap(Texture.WrapMode.EdgeClamp);
+ textureReflectBlur.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ textureReflectBlur.setTextureMatrix(matrix);
+ tRenderer.setupTexture(textureReflectBlur);
+
+ textureState.setTexture(textureReflectBlur, 1);
+
+ dudvTexture = TextureManager.load(dudvMapTextureString, Texture.MinificationFilter.Trilinear,
+ TextureStoreFormat.GuessNoCompressedFormat, true);
+ matrix = new Matrix4();
+ matrix.setM00(0.8);
+ matrix.setM11(0.8);
+ dudvTexture.setTextureMatrix(matrix);
+ textureState.setTexture(dudvTexture, 2);
+ dudvTexture.setWrap(Texture.WrapMode.Repeat);
+
+ if (useRefraction) {
+ textureRefract = new Texture2D();
+ textureRefract.setWrap(Texture.WrapMode.EdgeClamp);
+ textureRefract.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ tRenderer.setupTexture(textureRefract);
+
+ textureDepth = new Texture2D();
+ textureDepth.setWrap(Texture.WrapMode.EdgeClamp);
+ textureDepth.setMagnificationFilter(Texture.MagnificationFilter.NearestNeighbor);
+ textureDepth.setTextureStoreFormat(TextureStoreFormat.Depth24);
+ tRenderer.setupTexture(textureDepth);
+
+ textureState.setTexture(textureRefract, 3);
+ textureState.setTexture(textureDepth, 4);
+ }
+
+ if (useProjectedShader) {
+ foamTexture = TextureManager.load(foamMapTextureString, Texture.MinificationFilter.Trilinear,
+ TextureStoreFormat.GuessCompressedFormat, true);
+ if (useRefraction) {
+ textureState.setTexture(foamTexture, 5);
+ } else {
+ textureState.setTexture(foamTexture, 3);
+ }
+ foamTexture.setWrap(Texture.WrapMode.Repeat);
+ }
+
+ reloadShader();
+ }
+
+ /**
+ * Create setup to use as fallback if fancy water is not supported.
+ */
+ private void createFallbackData() {
+ fallbackTextureState = new TextureState();
+ fallbackTextureState.setEnabled(true);
+
+ fallbackTexture = TextureManager.load(fallbackMapTextureString, Texture.MinificationFilter.Trilinear,
+ TextureStoreFormat.GuessCompressedFormat, true);
+ fallbackTextureState.setTexture(fallbackTexture, 0);
+ fallbackTexture.setWrap(Texture.WrapMode.Repeat);
+
+ fallbackTextureStateMatrix = new Matrix4();
+
+ as1 = new BlendState();
+ as1.setBlendEnabled(true);
+ as1.setTestEnabled(true);
+ as1.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
+ as1.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
+ as1.setEnabled(true);
+ }
+
+ public void update(final double tpf) {
+ this.tpf = tpf;
+ }
+
+ @Override
+ public void draw(final Renderer r) {
+ initialize(r);
+
+ updateTranslations();
+
+ final double camWaterDist = waterPlane.pseudoDistance(cam.getLocation());
+ aboveWater = camWaterDist >= 0;
+
+ if (isSupported()) {
+ waterShader.setUniform("tangent", tangent);
+ waterShader.setUniform("binormal", binormal);
+ waterShader.setUniform("useFadeToFogColor", useFadeToFogColor);
+ waterShader.setUniform("waterColor", waterColorStart);
+ waterShader.setUniform("waterColorEnd", waterColorEnd);
+ waterShader.setUniform("normalTranslation", (float) normalTranslation);
+ waterShader.setUniform("refractionTranslation", (float) refractionTranslation);
+ waterShader.setUniform("abovewater", aboveWater);
+ if (useProjectedShader) {
+ waterShader.setUniform("cameraPos", cam.getLocation());
+ waterShader.setUniform("waterHeight", (float) waterPlane.getConstant());
+ waterShader.setUniform("amplitude", (float) waterMaxAmplitude);
+ waterShader.setUniform("heightFalloffStart", (float) heightFalloffStart);
+ waterShader.setUniform("heightFalloffSpeed", (float) heightFalloffSpeed);
+ }
+
+ final double heightTotal = clipBias + waterMaxAmplitude - waterPlane.getConstant();
+ final Vector4 clipPlane = Vector4.fetchTempInstance();
+
+ if (useReflection) {
+ clipPlane.set(waterPlane.getNormal().getX(), waterPlane.getNormal().getY(), waterPlane.getNormal()
+ .getZ(), heightTotal);
+ renderReflection(clipPlane);
+ }
+
+ if (useRefraction && aboveWater) {
+ clipPlane.set(-waterPlane.getNormal().getX(), -waterPlane.getNormal().getY(), -waterPlane.getNormal()
+ .getZ(), -waterPlane.getConstant());
+ renderRefraction(clipPlane);
+ }
+ }
+
+ if (fallbackTextureState != null) {
+ fallbackTextureStateMatrix.setM31(normalTranslation);
+ fallbackTexture.setTextureMatrix(fallbackTextureStateMatrix);
+ }
+
+ super.draw(r);
+ }
+
+ protected void updateTranslations() {
+ normalTranslation += speedReflection * tpf;
+ refractionTranslation += speedRefraction * tpf;
+ }
+
+ public void reloadShader() {
+ if (useProjectedShader) {
+ if (useRefraction) {
+ currentShaderStr = projectedShaderRefractionStr;
+ } else {
+ currentShaderStr = projectedShaderStr;
+ }
+ } else {
+ if (useRefraction) {
+ currentShaderStr = simpleShaderRefractionStr;
+ } else {
+ currentShaderStr = simpleShaderStr;
+ }
+ }
+
+ try {
+ logger.info("loading " + currentShaderStr);
+ waterShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
+ currentShaderStr + ".vert"));
+ waterShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
+ currentShaderStr + ".frag"));
+ } catch (final IOException e) {
+ logger.log(Level.WARNING, "Error loading shader", e);
+ return;
+ }
+
+ waterShader.setUniform("normalMap", 0);
+ waterShader.setUniform("reflection", 1);
+ waterShader.setUniform("dudvMap", 2);
+ if (useRefraction) {
+ waterShader.setUniform("refraction", 3);
+ waterShader.setUniform("depthMap", 4);
+ }
+ if (useProjectedShader) {
+ if (useRefraction) {
+ waterShader.setUniform("foamMap", 5);
+ } else {
+ waterShader.setUniform("foamMap", 3);
+ }
+ }
+
+ waterShader._needSendShader = true;
+
+ try {
+ blurShaderVertical.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
+ "com/ardor3d/extension/effect/bloom/bloom_blur.vert"));
+ blurShaderVertical.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(WaterNode.class,
+ "com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ blurShaderVertical.setUniform("RT", 0);
+ blurShaderVertical.setUniform("sampleDist", blurSampleDistance);
+ blurShaderVertical._needSendShader = true;
+
+ logger.info("Shader reloaded...");
+ }
+
+ /**
+ * Sets a spatial up for being rendered with the watereffect
+ *
+ * @param spatial
+ * Spatial to use as base for the watereffect
+ */
+ public void setWaterEffectOnSpatial(final Spatial spatial) {
+ spatial.setRenderState(cullBackFace);
+ if (isSupported()) {
+ // spatial.setRenderBucketType(RenderBucketType.Skip);
+ spatial.setRenderState(waterShader);
+ spatial.setRenderState(textureState);
+ } else {
+ spatial.getSceneHints().setRenderBucketType(RenderBucketType.Transparent);
+ spatial.getSceneHints().setLightCombineMode(LightCombineMode.Off);
+ spatial.setRenderState(fallbackTextureState);
+ spatial.setRenderState(as1);
+ }
+ }
+
+ // temporary vectors for mem opt.
+ private final Vector3 tmpLocation = new Vector3();
+ private final Vector3 camReflectPos = new Vector3();
+ private final Vector3 camReflectDir = new Vector3();
+ private final Vector3 camReflectUp = new Vector3();
+ private final Vector3 camReflectLeft = new Vector3();
+ private final Vector3 camLocation = new Vector3();
+
+ /**
+ * Render water reflection RTT
+ */
+ private void renderReflection(final Vector4 clipPlane) {
+ if (renderList.isEmpty()) {
+ return;
+ }
+
+ reflectionTime += tpf;
+ if (reflectionTime < reflectionThrottle) {
+ return;
+ }
+ reflectionTime = 0;
+
+ if (aboveWater) {
+ camLocation.set(cam.getLocation());
+
+ double planeDistance = waterPlane.pseudoDistance(camLocation);
+ calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
+ camReflectPos.set(camLocation.subtractLocal(calcVect));
+
+ camLocation.set(cam.getLocation()).addLocal(cam.getDirection());
+ planeDistance = waterPlane.pseudoDistance(camLocation);
+ calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
+ camReflectDir.set(camLocation.subtractLocal(calcVect)).subtractLocal(camReflectPos).normalizeLocal();
+
+ camLocation.set(cam.getLocation()).addLocal(cam.getUp());
+ planeDistance = waterPlane.pseudoDistance(camLocation);
+ calcVect.set(waterPlane.getNormal()).multiplyLocal(planeDistance * 2.0f);
+ camReflectUp.set(camLocation.subtractLocal(calcVect)).subtractLocal(camReflectPos).normalizeLocal();
+
+ camReflectLeft.set(camReflectUp).crossLocal(camReflectDir).normalizeLocal();
+
+ tRenderer.getCamera().setLocation(camReflectPos);
+ tRenderer.getCamera().setDirection(camReflectDir);
+ tRenderer.getCamera().setUp(camReflectUp);
+ tRenderer.getCamera().setLeft(camReflectLeft);
+ } else {
+ tRenderer.getCamera().setLocation(cam.getLocation());
+ tRenderer.getCamera().setDirection(cam.getDirection());
+ tRenderer.getCamera().setUp(cam.getUp());
+ tRenderer.getCamera().setLeft(cam.getLeft());
+ }
+
+ if (skyBox != null) {
+ tmpLocation.set(skyBox.getTranslation());
+ skyBox.setTranslation(tRenderer.getCamera().getLocation());
+ skyBox.updateGeometricState(0.0f);
+ skyBox.getSceneHints().setCullHint(CullHint.Never);
+ }
+
+ texArray.clear();
+ if (doBlurReflection) {
+ texArray.add(textureReflect);
+ } else {
+ texArray.add(textureReflectBlur);
+ }
+
+ tRenderer.getCamera().setProjectionMode(ProjectionMode.Custom);
+ tRenderer.getCamera().setProjectionMatrix(cam.getProjectionMatrix());
+ tRenderer.render(skyBox, texArray, Renderer.BUFFER_COLOR_AND_DEPTH);
+
+ if (skyBox != null) {
+ skyBox.getSceneHints().setCullHint(CullHint.Always);
+ }
+
+ modifyProjectionMatrix(clipPlane);
+
+ tRenderer.render(renderList, texArray, Renderer.BUFFER_NONE);
+
+ if (doBlurReflection) {
+ blurReflectionTexture();
+ }
+
+ if (skyBox != null) {
+ skyBox.setTranslation(tmpLocation);
+ skyBox.updateGeometricState(0.0f);
+ skyBox.getSceneHints().setCullHint(CullHint.Never);
+ }
+ }
+
+ private void blurReflectionTexture() {
+ tRenderer.render(fullScreenQuad, textureReflectBlur, Renderer.BUFFER_NONE);
+ }
+
+ /**
+ * Render water refraction RTT
+ */
+ private void renderRefraction(final Vector4 clipPlane) {
+ if (renderList.isEmpty()) {
+ return;
+ }
+
+ refractionTime += tpf;
+ if (refractionTime < refractionThrottle) {
+ return;
+ }
+ refractionTime = 0;
+
+ // tRenderer.getCamera().set(cam);
+ tRenderer.getCamera().setLocation(cam.getLocation());
+ tRenderer.getCamera().setDirection(cam.getDirection());
+ tRenderer.getCamera().setUp(cam.getUp());
+ tRenderer.getCamera().setLeft(cam.getLeft());
+
+ CullHint cullMode = CullHint.Dynamic;
+ if (skyBox != null) {
+ cullMode = skyBox.getSceneHints().getCullHint();
+ skyBox.getSceneHints().setCullHint(CullHint.Always);
+ }
+
+ tRenderer.getCamera().setProjectionMatrix(cam.getProjectionMatrix());
+
+ texArray.clear();
+ texArray.add(textureRefract);
+ texArray.add(textureDepth);
+
+ tRenderer.getCamera().update();
+ tRenderer.getCamera().getModelViewMatrix();
+ tRenderer.getCamera().getProjectionMatrix();
+
+ tRenderer.render(renderList, texArray, Renderer.BUFFER_COLOR_AND_DEPTH);
+
+ if (skyBox != null) {
+ skyBox.getSceneHints().setCullHint(cullMode);
+ }
+ }
+
+ private double sign(final double a) {
+ if (a > 0.0) {
+ return 1.0;
+ }
+ if (a < 0.0) {
+ return -1.0;
+ }
+ return 0.0;
+ }
+
+ private double projectionMatrix[] = new double[16];
+ private final Vector4 cornerPoint = new Vector4();
+ private final Matrix4 tmpMatrix = new Matrix4();
+
+ private void modifyProjectionMatrix(final Vector4 clipPlane) {
+ // Get the current projection matrix
+ projectionMatrix = cam.getProjectionMatrix().toArray(projectionMatrix);
+
+ // Get the inverse transpose of the current modelview matrix
+ final ReadOnlyMatrix4 modelViewMatrixInvTrans = tRenderer.getCamera().getModelViewMatrix().invert(tmpMatrix)
+ .transposeLocal();
+ modelViewMatrixInvTrans.applyPre(clipPlane, clipPlane);
+
+ // Calculate the clip-space corner point opposite the clipping plane
+ // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
+ // transform it into camera space by multiplying it
+ // by the inverse of the projection matrix
+ cornerPoint.setX((sign(clipPlane.getX()) + projectionMatrix[8]) / projectionMatrix[0]);
+ cornerPoint.setY((sign(clipPlane.getY()) + projectionMatrix[9]) / projectionMatrix[5]);
+ cornerPoint.setZ(-1.0);
+ cornerPoint.setW((1.0 + projectionMatrix[10]) / projectionMatrix[14]);
+
+ // Calculate the scaled plane vector
+ final Vector4 scaledPlaneVector = clipPlane.multiply((2.0 / clipPlane.dot(cornerPoint)), cornerPoint);
+
+ // Replace the third row of the projection matrix
+ projectionMatrix[2] = scaledPlaneVector.getX();
+ projectionMatrix[6] = scaledPlaneVector.getY();
+ projectionMatrix[10] = scaledPlaneVector.getZ() + 1.0;
+ projectionMatrix[14] = scaledPlaneVector.getW();
+
+ // Load it back into OpenGL
+ final Matrix4 newProjectionMatrix = tmpMatrix.fromArray(projectionMatrix);
+ tRenderer.getCamera().setProjectionMatrix(newProjectionMatrix);
+ }
+
+ public void removeReflectedScene(final Spatial renderNode) {
+ if (logger.isLoggable(Level.INFO)) {
+ logger.info("Removed reflected scene: " + renderList.remove(renderNode));
+ }
+ }
+
+ public void clearReflectedScene() {
+ renderList.clear();
+ }
+
+ /**
+ * Adds a spatial to the list of spatials used as reflection in the water
+ *
+ * @param renderNode
+ * Spatial to add to the list of objects used as reflection in the water
+ */
+ public void addReflectedScene(final Spatial renderNode) {
+ if (renderNode == null) {
+ return;
+ }
+
+ if (!renderList.contains(renderNode)) {
+ renderList.add(renderNode);
+ }
+ }
+
+ /**
+ * Sets up a node to be transformed and clipped for skybox usage
+ *
+ * @param skyBox
+ * Handle to a node to use as skybox
+ */
+ public void setSkybox(final Node skyBox) {
+ if (skyBox != null) {
+ final ClipState skyboxClipState = new ClipState();
+ skyboxClipState.setEnabled(false);
+ skyBox.setRenderState(skyboxClipState);
+ }
+
+ this.skyBox = skyBox;
+ }
+
+ public Camera getCam() {
+ return cam;
+ }
+
+ public void setCam(final Camera cam) {
+ this.cam = cam;
+ }
+
+ public ColorRGBA getWaterColorStart() {
+ return waterColorStart;
+ }
+
+ /**
+ * Color to use when the incident angle to the surface is low
+ */
+ public void setWaterColorStart(final ColorRGBA waterColorStart) {
+ this.waterColorStart = waterColorStart;
+ }
+
+ public ColorRGBA getWaterColorEnd() {
+ return waterColorEnd;
+ }
+
+ /**
+ * Color to use when the incident angle to the surface is high
+ */
+ public void setWaterColorEnd(final ColorRGBA waterColorEnd) {
+ this.waterColorEnd = waterColorEnd;
+ }
+
+ public double getHeightFalloffStart() {
+ return heightFalloffStart;
+ }
+
+ /**
+ * Set at what distance the waveheights should start to fade out(for projected water only)
+ *
+ * @param heightFalloffStart
+ */
+ public void setHeightFalloffStart(final double heightFalloffStart) {
+ this.heightFalloffStart = heightFalloffStart;
+ }
+
+ public double getHeightFalloffSpeed() {
+ return heightFalloffSpeed;
+ }
+
+ /**
+ * Set the fadeout length of the waveheights, when over falloff start(for projected water only)
+ *
+ * @param heightFalloffStart
+ */
+ public void setHeightFalloffSpeed(final double heightFalloffSpeed) {
+ this.heightFalloffSpeed = heightFalloffSpeed;
+ }
+
+ public double getWaterHeight() {
+ return waterPlane.getConstant();
+ }
+
+ /**
+ * Set base height of the waterplane(Used for reflecting the camera for rendering reflection)
+ *
+ * @param waterHeight
+ * Waterplane height
+ */
+ public void setWaterHeight(final double waterHeight) {
+ waterPlane.setConstant(waterHeight);
+ }
+
+ public ReadOnlyVector3 getNormal() {
+ return waterPlane.getNormal();
+ }
+
+ /**
+ * Set the normal of the waterplane(Used for reflecting the camera for rendering reflection)
+ *
+ * @param normal
+ * Waterplane normal
+ */
+ public void setNormal(final Vector3 normal) {
+ waterPlane.setNormal(normal);
+ }
+
+ public double getSpeedReflection() {
+ return speedReflection;
+ }
+
+ /**
+ * Set the movement speed of the reflectiontexture
+ *
+ * @param speedReflection
+ * Speed of reflectiontexture
+ */
+ public void setSpeedReflection(final double speedReflection) {
+ this.speedReflection = speedReflection;
+ }
+
+ public double getSpeedRefraction() {
+ return speedRefraction;
+ }
+
+ /**
+ * Set the movement speed of the refractiontexture
+ *
+ * @param speedRefraction
+ * Speed of refractiontexture
+ */
+ public void setSpeedRefraction(final double speedRefraction) {
+ this.speedRefraction = speedRefraction;
+ }
+
+ public double getWaterMaxAmplitude() {
+ return waterMaxAmplitude;
+ }
+
+ /**
+ * Maximum amplitude of the water, used for clipping correctly(projected water only)
+ *
+ * @param waterMaxAmplitude
+ * Maximum amplitude
+ */
+ public void setWaterMaxAmplitude(final double waterMaxAmplitude) {
+ this.waterMaxAmplitude = waterMaxAmplitude;
+ }
+
+ public double getClipBias() {
+ return clipBias;
+ }
+
+ public void setClipBias(final double clipBias) {
+ this.clipBias = clipBias;
+ }
+
+ public Plane getWaterPlane() {
+ return waterPlane;
+ }
+
+ public void setWaterPlane(final Plane waterPlane) {
+ this.waterPlane = waterPlane;
+ }
+
+ public Vector3 getTangent() {
+ return tangent;
+ }
+
+ public void setTangent(final Vector3 tangent) {
+ this.tangent = tangent;
+ }
+
+ public Vector3 getBinormal() {
+ return binormal;
+ }
+
+ public void setBinormal(final Vector3 binormal) {
+ this.binormal = binormal;
+ }
+
+ public Texture getTextureReflect() {
+ return textureReflect;
+ }
+
+ public Texture getTextureRefract() {
+ return textureRefract;
+ }
+
+ public Texture getTextureDepth() {
+ return textureDepth;
+ }
+
+ /**
+ * If true, fade to fogcolor. If false, fade to 100% reflective surface
+ *
+ * @param value
+ */
+ public void useFadeToFogColor(final boolean value) {
+ useFadeToFogColor = value;
+ }
+
+ public boolean isUseFadeToFogColor() {
+ return useFadeToFogColor;
+ }
+
+ public boolean isUseReflection() {
+ return useReflection;
+ }
+
+ /**
+ * Turn reflection on and off
+ *
+ * @param useReflection
+ */
+ public void setUseReflection(final boolean useReflection) {
+ if (useReflection == this.useReflection) {
+ return;
+ }
+ this.useReflection = useReflection;
+ reloadShader();
+ }
+
+ public boolean isUseRefraction() {
+ return useRefraction;
+ }
+
+ /**
+ * Turn refraction on and off
+ *
+ * @param useRefraction
+ */
+ public void setUseRefraction(final boolean useRefraction) {
+ if (useRefraction == this.useRefraction) {
+ return;
+ }
+ this.useRefraction = useRefraction;
+ reloadShader();
+ }
+
+ public int getRenderScale() {
+ return renderScale;
+ }
+
+ public void setRenderScale(final int renderScale) {
+ this.renderScale = renderScale;
+ }
+
+ public boolean isUseProjectedShader() {
+ return useProjectedShader;
+ }
+
+ public void setUseProjectedShader(final boolean useProjectedShader) {
+ if (useProjectedShader == this.useProjectedShader) {
+ return;
+ }
+ this.useProjectedShader = useProjectedShader;
+ reloadShader();
+ }
+
+ public double getReflectionThrottle() {
+ return reflectionThrottle;
+ }
+
+ public void setReflectionThrottle(final double reflectionThrottle) {
+ this.reflectionThrottle = reflectionThrottle;
+ }
+
+ public double getRefractionThrottle() {
+ return refractionThrottle;
+ }
+
+ public void setRefractionThrottle(final double refractionThrottle) {
+ this.refractionThrottle = refractionThrottle;
+ }
+
+ public TextureState getTextureState() {
+ return textureState;
+ }
+
+ public void setTextureState(final TextureState textureState) {
+ this.textureState = textureState;
+ }
+
+ public void updateCamera() {
+ if (isSupported()) {
+ tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
+ cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());
+ }
+ }
+
+ public void setFallbackTexture(final Texture fallbackTexture) {
+ this.fallbackTexture = fallbackTexture;
+ }
+
+ public Texture getFallbackTexture() {
+ return fallbackTexture;
+ }
+
+ public void setNormalmapTexture(final Texture normalmapTexture) {
+ this.normalmapTexture = normalmapTexture;
+ }
+
+ public Texture getNormalmapTexture() {
+ return normalmapTexture;
+ }
+
+ public void setDudvTexture(final Texture dudvTexture) {
+ this.dudvTexture = dudvTexture;
+ }
+
+ public Texture getDudvTexture() {
+ return dudvTexture;
+ }
+
+ public void setFoamTexture(final Texture foamTexture) {
+ this.foamTexture = foamTexture;
+ }
+
+ public Texture getFoamTexture() {
+ return foamTexture;
+ }
+
+ /**
+ * @return the normalMapTextureString
+ */
+ public String getNormalMapTextureString() {
+ return normalMapTextureString;
+ }
+
+ /**
+ * @param normalMapTextureString
+ * the normalMapTextureString to set
+ */
+ public void setNormalMapTextureString(final String normalMapTextureString) {
+ this.normalMapTextureString = normalMapTextureString;
+ }
+
+ /**
+ * @return the dudvMapTextureString
+ */
+ public String getDudvMapTextureString() {
+ return dudvMapTextureString;
+ }
+
+ /**
+ * @param dudvMapTextureString
+ * the dudvMapTextureString to set
+ */
+ public void setDudvMapTextureString(final String dudvMapTextureString) {
+ this.dudvMapTextureString = dudvMapTextureString;
+ }
+
+ /**
+ * @return the foamMapTextureString
+ */
+ public String getFoamMapTextureString() {
+ return foamMapTextureString;
+ }
+
+ /**
+ * @param foamMapTextureString
+ * the foamMapTextureString to set
+ */
+ public void setFoamMapTextureString(final String foamMapTextureString) {
+ this.foamMapTextureString = foamMapTextureString;
+ }
+
+ /**
+ * @return the fallbackMapTextureString
+ */
+ public String getFallbackMapTextureString() {
+ return fallbackMapTextureString;
+ }
+
+ /**
+ * @param fallbackMapTextureString
+ * the fallbackMapTextureString to set
+ */
+ public void setFallbackMapTextureString(final String fallbackMapTextureString) {
+ this.fallbackMapTextureString = fallbackMapTextureString;
+ }
+
+ public boolean isDoBlurReflection() {
+ return doBlurReflection;
+ }
+
+ public void setDoBlurReflection(final boolean doBlurReflection) {
+ this.doBlurReflection = doBlurReflection;
+ }
+
+ public float getBlurSampleDistance() {
+ return blurSampleDistance;
+ }
+
+ public void setBlurSampleDistance(final float blurSampleDistance) {
+ this.blurSampleDistance = blurSampleDistance;
+ }
+}
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ParallelSplitShadowMapPass.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ParallelSplitShadowMapPass.java
index cf07f8a..96f452e 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ParallelSplitShadowMapPass.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ParallelSplitShadowMapPass.java
@@ -1,1365 +1,1365 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.shadow.map;
-
-import java.io.IOException;
-import java.nio.FloatBuffer;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.ardor3d.bounding.BoundingBox;
-import com.ardor3d.bounding.BoundingSphere;
-import com.ardor3d.bounding.BoundingVolume;
-import com.ardor3d.bounding.OrientedBoundingBox;
-import com.ardor3d.image.Texture;
-import com.ardor3d.image.Texture.DepthTextureCompareFunc;
-import com.ardor3d.image.Texture.DepthTextureCompareMode;
-import com.ardor3d.image.Texture.DepthTextureMode;
-import com.ardor3d.image.Texture2D;
-import com.ardor3d.image.TextureStoreFormat;
-import com.ardor3d.light.DirectionalLight;
-import com.ardor3d.light.Light;
-import com.ardor3d.light.PointLight;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.Matrix4;
-import com.ardor3d.math.Quaternion;
-import com.ardor3d.math.Vector3;
-import com.ardor3d.math.Vector4;
-import com.ardor3d.math.type.ReadOnlyColorRGBA;
-import com.ardor3d.math.type.ReadOnlyMatrix4;
-import com.ardor3d.math.type.ReadOnlyVector3;
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.Camera.ProjectionMode;
-import com.ardor3d.renderer.ContextCapabilities;
-import com.ardor3d.renderer.ContextManager;
-import com.ardor3d.renderer.IndexMode;
-import com.ardor3d.renderer.RenderLogic;
-import com.ardor3d.renderer.Renderer;
-import com.ardor3d.renderer.TextureRenderer;
-import com.ardor3d.renderer.TextureRendererFactory;
-import com.ardor3d.renderer.pass.Pass;
-import com.ardor3d.renderer.queue.RenderBucketType;
-import com.ardor3d.renderer.state.BlendState;
-import com.ardor3d.renderer.state.ClipState;
-import com.ardor3d.renderer.state.ColorMaskState;
-import com.ardor3d.renderer.state.CullState;
-import com.ardor3d.renderer.state.CullState.Face;
-import com.ardor3d.renderer.state.GLSLShaderObjectsState;
-import com.ardor3d.renderer.state.LightState;
-import com.ardor3d.renderer.state.OffsetState;
-import com.ardor3d.renderer.state.OffsetState.OffsetType;
-import com.ardor3d.renderer.state.RenderState;
-import com.ardor3d.renderer.state.RenderState.StateType;
-import com.ardor3d.renderer.state.ShadingState;
-import com.ardor3d.renderer.state.ShadingState.ShadingMode;
-import com.ardor3d.renderer.state.TextureState;
-import com.ardor3d.renderer.state.WireframeState;
-import com.ardor3d.renderer.state.ZBufferState;
-import com.ardor3d.scenegraph.Line;
-import com.ardor3d.scenegraph.Mesh;
-import com.ardor3d.scenegraph.Renderable;
-import com.ardor3d.scenegraph.Spatial;
-import com.ardor3d.scenegraph.hint.LightCombineMode;
-import com.ardor3d.scenegraph.shape.Sphere;
-import com.ardor3d.util.geom.BufferUtils;
-import com.ardor3d.util.resource.ResourceLocatorTool;
-import com.google.common.collect.Lists;
-
-/**
- * A pass providing a parallel split shadow mapping (PSSM) layer across the top of an existing scene.
- */
-public class ParallelSplitShadowMapPass extends Pass {
-
- /** The Constant logger. */
- private static final Logger logger = Logger.getLogger(ParallelSplitShadowMapPass.class.getName());
-
- /** The Constant serialVersionUID. */
- private static final long serialVersionUID = 1L;
-
- /** Bias matrix from [-1, 1] to [0, 1]. */
- public static final ReadOnlyMatrix4 SCALE_BIAS_MATRIX = new Matrix4( //
- 0.5, 0.0, 0.0, 0.0, //
- 0.0, 0.5, 0.0, 0.0, //
- 0.0, 0.0, 0.5, 0.0, //
- 0.5, 0.5, 0.5, 1.0);//
-
- /** The renderer used to produce the shadow map. */
- private TextureRenderer _shadowMapRenderer;
-
- /** The textures storing the shadow maps. */
- private Texture2D _shadowMapTexture[];
-
- /** The list of occluding nodes. */
- private final List<Spatial> _occluderNodes = Lists.newArrayList();
-
- /** Extra bounds receivers, when rendering shadows other ways than through overlay */
- private final List<Spatial> _boundsReceiver = Lists.newArrayList();
-
- // Various optimizations for rendering shadow maps...
- /** Culling front faces when rendering shadow maps. */
- private final CullState _cullFrontFace;
-
- /** Turn off textures when rendering shadow maps. */
- private final TextureState _noTexture;
-
- /** Turn off lighting when rendering shadow maps. */
- private final LightState _noLights;
-
- /** set flat shading when rendering shadow maps. */
- private final ShadingState _flat;
-
- // Important pieces for rendering shadow maps
- /** Turn off colors when rendering shadow maps. */
- private final ColorMaskState _colorDisabled;
-
- /** The state applying the depth offset for the shadow. */
- private final OffsetState _shadowOffsetState;
-
- /**
- * The blending to both discard the fragments that have been determined to be free of shadows and to blend into the
- * background scene.
- */
- private final BlendState _discardShadowFragments;
-
- /** The state applying the shadow map. */
- private final TextureState _shadowTextureState;
-
- /** Don't perform any plane clipping when rendering the shadowed scene. */
- private final ClipState _noClip;
-
- /** True once the pass has been initialized. */
- protected boolean _initialised = false;
-
- /** Flag for updating texture splits when number of splits changed. */
- protected boolean _reinitSplitsDirty = true;
-
- /** Flag for updating texture renderer when texture size changed. */
- protected boolean _reinitTextureSizeDirty = true;
-
- /** The size of the shadow map texture. */
- private int _shadowMapSize;
-
- /** Minimum number of splits allowed */
- public static final int _MIN_SPLITS = 1;
-
- /** Maximum number of splits allowed */
- public static final int _MAX_SPLITS = 4;
-
- /** Number of splits used. */
- protected int _numOfSplits;
-
- /** Minimum light z distance from target. */
- private double _minimumLightDistance = 1000.0;
-
- /** Shadow color and transparency. */
- private final ColorRGBA _shadowColor = new ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f);
-
- /** Light -> Camera transformation matrix. */
- private final Matrix4 _shadowMatrix = new Matrix4();
-
- /** Bounding of scene for packing frustum. */
- protected BoundingBox _receiverBounds = new BoundingBox();
-
- /** Indicates if we have any valid reciever bounds to use for frustum packing */
- protected boolean hasValidBounds = false;
-
- /** Special camera with functionality for packing frustum etc. */
- protected PSSMCamera _pssmCam;
-
- /** Light that casts the shadow. */
- protected Light _light;
-
- /** Shader for rendering pssm shadows in one pass. */
- private GLSLShaderObjectsState _pssmShader;
-
- /** Might need to keep main shader when doing both multitexturing shadows and overlays */
- private GLSLShaderObjectsState _mainShader;
-
- /** Shader for debugging pssm shadows drawing splits in different colors. */
- private GLSLShaderObjectsState _pssmDebugShader;
-
- /** Debug for stopping camera update. */
- private boolean _updateMainCamera = true;
-
- /** Debug drawing frustums. */
- private boolean _drawDebug = false;
-
- /** Debug drawing shader. */
- private boolean _drawShaderDebug = false;
-
- /** Do we want to keep the main shader to do both multitexturing shadows and overlays? */
- private boolean _keepMainShader = false;
-
- /**
- * True if we want to factor in texturing to shadows; useful for casting shadows against alpha-tested textures.
- * Default is false.
- */
- private boolean _useSceneTexturing = false;
-
- /**
- * True if we want to use the culling set on the objects instead of always culling front face (which is done for
- * shadow precision). Default is false.
- */
- private boolean _useObjectCullFace = false;
-
- /**
- * When true (the default) the generated shadow map textures are drawn over the scene in a separate blend pass. If
- * false, the shadows are generated, but not applied.
- */
- private boolean _renderShadowedScene = true;
-
- /** Store format to use for the shadow textures. */
- protected TextureStoreFormat _shadowTextureStoreFormat = TextureStoreFormat.Depth16;
-
- /** Shadow filter techniques */
- public enum Filter {
- None, Pcf
- }
-
- private Filter filter = Filter.None;
-
- private ShadowRenderCallback shadowRenderCallback;
-
- /**
- * Create a pssm shadow map pass casting shadows from a light with the direction given.
- *
- * @param shadowMapSize
- * The size of the shadow map texture
- * @param numOfSplits
- * the num of splits
- */
- public ParallelSplitShadowMapPass(final Light light, final int shadowMapSize, final int numOfSplits) {
- _light = light;
- _shadowMapSize = shadowMapSize;
- setNumOfSplits(numOfSplits);
- _pssmCam = new PSSMCamera();
-
- _noClip = new ClipState();
- _noClip.setEnabled(false);
- _noTexture = new TextureState();
- _noTexture.setEnabled(false);
- _colorDisabled = new ColorMaskState();
- _colorDisabled.setAll(false);
- _cullFrontFace = new CullState();
- _cullFrontFace.setEnabled(true);
- _cullFrontFace.setCullFace(CullState.Face.Front);
- _noLights = new LightState();
- _noLights.setEnabled(false);
-
- _shadowOffsetState = new OffsetState();
- _shadowOffsetState.setEnabled(true);
- _shadowOffsetState.setTypeEnabled(OffsetType.Fill, true);
- _shadowOffsetState.setFactor(1.1f);
- _shadowOffsetState.setUnits(4.0f);
-
- _flat = new ShadingState();
- _flat.setShadingMode(ShadingMode.Flat);
-
- // When rendering and comparing the shadow map with the current depth, the result will be set to alpha 1 if in
- // shadow and to 0 if not in shadow.
- _discardShadowFragments = new BlendState();
- _discardShadowFragments.setEnabled(true);
- _discardShadowFragments.setBlendEnabled(true);
- _discardShadowFragments.setTestEnabled(true);
- _discardShadowFragments.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
- _discardShadowFragments.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
-
- _shadowTextureState = new TextureState();
- }
-
- /**
- * Add a spatial that will occlude light and hence cast a shadow.
- *
- * @param occluder
- * The spatial to add as an occluder
- */
- public void addOccluder(final Spatial occluder) {
- if (!_occluderNodes.contains(occluder)) {
- _occluderNodes.add(occluder);
- }
- }
-
- /**
- * Remove a spatial from the list of occluders.
- *
- * @param occluder
- * The spatial to remove from the occluderlist
- */
- public void removeOccluder(final Spatial occluder) {
- _occluderNodes.remove(occluder);
- }
-
- /**
- * Initialize the pass render states.
- *
- * @param r
- * the r
- */
- public void init(final Renderer r) {
- if (_initialised) {
- return;
- }
-
- _initialised = true; // now it's initialized
-
- // render states to use when rendering into the shadow map, no textures or colors are required since we're only
- // interested in recording depth. Also only need back faces when rendering the shadow maps
-
- // Load PSSM shader.
- final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
- if (caps.isGLSLSupported()) {
- _pssmShader = new GLSLShaderObjectsState();
- try {
- _pssmShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
- ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssm.vert"));
- if (filter == Filter.None) {
- _pssmShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
- ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssm.frag"));
- } else if (filter == Filter.Pcf) {
- _pssmShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
- ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmPCF.frag"));
- }
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- _mainShader = _pssmShader;
-
- _pssmDebugShader = new GLSLShaderObjectsState();
- try {
- _pssmDebugShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
- ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmDebug.vert"));
- _pssmDebugShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
- ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmDebug.frag"));
- } catch (final IOException ex) {
- logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
- }
- }
-
- // Setup texture renderer.
- reinitTextureSize(r);
-
- // Setup textures and shader for all splits
- reinitSplits();
- }
-
- public void reinit(final Renderer r) {
- reinitTextureSize(r);
- reinitSplits();
- }
-
- /**
- * Reinit texture size. Sets up texture renderer.
- *
- * @param r
- * the Renderer
- */
- private void reinitTextureSize(final Renderer r) {
- if (!_reinitTextureSizeDirty) {
- return;
- }
-
- _reinitTextureSizeDirty = false;
-
- final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
-
- // Create texture renderer
- _shadowMapRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(_shadowMapSize, _shadowMapSize, r,
- caps);
-
- // Enforce performance enhancing states on the renderer.
- _shadowMapRenderer.enforceState(_noClip);
- _shadowMapRenderer.enforceState(_colorDisabled);
- if (!_useObjectCullFace) {
- _shadowMapRenderer.enforceState(_cullFrontFace);
- } else {
- _shadowMapRenderer.clearEnforcedState(StateType.Cull);
- }
- _shadowMapRenderer.enforceState(_noLights);
- _shadowMapRenderer.enforceState(_flat);
- _shadowMapRenderer.enforceState(_shadowOffsetState);
- if (!_useSceneTexturing) {
- _shadowMapRenderer.enforceState(_noTexture);
- } else {
- _shadowMapRenderer.clearEnforcedState(RenderState.StateType.Texture);
- }
-
- if (_light instanceof DirectionalLight) {
- _shadowMapRenderer.getCamera().setProjectionMode(ProjectionMode.Parallel);
- }
- }
-
- /**
- * Reinit splits. Setup textures and shader for all splits
- */
- private void reinitSplits() {
- if (!_reinitSplitsDirty) {
- return;
- }
-
- _reinitSplitsDirty = false;
-
- // render state to apply the shadow map texture
- _shadowMapTexture = new Texture2D[_numOfSplits];
- for (int i = 0; i < _numOfSplits; i++) {
- _shadowMapTexture[i] = new Texture2D();
- _shadowMapTexture[i].setWrap(Texture.WrapMode.BorderClamp);
- _shadowMapTexture[i].setMinificationFilter(Texture.MinificationFilter.BilinearNoMipMaps);
- _shadowMapTexture[i].setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
- _shadowMapTexture[i].setBorderColor(ColorRGBA.WHITE);
-
- _shadowMapTexture[i].setEnvironmentalMapMode(Texture.EnvironmentalMapMode.EyeLinear);
-
- _shadowMapTexture[i].setTextureStoreFormat(_shadowTextureStoreFormat);
- _shadowMapTexture[i].setDepthCompareMode(DepthTextureCompareMode.RtoTexture);
- _shadowMapTexture[i].setDepthCompareFunc(DepthTextureCompareFunc.GreaterThanEqual);
- _shadowMapTexture[i].setDepthMode(DepthTextureMode.Intensity);
-
- _shadowMapRenderer.setupTexture(_shadowMapTexture[i]);
- _shadowTextureState.setTexture(_shadowMapTexture[i], i);
- }
- if (_pssmShader != null) {
- for (int i = 0; i < _MAX_SPLITS; i++) {
- _pssmShader.setUniform("shadowMap" + i, i);
- _pssmDebugShader.setUniform("shadowMap" + i, i);
- _mainShader.setUniform("shadowMap" + i, i);
- }
- }
- }
-
- /**
- * Render the pass.
- *
- * @param r
- * the Renderer
- */
- @Override
- protected void doRender(final Renderer r) {
- updateShadowMaps(r);
-
- if (_renderShadowedScene) {
- // Render overlay scene
- renderShadowedScene(r);
- }
- }
-
- public void updateShadowMaps(final Renderer r) {
- init(r);
- reinitTextureSize(r);
- reinitSplits();
-
- // Update receiving scene bounds to prepare for frustum packing
- updateReceiverBounds();
-
- // If updating camera is true (can be turned off for debugging), copy from main
- // camera and pack frustum.
- if (_updateMainCamera) {
- // Copy our active camera to our working pssm camera.
- final Camera cam = ContextManager.getCurrentContext().getCurrentCamera();
- _pssmCam.set(cam);
-
- // Calculate the closest fitting near and far planes.
- if (hasValidBounds) {
- _pssmCam.pack(_receiverBounds);
- } else {
- _pssmCam.updateMaxCameraFar();
- }
- }
-
- // Calculate the split distances
- _pssmCam.calculateSplitDistances(_numOfSplits);
-
- // Render our scene in sections.
- // For each part...
- for (int iSplit = 0; iSplit < _numOfSplits; iSplit++) {
- // Figure out the appropriate frustum.
- final double fNear = _pssmCam.getSplitDistances()[iSplit];
- final double fFar = _pssmCam.getSplitDistances()[iSplit + 1];
-
- // Calculate the frustum corners for the current split
- _pssmCam.calculateFrustum(fNear, fFar);
-
- // Debug draw main camera frustum for current split
- if (_drawDebug) {
- drawFrustum(r, _pssmCam, fNear, fFar, new ColorRGBA(0, 1, (float) (iSplit + 1) / _numOfSplits, 1),
- (short) 0xF000, iSplit == 0);
- }
-
- // Calculate the appropriate lightview and projection matrices for the current split
- if (_light instanceof DirectionalLight) {
- calculateOptimalLightFrustum(_pssmCam._corners, _pssmCam._center);
-
- if (_drawDebug) {
- boundingSphere
- .setData(frustumBoundingSphere.getCenter(), 10, 10, frustumBoundingSphere.getRadius());
- boundingSphere.draw(r);
- }
- } else if (_light instanceof PointLight) {
- calculateOptimalLightFrustumOld(_pssmCam._corners, _pssmCam._center);
- }
-
- // Debug draw light frustum for current split
- if (_drawDebug) {
- drawFrustum(r, _shadowMapRenderer.getCamera(), new ColorRGBA(1, 1, (iSplit + 1) / (float) _numOfSplits,
- 1), (short) 0xFFFF, true);
- }
-
- // Render shadowmap from light view for current split
- updateShadowMap(iSplit, r);
-
- // Update texture matrix for shadowmap
- updateTextureMatrix(iSplit);
- }
-
- updateShaderVariables();
- }
-
- private void updateShaderVariables() {
- if (_pssmShader != null && ContextManager.getCurrentContext().getCapabilities().isGLSLSupported()) {
- final float split1 = (float) _pssmCam.getSplitDistances()[1];
- final float split2 = (float) (_pssmCam.getSplitDistances().length > 2 ? _pssmCam.getSplitDistances()[2]
- : 0f);
- final float split3 = (float) (_pssmCam.getSplitDistances().length > 3 ? _pssmCam.getSplitDistances()[3]
- : 0f);
- final float split4 = (float) (_pssmCam.getSplitDistances().length > 4 ? _pssmCam.getSplitDistances()[4]
- : 0f);
-
- GLSLShaderObjectsState currentShader = _drawShaderDebug ? _pssmDebugShader : _pssmShader;
- if (_drawShaderDebug) {
- currentShader = _pssmDebugShader;
- }
-
- currentShader.setUniform("sampleDist", split1, split2, split3, split4);
- if (filter == Filter.Pcf) {
- // TODO
- // currentShader.setUniform("_shadowSize", 1f / _shadowMapSize);
- }
-
- if (!_drawShaderDebug) {
- currentShader.setUniform("shadowColor", _shadowColor);
- }
-
- if (_keepMainShader) {
- _mainShader.setUniform("sampleDist", split1, split2, split3, split4);
- if (filter == Filter.Pcf) {
- // TODO
- // _mainShader.setUniform("_shadowSize", 1f / _shadowMapSize);
- }
-
- if (!_drawShaderDebug) {
- _mainShader.setUniform("shadowColor", _shadowColor);
- }
- }
- }
- }
-
- // TODO
- final FloatBuffer frustumBoundingBuffer = BufferUtils.createVector3Buffer(8);
- final BoundingSphere frustumBoundingSphere = new BoundingSphere();
-
- /**
- * Calculate optimal light frustum perspective.
- *
- * @param frustumCorners
- * the frustum corners
- * @param center
- * the center
- */
- private void calculateOptimalLightFrustum(final Vector3[] frustumCorners, final ReadOnlyVector3 centerFrustum) {
- for (int i = 0; i < 8; i++) {
- BufferUtils.setInBuffer(frustumCorners[i], frustumBoundingBuffer, i);
- }
- frustumBoundingSphere.computeFromPoints(frustumBoundingBuffer);
-
- final Camera shadowCam = _shadowMapRenderer.getCamera();
-
- final ReadOnlyVector3 center = frustumBoundingSphere.getCenter();
- final double radius = frustumBoundingSphere.getRadius();
-
- Vector3 direction = new Vector3();
- final DirectionalLight dl = (DirectionalLight) _light;
- direction = direction.set(dl.getDirection());
- final double distance = Math.max(radius, _minimumLightDistance);
-
- final Vector3 tmpVec = Vector3.fetchTempInstance();
- tmpVec.set(direction);
- tmpVec.negateLocal();
- tmpVec.multiplyLocal(distance);
- tmpVec.addLocal(center);
-
- // temporary location
- shadowCam.setLocation(tmpVec);
- shadowCam.lookAt(center, Vector3.UNIT_Y);
-
- {
- // determine
- final double texelSizeW = (2 * radius) / _shadowMapRenderer.getWidth();
- final double texelSizeH = (2 * radius) / _shadowMapRenderer.getHeight();
-
- // build a Quaternion from camera axes to move
- final Quaternion q = Quaternion.fetchTempInstance();
- q.fromAxes(shadowCam.getLeft(), shadowCam.getUp(), shadowCam.getDirection());
-
- // invert to calculate in light space
- final Vector3 lightSpace = q.invert(null).apply(tmpVec, Vector3.fetchTempInstance());
-
- // snap to nearest texel
- lightSpace.setX(lightSpace.getX() - (lightSpace.getX() % texelSizeW));
- lightSpace.setY(lightSpace.getY() - (lightSpace.getY() % texelSizeH));
-
- // convert back
- q.apply(lightSpace, tmpVec);
- Vector3.releaseTempInstance(lightSpace);
-
- Quaternion.releaseTempInstance(q);
- }
-
- // updated location
- final double x = tmpVec.getX();
- final double y = tmpVec.getY();
- final double z = tmpVec.getZ();
- final double farZ = tmpVec.subtractLocal(center).length() + radius;
- Vector3.releaseTempInstance(tmpVec);
-
- // set frustum, then location
- shadowCam.setFrustum(1, farZ, -radius, radius, radius, -radius);
- shadowCam.setLocation(x, y, z);
- }
-
- /**
- * Saving this around until we fully support a good solution for non-directional lights. Like dual paraboloid shadow
- * maps...
- *
- * @param frustumCorners
- * @param center
- */
- private void calculateOptimalLightFrustumOld(final Vector3[] frustumCorners, final ReadOnlyVector3 center) {
- final Camera shadowCam = _shadowMapRenderer.getCamera();
-
- double distance = _minimumLightDistance;
-
- final Vector3 tmpVec = Vector3.fetchTempInstance();
-
- // Update shadow camera from light
- final PointLight pl = (PointLight) _light;
-
- shadowCam.setLocation(pl.getLocation());
-
- // Point light at split center
- shadowCam.lookAt(center, Vector3.UNIT_Y);
-
- // Reset frustum
- distance = center.subtract(shadowCam.getLocation(), tmpVec).length();
- shadowCam.setFrustum(1, distance, -1, 1, 1, -1);
-
- double fMinX = Double.POSITIVE_INFINITY;
- double fMaxX = Double.NEGATIVE_INFINITY;
- double fMinY = Double.POSITIVE_INFINITY;
- double fMaxY = Double.NEGATIVE_INFINITY;
- double fMinZ = Double.POSITIVE_INFINITY;
- double fMaxZ = Double.NEGATIVE_INFINITY;
-
- final ReadOnlyMatrix4 lightviewproj = shadowCam.getModelViewProjectionMatrix();
-
- final Vector4 position = Vector4.fetchTempInstance();
- for (final Vector3 frustumCorner : frustumCorners) {
- position.set(frustumCorner.getX(), frustumCorner.getY(), frustumCorner.getZ(), 1);
- lightviewproj.applyPre(position, position);
-
- position.setX(position.getX() / position.getW());
- position.setY(position.getY() / position.getW());
- position.setZ(position.getZ());
-
- fMinX = Math.min(position.getX(), fMinX);
- fMaxX = Math.max(position.getX(), fMaxX);
-
- fMinY = Math.min(position.getY(), fMinY);
- fMaxY = Math.max(position.getY(), fMaxY);
-
- fMinZ = Math.min(position.getZ(), fMinZ);
- fMaxZ = Math.max(position.getZ(), fMaxZ);
- }
-
- double width = 0;
- double height = 0;
- fMinX = clamp(fMinX, -1.0, 1.0);
- fMaxX = clamp(fMaxX, -1.0, 1.0);
- fMinY = clamp(fMinY, -1.0, 1.0);
- fMaxY = clamp(fMaxY, -1.0, 1.0);
-
- // Make sure the minimum z is at least a specified distance from
- // the target.
- fMinZ = Math.min(fMinZ, distance - _minimumLightDistance);
- fMinZ = Math.max(10.0, fMinZ);
-
- width = fMinZ * (fMaxX - fMinX) * 0.5;
- height = fMinZ * (fMaxY - fMinY) * 0.5;
-
- final Vector3 newCenter = Vector3.fetchTempInstance();
- position.set((fMinX + fMaxX) * 0.5, (fMinY + fMaxY) * 0.5, 1.0, 1);
- shadowCam.getModelViewProjectionInverseMatrix().applyPre(position, position);
- position.divideLocal(position.getW());
- newCenter.set(position.getX(), position.getY(), position.getZ());
-
- shadowCam.lookAt(newCenter, Vector3.UNIT_Y);
-
- Vector3.releaseTempInstance(newCenter);
- Vector4.releaseTempInstance(position);
-
- shadowCam.setFrustum(fMinZ, fMaxZ, -width, width, height, -height);
- shadowCam.update();
- }
-
- /**
- * Render the overlay scene with shadows.
- *
- * @param r
- * The renderer to use
- */
- public void renderShadowedScene(final Renderer r) {
- boolean reset = false;
- if (_context == null) {
- _context = ContextManager.getCurrentContext();
- reset = true;
- }
-
- _context.pushEnforcedStates();
- _context.enforceState(_shadowTextureState);
- _context.enforceState(_discardShadowFragments);
-
- if (_pssmShader != null && _context.getCapabilities().isGLSLSupported()) {
- GLSLShaderObjectsState currentShader = _drawShaderDebug ? _pssmDebugShader : _pssmShader;
- if (_drawShaderDebug) {
- currentShader = _pssmDebugShader;
- }
- if (_keepMainShader) {
- currentShader = _mainShader;
- }
- _context.enforceState(currentShader);
- }
-
- for (final Spatial spat : _spatials) {
- spat.onDraw(r);
- }
- r.renderBuckets();
-
- _context.popEnforcedStates();
-
- if (reset) {
- // _context = null;
- }
- }
-
- private static RenderLogic logic = new RenderLogic() {
- private CullState cullState;
- private Face cullFace;
- private boolean isVisible;
-
- public void apply(final Renderable renderable) {
- if (renderable instanceof Mesh) {
- final Mesh mesh = (Mesh) renderable;
-
- isVisible = mesh.isVisible();
- if (!mesh.getSceneHints().isCastsShadows()) {
- mesh.setVisible(false);
- }
-
- cullState = (CullState) mesh.getWorldRenderState(StateType.Cull);
- if (cullState != null) {
- cullFace = cullState.getCullFace();
- if (cullFace != Face.None) {
- cullState.setCullFace(Face.Front);
- }
- }
- }
- }
-
- public void restore(final Renderable renderable) {
- if (renderable instanceof Mesh) {
- final Mesh mesh = (Mesh) renderable;
-
- mesh.setVisible(isVisible);
-
- if (cullState != null) {
- cullState.setCullFace(cullFace);
- }
- }
- }
- };
-
- /**
- * Update the shadow map.
- *
- * @param index
- * shadow map texture index to update
- */
- private void updateShadowMap(final int index, final Renderer r) {
-
- if (shadowRenderCallback != null) {
- shadowRenderCallback.onRender(index, r, this, _shadowMapRenderer.getCamera());
- }
-
- r.setRenderLogic(logic);
- if (!_useSceneTexturing) {
- Mesh.RENDER_VERTEX_ONLY = true;
- }
- _shadowMapRenderer.render(_occluderNodes, _shadowMapTexture[index], Renderer.BUFFER_COLOR_AND_DEPTH);
- if (!_useSceneTexturing) {
- Mesh.RENDER_VERTEX_ONLY = false;
- }
- r.setRenderLogic(null);
- }
-
- /**
- * Update texture matrix.
- *
- * @param index
- * the index
- */
- private void updateTextureMatrix(final int index) {
- // Create a matrix going from light to camera space
- final Camera cam = ContextManager.getCurrentContext().getCurrentCamera();
- _shadowMatrix.set(cam.getModelViewMatrix()).invertLocal();
- _shadowMatrix.multiplyLocal(_shadowMapRenderer.getCamera().getModelViewProjectionMatrix()).multiplyLocal(
- SCALE_BIAS_MATRIX);
- _shadowMapTexture[index].setTextureMatrix(_shadowMatrix);
- }
-
- /**
- * Checks if this pass is initialized.
- *
- * @return true, if is initialized
- */
- public boolean isInitialised() {
- return _initialised;
- }
-
- /**
- *
- * @return the offset state used for drawing the shadow textures.
- */
- public OffsetState getShadowOffsetState() {
- return _shadowOffsetState;
- }
-
- /**
- * Update receiver bounds.
- */
- private void updateReceiverBounds() {
- hasValidBounds = false;
- boolean firstRun = true;
-
- for (int i = 0, cSize = _boundsReceiver.size(); i < cSize; i++) {
- final Spatial child = _boundsReceiver.get(i);
- if (child != null && child.getWorldBound() != null && boundIsValid(child.getWorldBound())) {
- if (firstRun) {
- _receiverBounds.setCenter(child.getWorldBound().getCenter());
- _receiverBounds.setXExtent(0);
- _receiverBounds.setYExtent(0);
- _receiverBounds.setZExtent(0);
- firstRun = false;
- }
- _receiverBounds.mergeLocal(child.getWorldBound());
- hasValidBounds = true;
- }
- }
-
- for (int i = 0, cSize = _spatials.size(); i < cSize; i++) {
- final Spatial child = _spatials.get(i);
- if (child != null && child.getWorldBound() != null && boundIsValid(child.getWorldBound())) {
- if (firstRun) {
- _receiverBounds.setCenter(child.getWorldBound().getCenter());
- _receiverBounds.setXExtent(0);
- _receiverBounds.setYExtent(0);
- _receiverBounds.setZExtent(0);
- firstRun = false;
- }
- _receiverBounds.mergeLocal(child.getWorldBound());
- hasValidBounds = true;
- }
- }
- }
-
- /**
- * Checks if a bounding volume is valid.
- *
- * @param volume
- * @return
- */
- private boolean boundIsValid(final BoundingVolume volume) {
- if (!Vector3.isValid(volume.getCenter())) {
- return false;
- }
- switch (volume.getType()) {
- case AABB: {
- final BoundingBox vBox = (BoundingBox) volume;
- return !(Double.isInfinite(vBox.getXExtent()) || Double.isInfinite(vBox.getYExtent())
- || Double.isInfinite(vBox.getZExtent()) || Double.isNaN(vBox.getXExtent())
- || Double.isNaN(vBox.getYExtent()) || Double.isNaN(vBox.getZExtent()));
- }
-
- case Sphere: {
- final BoundingSphere vSphere = (BoundingSphere) volume;
- return !(Double.isInfinite(vSphere.getRadius()) || Double.isNaN(vSphere.getRadius()));
- }
-
- case OBB: {
- final OrientedBoundingBox obb = (OrientedBoundingBox) volume;
- return Vector3.isValid(obb.getExtent());
- }
-
- default:
- return true;
- }
- }
-
- /**
- * Gets the shadow map texture.
- *
- * @param index
- * the index
- *
- * @return the shadow map texture
- */
- public Texture2D getShadowMapTexture(final int index) {
- return _shadowMapTexture[index];
- }
-
- /**
- * Gets the number of splits.
- *
- * @return the number of splits
- */
- public int getNumOfSplits() {
- return _numOfSplits;
- }
-
- /**
- * Sets the number of frustum splits and thus the number of shadow textures created by this pass. More splits
- * creates crisper shadows at the cost of increased texture memory.
- *
- * @param numOfSplits
- * the new number of splits
- */
- public void setNumOfSplits(final int numOfSplits) {
- _numOfSplits = Math.min(Math.max(_MIN_SPLITS, numOfSplits), _MAX_SPLITS);
- _reinitSplitsDirty = true;
-
- if (_numOfSplits != numOfSplits) {
- logger.warning("Valid range for number of splits is " + _MIN_SPLITS + " to " + _MAX_SPLITS
- + ". Tried to set it to " + numOfSplits);
- }
- }
-
- /**
- * Gets the shadow map size.
- *
- * @return the shadow map size
- */
- public int getShadowMapSize() {
- return _shadowMapSize;
- }
-
- /**
- * Sets the shadow map size.
- *
- * @param shadowMapSize
- * the new shadow map size
- */
- public void setShadowMapSize(final int shadowMapSize) {
- _shadowMapSize = shadowMapSize;
- _reinitTextureSizeDirty = true;
- _reinitSplitsDirty = true;
- }
-
- /**
- * Gets the maximum distance for shadowing.
- *
- * @return max distance
- * @see com.ardor3d.extension.shadow.map.PSSMCamera#getMaxFarPlaneDistance()
- */
- public double getMaxShadowDistance() {
- return _pssmCam.getMaxFarPlaneDistance();
- }
-
- /**
- * Sets the maximum distance for shadowing.
- *
- * @param maxShadowDistance
- * distance to set
- * @see com.ardor3d.extension.shadow.map.PSSMCamera#setMaxFarPlaneDistance(double)
- */
- public void setMaxShadowDistance(final double maxShadowDistance) {
- _pssmCam.setMaxFarPlaneDistance(maxShadowDistance);
- }
-
- /**
- * Gets the minimum z distance for the light.
- *
- * @return the minimumLightDistance
- */
- public double getMinimumLightDistance() {
- return _minimumLightDistance;
- }
-
- /**
- * Sets the minimum z distance for the light.
- *
- * @param minimumLightDistance
- * the minimumLightDistance to set
- */
- public void setMinimumLightDistance(final double minimumLightDistance) {
- _minimumLightDistance = minimumLightDistance;
- }
-
- /**
- * Gets shadow color and transparency.
- *
- * @return the shadowColor
- */
- public ReadOnlyColorRGBA getShadowColor() {
- return _shadowColor;
- }
-
- /**
- * Sets shadow color and transparency.
- *
- * @param shadowColor
- * the shadowColor to set
- */
- public void setShadowColor(final ReadOnlyColorRGBA shadowColor) {
- _shadowColor.set(shadowColor);
- }
-
- public ShadowRenderCallback getShadowRenderCallback() {
- return shadowRenderCallback;
- }
-
- public void setShadowRenderCallback(final ShadowRenderCallback callback) {
- shadowRenderCallback = callback;
- }
-
- /**
- * Clean up.
- *
- * @see com.ardor3d.renderer.pass.Pass#cleanUp()
- */
- @Override
- public void cleanUp() {
- super.cleanUp();
-
- if (_shadowMapRenderer != null) {
- _shadowMapRenderer.cleanup();
- }
- }
-
- /**
- * Remove the contents of the pass.
- */
- public void clear() {
- _occluderNodes.clear();
- _spatials.clear();
- }
-
- /**
- * Simple clamp.
- *
- * @param val
- * value to clamp
- * @param from
- * minimum value after clamping
- * @param to
- * maximum value after clamping
- * @return Math.min(to, Math.max(from, val))
- */
- private double clamp(final double val, final double from, final double to) {
- return Math.min(to, Math.max(from, val));
- }
-
- /**
- * @return the updateMainCamera
- */
- public boolean isUpdateMainCamera() {
- return _updateMainCamera;
- }
-
- /**
- * @param updateMainCamera
- * True (the default) if we want to copy the current rendering camera into this pass for use in shadow
- * generation. False if we will manage our shadow camera elsewhere.
- * @see #getPssmCam()
- */
- public void setUpdateMainCamera(final boolean updateMainCamera) {
- _updateMainCamera = updateMainCamera;
- }
-
- /**
- * @return the drawDebug
- */
- public boolean isDrawDebug() {
- return _drawDebug;
- }
-
- /**
- * @param drawDebug
- * True if we want to draw camera and light frustums for debugging purposes. Default is false.
- */
- public void setDrawDebug(final boolean drawDebug) {
- _drawDebug = drawDebug;
- }
-
- /**
- * @return the drawShaderDebug
- */
- public boolean isDrawShaderDebug() {
- return _drawShaderDebug;
- }
-
- /**
- * @param drawShaderDebug
- * True if we want to draw debug colors over the shadows, showing which level they come from.
- */
- public void setDrawShaderDebug(final boolean drawShaderDebug) {
- _drawShaderDebug = drawShaderDebug;
- }
-
- /**
- * @return the useSceneTexturing
- */
- public boolean isUseSceneTexturing() {
- return _useSceneTexturing;
- }
-
- /**
- * @param useSceneTexturing
- * True if we want to factor in texturing to shadows; useful for casting shadows against alpha-tested
- * textures. Default is false.
- */
- public void setUseSceneTexturing(final boolean useSceneTexturing) {
- _useSceneTexturing = useSceneTexturing;
- if (_shadowMapRenderer != null) {
- if (!_useSceneTexturing) {
- _shadowMapRenderer.enforceState(_noTexture);
- } else {
- _shadowMapRenderer.clearEnforcedState(RenderState.StateType.Texture);
- }
- }
-
- }
-
- public boolean isUseObjectCullFace() {
- return _useObjectCullFace;
- }
-
- /**
- * @param useObjectCullFace
- * True if we want to use the culling set on the objects instead of always culling front face (which is
- * done for shadow precision). Default is false.
- */
- public void setUseObjectCullFace(final boolean useObjectCullFace) {
- _useObjectCullFace = useObjectCullFace;
- if (_shadowMapRenderer != null) {
- if (!_useObjectCullFace) {
- _shadowMapRenderer.enforceState(_cullFrontFace);
- } else {
- _shadowMapRenderer.clearEnforcedState(StateType.Cull);
- }
- }
- }
-
- public boolean isRenderShadowedScene() {
- return _renderShadowedScene;
- }
-
- /**
- * @param renderShadowedScene
- * When true (the default) the generated shadow map textures are drawn over the scene in a separate blend
- * pass. If false, the shadows are generated, but not applied.
- */
- public void setRenderShadowedScene(final boolean renderShadowedScene) {
- _renderShadowedScene = renderShadowedScene;
- }
-
- /**
- * @return the camera used internally to generate shadows.
- */
- public PSSMCamera getPssmCam() {
- return _pssmCam;
- }
-
- /**
- * @return the texture store format to use for the shadow textures on the next call to init/setNumOfSplits.
- */
- public TextureStoreFormat getShadowTextureStoreFormat() {
- return _shadowTextureStoreFormat;
- }
-
- /**
- * @param shadowTextureStoreFormat
- * - the texture store format to use for the shadow textures. Only has an affect if called prior to
- * calling init on this pass (or if called before calling {@link #setNumOfSplits(int)}).
- */
- public void setShadowTextureStoreFormat(final TextureStoreFormat shadowTextureStoreFormat) {
- _shadowTextureStoreFormat = shadowTextureStoreFormat;
- }
-
- /** The debug line frustum. */
- private static Line lineFrustum;
-
- /** The debug test cam. */
- private static final PSSMCamera testCam = new PSSMCamera();
-
- /** Debug bounding sphere */
- private static final Sphere boundingSphere = new Sphere("bsphere", 10, 10, 1);
- static {
- boundingSphere.getSceneHints().setRenderBucketType(RenderBucketType.Skip);
- boundingSphere.setRenderState(new WireframeState());
- boundingSphere.setRenderState(new ZBufferState());
- boundingSphere.updateWorldRenderStates(false);
- }
-
- /**
- * Draw debug frustum.
- *
- * @param r
- * the r
- * @param cam
- * the cam
- * @param color
- * the color
- * @param drawOriginConnector
- * whether or not to draw a connector
- */
- private static void drawFrustum(final Renderer r, final Camera cam, final ReadOnlyColorRGBA color,
- final short pattern, final boolean drawOriginConnector) {
- drawFrustum(r, cam, cam.getFrustumNear(), cam.getFrustumFar(), color, pattern, drawOriginConnector);
- }
-
- /**
- * Draw debug frustum.
- *
- * @param r
- * the r
- * @param cam
- * the cam
- * @param fNear
- * the f near
- * @param fFar
- * the f far
- * @param color
- * the color
- * @param drawOriginConnector
- * whether or not to draw a connector
- */
- private static void drawFrustum(final Renderer r, final Camera cam, final double fNear, final double fFar,
- final ReadOnlyColorRGBA color, final short pattern, final boolean drawOriginConnector) {
- if (lineFrustum == null) {
- final FloatBuffer verts = BufferUtils.createVector3Buffer(24);
- final FloatBuffer colors = BufferUtils.createColorBuffer(24);
-
- lineFrustum = new Line("Lines", verts, null, colors, null);
- lineFrustum.getMeshData().setIndexModes(
- new IndexMode[] { IndexMode.LineLoop, IndexMode.LineLoop, IndexMode.Lines, IndexMode.Lines });
- lineFrustum.getMeshData().setIndexLengths(new int[] { 4, 4, 8, 8 });
- lineFrustum.setLineWidth(2);
- lineFrustum.getSceneHints().setLightCombineMode(LightCombineMode.Off);
-
- final BlendState lineBlendState = new BlendState();
- lineBlendState.setEnabled(true);
- lineBlendState.setBlendEnabled(true);
- lineBlendState.setTestEnabled(true);
- lineBlendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
- lineBlendState.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
- lineFrustum.setRenderState(lineBlendState);
-
- final ZBufferState zstate = new ZBufferState();
- lineFrustum.setRenderState(zstate);
- lineFrustum.updateGeometricState(0.0);
-
- lineFrustum.getSceneHints().setRenderBucketType(RenderBucketType.Skip);
- }
-
- lineFrustum.setDefaultColor(color);
- lineFrustum.setStipplePattern(pattern);
-
- testCam.set(cam);
- testCam.update();
- testCam.calculateFrustum(fNear, fFar);
-
- final FloatBuffer colors = lineFrustum.getMeshData().getColorBuffer();
- for (int i = 0; i < 16; i++) {
- BufferUtils.setInBuffer(color, colors, i);
- }
- final float alpha = drawOriginConnector ? 0.4f : 0.0f;
- for (int i = 16; i < 24; i++) {
- colors.position(i * 4);
- colors.put(color.getRed());
- colors.put(color.getGreen());
- colors.put(color.getBlue());
- colors.put(alpha);
- }
-
- final FloatBuffer verts = lineFrustum.getMeshData().getVertexBuffer();
- BufferUtils.setInBuffer(testCam._corners[0], verts, 0);
- BufferUtils.setInBuffer(testCam._corners[1], verts, 1);
- BufferUtils.setInBuffer(testCam._corners[2], verts, 2);
- BufferUtils.setInBuffer(testCam._corners[3], verts, 3);
-
- BufferUtils.setInBuffer(testCam._corners[4], verts, 4);
- BufferUtils.setInBuffer(testCam._corners[5], verts, 5);
- BufferUtils.setInBuffer(testCam._corners[6], verts, 6);
- BufferUtils.setInBuffer(testCam._corners[7], verts, 7);
-
- BufferUtils.setInBuffer(testCam._corners[0], verts, 8);
- BufferUtils.setInBuffer(testCam._corners[4], verts, 9);
- BufferUtils.setInBuffer(testCam._corners[1], verts, 10);
- BufferUtils.setInBuffer(testCam._corners[5], verts, 11);
- BufferUtils.setInBuffer(testCam._corners[2], verts, 12);
- BufferUtils.setInBuffer(testCam._corners[6], verts, 13);
- BufferUtils.setInBuffer(testCam._corners[3], verts, 14);
- BufferUtils.setInBuffer(testCam._corners[7], verts, 15);
-
- BufferUtils.setInBuffer(testCam.getLocation(), verts, 16);
- BufferUtils.setInBuffer(testCam._corners[0], verts, 17);
- BufferUtils.setInBuffer(testCam.getLocation(), verts, 18);
- BufferUtils.setInBuffer(testCam._corners[1], verts, 19);
- BufferUtils.setInBuffer(testCam.getLocation(), verts, 20);
- BufferUtils.setInBuffer(testCam._corners[2], verts, 21);
- BufferUtils.setInBuffer(testCam.getLocation(), verts, 22);
- BufferUtils.setInBuffer(testCam._corners[3], verts, 23);
-
- lineFrustum.draw(r);
- }
-
- public void setPssmShader(final GLSLShaderObjectsState pssmShader) {
- _pssmShader = pssmShader;
- }
-
- public boolean isKeepMainShader() {
- return _keepMainShader;
- }
-
- public void setKeepMainShader(final boolean keepMainShader) {
- _keepMainShader = keepMainShader;
- }
-
- public void addBoundsReceiver(final Spatial spatial) {
- _boundsReceiver.add(spatial);
- }
-
- public void setFiltering(final Filter filter) {
- this.filter = filter;
- }
-
- public BlendState getDiscardShadowFragmentsBlendState() {
- return _discardShadowFragments;
- }
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.shadow.map;
+
+import java.io.IOException;
+import java.nio.FloatBuffer;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.bounding.BoundingBox;
+import com.ardor3d.bounding.BoundingSphere;
+import com.ardor3d.bounding.BoundingVolume;
+import com.ardor3d.bounding.OrientedBoundingBox;
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture.DepthTextureCompareFunc;
+import com.ardor3d.image.Texture.DepthTextureCompareMode;
+import com.ardor3d.image.Texture.DepthTextureMode;
+import com.ardor3d.image.Texture2D;
+import com.ardor3d.image.TextureStoreFormat;
+import com.ardor3d.light.DirectionalLight;
+import com.ardor3d.light.Light;
+import com.ardor3d.light.PointLight;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Matrix4;
+import com.ardor3d.math.Quaternion;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.Vector4;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.math.type.ReadOnlyMatrix4;
+import com.ardor3d.math.type.ReadOnlyVector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Camera.ProjectionMode;
+import com.ardor3d.renderer.ContextCapabilities;
+import com.ardor3d.renderer.ContextManager;
+import com.ardor3d.renderer.IndexMode;
+import com.ardor3d.renderer.RenderLogic;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.TextureRenderer;
+import com.ardor3d.renderer.TextureRendererFactory;
+import com.ardor3d.renderer.pass.Pass;
+import com.ardor3d.renderer.queue.RenderBucketType;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.ClipState;
+import com.ardor3d.renderer.state.ColorMaskState;
+import com.ardor3d.renderer.state.CullState;
+import com.ardor3d.renderer.state.CullState.Face;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.LightState;
+import com.ardor3d.renderer.state.OffsetState;
+import com.ardor3d.renderer.state.OffsetState.OffsetType;
+import com.ardor3d.renderer.state.RenderState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.renderer.state.ShadingState;
+import com.ardor3d.renderer.state.ShadingState.ShadingMode;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.renderer.state.WireframeState;
+import com.ardor3d.renderer.state.ZBufferState;
+import com.ardor3d.scenegraph.Line;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.Renderable;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.hint.LightCombineMode;
+import com.ardor3d.scenegraph.shape.Sphere;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.google.common.collect.Lists;
+
+/**
+ * A pass providing a parallel split shadow mapping (PSSM) layer across the top of an existing scene.
+ */
+public class ParallelSplitShadowMapPass extends Pass {
+
+ /** The Constant logger. */
+ private static final Logger logger = Logger.getLogger(ParallelSplitShadowMapPass.class.getName());
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 1L;
+
+ /** Bias matrix from [-1, 1] to [0, 1]. */
+ public static final ReadOnlyMatrix4 SCALE_BIAS_MATRIX = new Matrix4( //
+ 0.5, 0.0, 0.0, 0.0, //
+ 0.0, 0.5, 0.0, 0.0, //
+ 0.0, 0.0, 0.5, 0.0, //
+ 0.5, 0.5, 0.5, 1.0);//
+
+ /** The renderer used to produce the shadow map. */
+ private TextureRenderer _shadowMapRenderer;
+
+ /** The textures storing the shadow maps. */
+ private Texture2D _shadowMapTexture[];
+
+ /** The list of occluding nodes. */
+ private final List<Spatial> _occluderNodes = Lists.newArrayList();
+
+ /** Extra bounds receivers, when rendering shadows other ways than through overlay */
+ private final List<Spatial> _boundsReceiver = Lists.newArrayList();
+
+ // Various optimizations for rendering shadow maps...
+ /** Culling front faces when rendering shadow maps. */
+ private final CullState _cullFrontFace;
+
+ /** Turn off textures when rendering shadow maps. */
+ private final TextureState _noTexture;
+
+ /** Turn off lighting when rendering shadow maps. */
+ private final LightState _noLights;
+
+ /** set flat shading when rendering shadow maps. */
+ private final ShadingState _flat;
+
+ // Important pieces for rendering shadow maps
+ /** Turn off colors when rendering shadow maps. */
+ private final ColorMaskState _colorDisabled;
+
+ /** The state applying the depth offset for the shadow. */
+ private final OffsetState _shadowOffsetState;
+
+ /**
+ * The blending to both discard the fragments that have been determined to be free of shadows and to blend into the
+ * background scene.
+ */
+ private final BlendState _discardShadowFragments;
+
+ /** The state applying the shadow map. */
+ private final TextureState _shadowTextureState;
+
+ /** Don't perform any plane clipping when rendering the shadowed scene. */
+ private final ClipState _noClip;
+
+ /** True once the pass has been initialized. */
+ protected boolean _initialised = false;
+
+ /** Flag for updating texture splits when number of splits changed. */
+ protected boolean _reinitSplitsDirty = true;
+
+ /** Flag for updating texture renderer when texture size changed. */
+ protected boolean _reinitTextureSizeDirty = true;
+
+ /** The size of the shadow map texture. */
+ private int _shadowMapSize;
+
+ /** Minimum number of splits allowed */
+ public static final int _MIN_SPLITS = 1;
+
+ /** Maximum number of splits allowed */
+ public static final int _MAX_SPLITS = 4;
+
+ /** Number of splits used. */
+ protected int _numOfSplits;
+
+ /** Minimum light z distance from target. */
+ private double _minimumLightDistance = 1000.0;
+
+ /** Shadow color and transparency. */
+ private final ColorRGBA _shadowColor = new ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f);
+
+ /** Light -> Camera transformation matrix. */
+ private final Matrix4 _shadowMatrix = new Matrix4();
+
+ /** Bounding of scene for packing frustum. */
+ protected BoundingBox _receiverBounds = new BoundingBox();
+
+ /** Indicates if we have any valid reciever bounds to use for frustum packing */
+ protected boolean hasValidBounds = false;
+
+ /** Special camera with functionality for packing frustum etc. */
+ protected PSSMCamera _pssmCam;
+
+ /** Light that casts the shadow. */
+ protected Light _light;
+
+ /** Shader for rendering pssm shadows in one pass. */
+ private GLSLShaderObjectsState _pssmShader;
+
+ /** Might need to keep main shader when doing both multitexturing shadows and overlays */
+ private GLSLShaderObjectsState _mainShader;
+
+ /** Shader for debugging pssm shadows drawing splits in different colors. */
+ private GLSLShaderObjectsState _pssmDebugShader;
+
+ /** Debug for stopping camera update. */
+ private boolean _updateMainCamera = true;
+
+ /** Debug drawing frustums. */
+ private boolean _drawDebug = false;
+
+ /** Debug drawing shader. */
+ private boolean _drawShaderDebug = false;
+
+ /** Do we want to keep the main shader to do both multitexturing shadows and overlays? */
+ private boolean _keepMainShader = false;
+
+ /**
+ * True if we want to factor in texturing to shadows; useful for casting shadows against alpha-tested textures.
+ * Default is false.
+ */
+ private boolean _useSceneTexturing = false;
+
+ /**
+ * True if we want to use the culling set on the objects instead of always culling front face (which is done for
+ * shadow precision). Default is false.
+ */
+ private boolean _useObjectCullFace = false;
+
+ /**
+ * When true (the default) the generated shadow map textures are drawn over the scene in a separate blend pass. If
+ * false, the shadows are generated, but not applied.
+ */
+ private boolean _renderShadowedScene = true;
+
+ /** Store format to use for the shadow textures. */
+ protected TextureStoreFormat _shadowTextureStoreFormat = TextureStoreFormat.Depth16;
+
+ /** Shadow filter techniques */
+ public enum Filter {
+ None, Pcf
+ }
+
+ private Filter filter = Filter.None;
+
+ private ShadowRenderCallback shadowRenderCallback;
+
+ /**
+ * Create a pssm shadow map pass casting shadows from a light with the direction given.
+ *
+ * @param shadowMapSize
+ * The size of the shadow map texture
+ * @param numOfSplits
+ * the num of splits
+ */
+ public ParallelSplitShadowMapPass(final Light light, final int shadowMapSize, final int numOfSplits) {
+ _light = light;
+ _shadowMapSize = shadowMapSize;
+ setNumOfSplits(numOfSplits);
+ _pssmCam = new PSSMCamera();
+
+ _noClip = new ClipState();
+ _noClip.setEnabled(false);
+ _noTexture = new TextureState();
+ _noTexture.setEnabled(false);
+ _colorDisabled = new ColorMaskState();
+ _colorDisabled.setAll(false);
+ _cullFrontFace = new CullState();
+ _cullFrontFace.setEnabled(true);
+ _cullFrontFace.setCullFace(CullState.Face.Front);
+ _noLights = new LightState();
+ _noLights.setEnabled(false);
+
+ _shadowOffsetState = new OffsetState();
+ _shadowOffsetState.setEnabled(true);
+ _shadowOffsetState.setTypeEnabled(OffsetType.Fill, true);
+ _shadowOffsetState.setFactor(1.1f);
+ _shadowOffsetState.setUnits(4.0f);
+
+ _flat = new ShadingState();
+ _flat.setShadingMode(ShadingMode.Flat);
+
+ // When rendering and comparing the shadow map with the current depth, the result will be set to alpha 1 if in
+ // shadow and to 0 if not in shadow.
+ _discardShadowFragments = new BlendState();
+ _discardShadowFragments.setEnabled(true);
+ _discardShadowFragments.setBlendEnabled(true);
+ _discardShadowFragments.setTestEnabled(true);
+ _discardShadowFragments.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
+ _discardShadowFragments.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
+
+ _shadowTextureState = new TextureState();
+ }
+
+ /**
+ * Add a spatial that will occlude light and hence cast a shadow.
+ *
+ * @param occluder
+ * The spatial to add as an occluder
+ */
+ public void addOccluder(final Spatial occluder) {
+ if (!_occluderNodes.contains(occluder)) {
+ _occluderNodes.add(occluder);
+ }
+ }
+
+ /**
+ * Remove a spatial from the list of occluders.
+ *
+ * @param occluder
+ * The spatial to remove from the occluderlist
+ */
+ public void removeOccluder(final Spatial occluder) {
+ _occluderNodes.remove(occluder);
+ }
+
+ /**
+ * Initialize the pass render states.
+ *
+ * @param r
+ * the r
+ */
+ public void init(final Renderer r) {
+ if (_initialised) {
+ return;
+ }
+
+ _initialised = true; // now it's initialized
+
+ // render states to use when rendering into the shadow map, no textures or colors are required since we're only
+ // interested in recording depth. Also only need back faces when rendering the shadow maps
+
+ // Load PSSM shader.
+ final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
+ if (caps.isGLSLSupported()) {
+ _pssmShader = new GLSLShaderObjectsState();
+ try {
+ _pssmShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssm.vert"));
+ if (filter == Filter.None) {
+ _pssmShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssm.frag"));
+ } else if (filter == Filter.Pcf) {
+ _pssmShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmPCF.frag"));
+ }
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ _mainShader = _pssmShader;
+
+ _pssmDebugShader = new GLSLShaderObjectsState();
+ try {
+ _pssmDebugShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmDebug.vert"));
+ _pssmDebugShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ ParallelSplitShadowMapPass.class, "com/ardor3d/extension/shadow/map/pssmDebug.frag"));
+ } catch (final IOException ex) {
+ logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
+ }
+ }
+
+ // Setup texture renderer.
+ reinitTextureSize(r);
+
+ // Setup textures and shader for all splits
+ reinitSplits();
+ }
+
+ public void reinit(final Renderer r) {
+ reinitTextureSize(r);
+ reinitSplits();
+ }
+
+ /**
+ * Reinit texture size. Sets up texture renderer.
+ *
+ * @param r
+ * the Renderer
+ */
+ private void reinitTextureSize(final Renderer r) {
+ if (!_reinitTextureSizeDirty) {
+ return;
+ }
+
+ _reinitTextureSizeDirty = false;
+
+ final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
+
+ // Create texture renderer
+ _shadowMapRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(_shadowMapSize, _shadowMapSize, r,
+ caps);
+
+ // Enforce performance enhancing states on the renderer.
+ _shadowMapRenderer.enforceState(_noClip);
+ _shadowMapRenderer.enforceState(_colorDisabled);
+ if (!_useObjectCullFace) {
+ _shadowMapRenderer.enforceState(_cullFrontFace);
+ } else {
+ _shadowMapRenderer.clearEnforcedState(StateType.Cull);
+ }
+ _shadowMapRenderer.enforceState(_noLights);
+ _shadowMapRenderer.enforceState(_flat);
+ _shadowMapRenderer.enforceState(_shadowOffsetState);
+ if (!_useSceneTexturing) {
+ _shadowMapRenderer.enforceState(_noTexture);
+ } else {
+ _shadowMapRenderer.clearEnforcedState(RenderState.StateType.Texture);
+ }
+
+ if (_light instanceof DirectionalLight) {
+ _shadowMapRenderer.getCamera().setProjectionMode(ProjectionMode.Parallel);
+ }
+ }
+
+ /**
+ * Reinit splits. Setup textures and shader for all splits
+ */
+ private void reinitSplits() {
+ if (!_reinitSplitsDirty) {
+ return;
+ }
+
+ _reinitSplitsDirty = false;
+
+ // render state to apply the shadow map texture
+ _shadowMapTexture = new Texture2D[_numOfSplits];
+ for (int i = 0; i < _numOfSplits; i++) {
+ _shadowMapTexture[i] = new Texture2D();
+ _shadowMapTexture[i].setWrap(Texture.WrapMode.BorderClamp);
+ _shadowMapTexture[i].setMinificationFilter(Texture.MinificationFilter.BilinearNoMipMaps);
+ _shadowMapTexture[i].setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
+ _shadowMapTexture[i].setBorderColor(ColorRGBA.WHITE);
+
+ _shadowMapTexture[i].setEnvironmentalMapMode(Texture.EnvironmentalMapMode.EyeLinear);
+
+ _shadowMapTexture[i].setTextureStoreFormat(_shadowTextureStoreFormat);
+ _shadowMapTexture[i].setDepthCompareMode(DepthTextureCompareMode.RtoTexture);
+ _shadowMapTexture[i].setDepthCompareFunc(DepthTextureCompareFunc.GreaterThanEqual);
+ _shadowMapTexture[i].setDepthMode(DepthTextureMode.Intensity);
+
+ _shadowMapRenderer.setupTexture(_shadowMapTexture[i]);
+ _shadowTextureState.setTexture(_shadowMapTexture[i], i);
+ }
+ if (_pssmShader != null) {
+ for (int i = 0; i < _MAX_SPLITS; i++) {
+ _pssmShader.setUniform("shadowMap" + i, i);
+ _pssmDebugShader.setUniform("shadowMap" + i, i);
+ _mainShader.setUniform("shadowMap" + i, i);
+ }
+ }
+ }
+
+ /**
+ * Render the pass.
+ *
+ * @param r
+ * the Renderer
+ */
+ @Override
+ protected void doRender(final Renderer r) {
+ updateShadowMaps(r);
+
+ if (_renderShadowedScene) {
+ // Render overlay scene
+ renderShadowedScene(r);
+ }
+ }
+
+ public void updateShadowMaps(final Renderer r) {
+ init(r);
+ reinitTextureSize(r);
+ reinitSplits();
+
+ // Update receiving scene bounds to prepare for frustum packing
+ updateReceiverBounds();
+
+ // If updating camera is true (can be turned off for debugging), copy from main
+ // camera and pack frustum.
+ if (_updateMainCamera) {
+ // Copy our active camera to our working pssm camera.
+ final Camera cam = ContextManager.getCurrentContext().getCurrentCamera();
+ _pssmCam.set(cam);
+
+ // Calculate the closest fitting near and far planes.
+ if (hasValidBounds) {
+ _pssmCam.pack(_receiverBounds);
+ } else {
+ _pssmCam.updateMaxCameraFar();
+ }
+ }
+
+ // Calculate the split distances
+ _pssmCam.calculateSplitDistances(_numOfSplits);
+
+ // Render our scene in sections.
+ // For each part...
+ for (int iSplit = 0; iSplit < _numOfSplits; iSplit++) {
+ // Figure out the appropriate frustum.
+ final double fNear = _pssmCam.getSplitDistances()[iSplit];
+ final double fFar = _pssmCam.getSplitDistances()[iSplit + 1];
+
+ // Calculate the frustum corners for the current split
+ _pssmCam.calculateFrustum(fNear, fFar);
+
+ // Debug draw main camera frustum for current split
+ if (_drawDebug) {
+ drawFrustum(r, _pssmCam, fNear, fFar, new ColorRGBA(0, 1, (float) (iSplit + 1) / _numOfSplits, 1),
+ (short) 0xF000, iSplit == 0);
+ }
+
+ // Calculate the appropriate lightview and projection matrices for the current split
+ if (_light instanceof DirectionalLight) {
+ calculateOptimalLightFrustum(_pssmCam._corners, _pssmCam._center);
+
+ if (_drawDebug) {
+ boundingSphere
+ .setData(frustumBoundingSphere.getCenter(), 10, 10, frustumBoundingSphere.getRadius());
+ boundingSphere.draw(r);
+ }
+ } else if (_light instanceof PointLight) {
+ calculateOptimalLightFrustumOld(_pssmCam._corners, _pssmCam._center);
+ }
+
+ // Debug draw light frustum for current split
+ if (_drawDebug) {
+ drawFrustum(r, _shadowMapRenderer.getCamera(), new ColorRGBA(1, 1, (iSplit + 1) / (float) _numOfSplits,
+ 1), (short) 0xFFFF, true);
+ }
+
+ // Render shadowmap from light view for current split
+ updateShadowMap(iSplit, r);
+
+ // Update texture matrix for shadowmap
+ updateTextureMatrix(iSplit);
+ }
+
+ updateShaderVariables();
+ }
+
+ private void updateShaderVariables() {
+ if (_pssmShader != null && ContextManager.getCurrentContext().getCapabilities().isGLSLSupported()) {
+ final float split1 = (float) _pssmCam.getSplitDistances()[1];
+ final float split2 = (float) (_pssmCam.getSplitDistances().length > 2 ? _pssmCam.getSplitDistances()[2]
+ : 0f);
+ final float split3 = (float) (_pssmCam.getSplitDistances().length > 3 ? _pssmCam.getSplitDistances()[3]
+ : 0f);
+ final float split4 = (float) (_pssmCam.getSplitDistances().length > 4 ? _pssmCam.getSplitDistances()[4]
+ : 0f);
+
+ GLSLShaderObjectsState currentShader = _drawShaderDebug ? _pssmDebugShader : _pssmShader;
+ if (_drawShaderDebug) {
+ currentShader = _pssmDebugShader;
+ }
+
+ currentShader.setUniform("sampleDist", split1, split2, split3, split4);
+ if (filter == Filter.Pcf) {
+ // TODO
+ // currentShader.setUniform("_shadowSize", 1f / _shadowMapSize);
+ }
+
+ if (!_drawShaderDebug) {
+ currentShader.setUniform("shadowColor", _shadowColor);
+ }
+
+ if (_keepMainShader) {
+ _mainShader.setUniform("sampleDist", split1, split2, split3, split4);
+ if (filter == Filter.Pcf) {
+ // TODO
+ // _mainShader.setUniform("_shadowSize", 1f / _shadowMapSize);
+ }
+
+ if (!_drawShaderDebug) {
+ _mainShader.setUniform("shadowColor", _shadowColor);
+ }
+ }
+ }
+ }
+
+ // TODO
+ final FloatBuffer frustumBoundingBuffer = BufferUtils.createVector3Buffer(8);
+ final BoundingSphere frustumBoundingSphere = new BoundingSphere();
+
+ /**
+ * Calculate optimal light frustum perspective.
+ *
+ * @param frustumCorners
+ * the frustum corners
+ * @param center
+ * the center
+ */
+ private void calculateOptimalLightFrustum(final Vector3[] frustumCorners, final ReadOnlyVector3 centerFrustum) {
+ for (int i = 0; i < 8; i++) {
+ BufferUtils.setInBuffer(frustumCorners[i], frustumBoundingBuffer, i);
+ }
+ frustumBoundingSphere.computeFromPoints(frustumBoundingBuffer);
+
+ final Camera shadowCam = _shadowMapRenderer.getCamera();
+
+ final ReadOnlyVector3 center = frustumBoundingSphere.getCenter();
+ final double radius = frustumBoundingSphere.getRadius();
+
+ Vector3 direction = new Vector3();
+ final DirectionalLight dl = (DirectionalLight) _light;
+ direction = direction.set(dl.getDirection());
+ final double distance = Math.max(radius, _minimumLightDistance);
+
+ final Vector3 tmpVec = Vector3.fetchTempInstance();
+ tmpVec.set(direction);
+ tmpVec.negateLocal();
+ tmpVec.multiplyLocal(distance);
+ tmpVec.addLocal(center);
+
+ // temporary location
+ shadowCam.setLocation(tmpVec);
+ shadowCam.lookAt(center, Vector3.UNIT_Y);
+
+ {
+ // determine
+ final double texelSizeW = (2 * radius) / _shadowMapRenderer.getWidth();
+ final double texelSizeH = (2 * radius) / _shadowMapRenderer.getHeight();
+
+ // build a Quaternion from camera axes to move
+ final Quaternion q = Quaternion.fetchTempInstance();
+ q.fromAxes(shadowCam.getLeft(), shadowCam.getUp(), shadowCam.getDirection());
+
+ // invert to calculate in light space
+ final Vector3 lightSpace = q.invert(null).apply(tmpVec, Vector3.fetchTempInstance());
+
+ // snap to nearest texel
+ lightSpace.setX(lightSpace.getX() - (lightSpace.getX() % texelSizeW));
+ lightSpace.setY(lightSpace.getY() - (lightSpace.getY() % texelSizeH));
+
+ // convert back
+ q.apply(lightSpace, tmpVec);
+ Vector3.releaseTempInstance(lightSpace);
+
+ Quaternion.releaseTempInstance(q);
+ }
+
+ // updated location
+ final double x = tmpVec.getX();
+ final double y = tmpVec.getY();
+ final double z = tmpVec.getZ();
+ final double farZ = tmpVec.subtractLocal(center).length() + radius;
+ Vector3.releaseTempInstance(tmpVec);
+
+ // set frustum, then location
+ shadowCam.setFrustum(1, farZ, -radius, radius, radius, -radius);
+ shadowCam.setLocation(x, y, z);
+ }
+
+ /**
+ * Saving this around until we fully support a good solution for non-directional lights. Like dual paraboloid shadow
+ * maps...
+ *
+ * @param frustumCorners
+ * @param center
+ */
+ private void calculateOptimalLightFrustumOld(final Vector3[] frustumCorners, final ReadOnlyVector3 center) {
+ final Camera shadowCam = _shadowMapRenderer.getCamera();
+
+ double distance = _minimumLightDistance;
+
+ final Vector3 tmpVec = Vector3.fetchTempInstance();
+
+ // Update shadow camera from light
+ final PointLight pl = (PointLight) _light;
+
+ shadowCam.setLocation(pl.getLocation());
+
+ // Point light at split center
+ shadowCam.lookAt(center, Vector3.UNIT_Y);
+
+ // Reset frustum
+ distance = center.subtract(shadowCam.getLocation(), tmpVec).length();
+ shadowCam.setFrustum(1, distance, -1, 1, 1, -1);
+
+ double fMinX = Double.POSITIVE_INFINITY;
+ double fMaxX = Double.NEGATIVE_INFINITY;
+ double fMinY = Double.POSITIVE_INFINITY;
+ double fMaxY = Double.NEGATIVE_INFINITY;
+ double fMinZ = Double.POSITIVE_INFINITY;
+ double fMaxZ = Double.NEGATIVE_INFINITY;
+
+ final ReadOnlyMatrix4 lightviewproj = shadowCam.getModelViewProjectionMatrix();
+
+ final Vector4 position = Vector4.fetchTempInstance();
+ for (final Vector3 frustumCorner : frustumCorners) {
+ position.set(frustumCorner.getX(), frustumCorner.getY(), frustumCorner.getZ(), 1);
+ lightviewproj.applyPre(position, position);
+
+ position.setX(position.getX() / position.getW());
+ position.setY(position.getY() / position.getW());
+ position.setZ(position.getZ());
+
+ fMinX = Math.min(position.getX(), fMinX);
+ fMaxX = Math.max(position.getX(), fMaxX);
+
+ fMinY = Math.min(position.getY(), fMinY);
+ fMaxY = Math.max(position.getY(), fMaxY);
+
+ fMinZ = Math.min(position.getZ(), fMinZ);
+ fMaxZ = Math.max(position.getZ(), fMaxZ);
+ }
+
+ double width = 0;
+ double height = 0;
+ fMinX = clamp(fMinX, -1.0, 1.0);
+ fMaxX = clamp(fMaxX, -1.0, 1.0);
+ fMinY = clamp(fMinY, -1.0, 1.0);
+ fMaxY = clamp(fMaxY, -1.0, 1.0);
+
+ // Make sure the minimum z is at least a specified distance from
+ // the target.
+ fMinZ = Math.min(fMinZ, distance - _minimumLightDistance);
+ fMinZ = Math.max(10.0, fMinZ);
+
+ width = fMinZ * (fMaxX - fMinX) * 0.5;
+ height = fMinZ * (fMaxY - fMinY) * 0.5;
+
+ final Vector3 newCenter = Vector3.fetchTempInstance();
+ position.set((fMinX + fMaxX) * 0.5, (fMinY + fMaxY) * 0.5, 1.0, 1);
+ shadowCam.getModelViewProjectionInverseMatrix().applyPre(position, position);
+ position.divideLocal(position.getW());
+ newCenter.set(position.getX(), position.getY(), position.getZ());
+
+ shadowCam.lookAt(newCenter, Vector3.UNIT_Y);
+
+ Vector3.releaseTempInstance(newCenter);
+ Vector4.releaseTempInstance(position);
+
+ shadowCam.setFrustum(fMinZ, fMaxZ, -width, width, height, -height);
+ shadowCam.update();
+ }
+
+ /**
+ * Render the overlay scene with shadows.
+ *
+ * @param r
+ * The renderer to use
+ */
+ public void renderShadowedScene(final Renderer r) {
+ boolean reset = false;
+ if (_context == null) {
+ _context = ContextManager.getCurrentContext();
+ reset = true;
+ }
+
+ _context.pushEnforcedStates();
+ _context.enforceState(_shadowTextureState);
+ _context.enforceState(_discardShadowFragments);
+
+ if (_pssmShader != null && _context.getCapabilities().isGLSLSupported()) {
+ GLSLShaderObjectsState currentShader = _drawShaderDebug ? _pssmDebugShader : _pssmShader;
+ if (_drawShaderDebug) {
+ currentShader = _pssmDebugShader;
+ }
+ if (_keepMainShader) {
+ currentShader = _mainShader;
+ }
+ _context.enforceState(currentShader);
+ }
+
+ for (final Spatial spat : _spatials) {
+ spat.onDraw(r);
+ }
+ r.renderBuckets();
+
+ _context.popEnforcedStates();
+
+ if (reset) {
+ // _context = null;
+ }
+ }
+
+ private static RenderLogic logic = new RenderLogic() {
+ private CullState cullState;
+ private Face cullFace;
+ private boolean isVisible;
+
+ public void apply(final Renderable renderable) {
+ if (renderable instanceof Mesh) {
+ final Mesh mesh = (Mesh) renderable;
+
+ isVisible = mesh.isVisible();
+ if (!mesh.getSceneHints().isCastsShadows()) {
+ mesh.setVisible(false);
+ }
+
+ cullState = (CullState) mesh.getWorldRenderState(StateType.Cull);
+ if (cullState != null) {
+ cullFace = cullState.getCullFace();
+ if (cullFace != Face.None) {
+ cullState.setCullFace(Face.Front);
+ }
+ }
+ }
+ }
+
+ public void restore(final Renderable renderable) {
+ if (renderable instanceof Mesh) {
+ final Mesh mesh = (Mesh) renderable;
+
+ mesh.setVisible(isVisible);
+
+ if (cullState != null) {
+ cullState.setCullFace(cullFace);
+ }
+ }
+ }
+ };
+
+ /**
+ * Update the shadow map.
+ *
+ * @param index
+ * shadow map texture index to update
+ */
+ private void updateShadowMap(final int index, final Renderer r) {
+
+ if (shadowRenderCallback != null) {
+ shadowRenderCallback.onRender(index, r, this, _shadowMapRenderer.getCamera());
+ }
+
+ r.setRenderLogic(logic);
+ if (!_useSceneTexturing) {
+ Mesh.RENDER_VERTEX_ONLY = true;
+ }
+ _shadowMapRenderer.render(_occluderNodes, _shadowMapTexture[index], Renderer.BUFFER_COLOR_AND_DEPTH);
+ if (!_useSceneTexturing) {
+ Mesh.RENDER_VERTEX_ONLY = false;
+ }
+ r.setRenderLogic(null);
+ }
+
+ /**
+ * Update texture matrix.
+ *
+ * @param index
+ * the index
+ */
+ private void updateTextureMatrix(final int index) {
+ // Create a matrix going from light to camera space
+ final Camera cam = ContextManager.getCurrentContext().getCurrentCamera();
+ _shadowMatrix.set(cam.getModelViewMatrix()).invertLocal();
+ _shadowMatrix.multiplyLocal(_shadowMapRenderer.getCamera().getModelViewProjectionMatrix()).multiplyLocal(
+ SCALE_BIAS_MATRIX);
+ _shadowMapTexture[index].setTextureMatrix(_shadowMatrix);
+ }
+
+ /**
+ * Checks if this pass is initialized.
+ *
+ * @return true, if is initialized
+ */
+ public boolean isInitialised() {
+ return _initialised;
+ }
+
+ /**
+ *
+ * @return the offset state used for drawing the shadow textures.
+ */
+ public OffsetState getShadowOffsetState() {
+ return _shadowOffsetState;
+ }
+
+ /**
+ * Update receiver bounds.
+ */
+ private void updateReceiverBounds() {
+ hasValidBounds = false;
+ boolean firstRun = true;
+
+ for (int i = 0, cSize = _boundsReceiver.size(); i < cSize; i++) {
+ final Spatial child = _boundsReceiver.get(i);
+ if (child != null && child.getWorldBound() != null && boundIsValid(child.getWorldBound())) {
+ if (firstRun) {
+ _receiverBounds.setCenter(child.getWorldBound().getCenter());
+ _receiverBounds.setXExtent(0);
+ _receiverBounds.setYExtent(0);
+ _receiverBounds.setZExtent(0);
+ firstRun = false;
+ }
+ _receiverBounds.mergeLocal(child.getWorldBound());
+ hasValidBounds = true;
+ }
+ }
+
+ for (int i = 0, cSize = _spatials.size(); i < cSize; i++) {
+ final Spatial child = _spatials.get(i);
+ if (child != null && child.getWorldBound() != null && boundIsValid(child.getWorldBound())) {
+ if (firstRun) {
+ _receiverBounds.setCenter(child.getWorldBound().getCenter());
+ _receiverBounds.setXExtent(0);
+ _receiverBounds.setYExtent(0);
+ _receiverBounds.setZExtent(0);
+ firstRun = false;
+ }
+ _receiverBounds.mergeLocal(child.getWorldBound());
+ hasValidBounds = true;
+ }
+ }
+ }
+
+ /**
+ * Checks if a bounding volume is valid.
+ *
+ * @param volume
+ * @return
+ */
+ private boolean boundIsValid(final BoundingVolume volume) {
+ if (!Vector3.isValid(volume.getCenter())) {
+ return false;
+ }
+ switch (volume.getType()) {
+ case AABB: {
+ final BoundingBox vBox = (BoundingBox) volume;
+ return !(Double.isInfinite(vBox.getXExtent()) || Double.isInfinite(vBox.getYExtent())
+ || Double.isInfinite(vBox.getZExtent()) || Double.isNaN(vBox.getXExtent())
+ || Double.isNaN(vBox.getYExtent()) || Double.isNaN(vBox.getZExtent()));
+ }
+
+ case Sphere: {
+ final BoundingSphere vSphere = (BoundingSphere) volume;
+ return !(Double.isInfinite(vSphere.getRadius()) || Double.isNaN(vSphere.getRadius()));
+ }
+
+ case OBB: {
+ final OrientedBoundingBox obb = (OrientedBoundingBox) volume;
+ return Vector3.isValid(obb.getExtent());
+ }
+
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Gets the shadow map texture.
+ *
+ * @param index
+ * the index
+ *
+ * @return the shadow map texture
+ */
+ public Texture2D getShadowMapTexture(final int index) {
+ return _shadowMapTexture[index];
+ }
+
+ /**
+ * Gets the number of splits.
+ *
+ * @return the number of splits
+ */
+ public int getNumOfSplits() {
+ return _numOfSplits;
+ }
+
+ /**
+ * Sets the number of frustum splits and thus the number of shadow textures created by this pass. More splits
+ * creates crisper shadows at the cost of increased texture memory.
+ *
+ * @param numOfSplits
+ * the new number of splits
+ */
+ public void setNumOfSplits(final int numOfSplits) {
+ _numOfSplits = Math.min(Math.max(_MIN_SPLITS, numOfSplits), _MAX_SPLITS);
+ _reinitSplitsDirty = true;
+
+ if (_numOfSplits != numOfSplits) {
+ logger.warning("Valid range for number of splits is " + _MIN_SPLITS + " to " + _MAX_SPLITS
+ + ". Tried to set it to " + numOfSplits);
+ }
+ }
+
+ /**
+ * Gets the shadow map size.
+ *
+ * @return the shadow map size
+ */
+ public int getShadowMapSize() {
+ return _shadowMapSize;
+ }
+
+ /**
+ * Sets the shadow map size.
+ *
+ * @param shadowMapSize
+ * the new shadow map size
+ */
+ public void setShadowMapSize(final int shadowMapSize) {
+ _shadowMapSize = shadowMapSize;
+ _reinitTextureSizeDirty = true;
+ _reinitSplitsDirty = true;
+ }
+
+ /**
+ * Gets the maximum distance for shadowing.
+ *
+ * @return max distance
+ * @see com.ardor3d.extension.shadow.map.PSSMCamera#getMaxFarPlaneDistance()
+ */
+ public double getMaxShadowDistance() {
+ return _pssmCam.getMaxFarPlaneDistance();
+ }
+
+ /**
+ * Sets the maximum distance for shadowing.
+ *
+ * @param maxShadowDistance
+ * distance to set
+ * @see com.ardor3d.extension.shadow.map.PSSMCamera#setMaxFarPlaneDistance(double)
+ */
+ public void setMaxShadowDistance(final double maxShadowDistance) {
+ _pssmCam.setMaxFarPlaneDistance(maxShadowDistance);
+ }
+
+ /**
+ * Gets the minimum z distance for the light.
+ *
+ * @return the minimumLightDistance
+ */
+ public double getMinimumLightDistance() {
+ return _minimumLightDistance;
+ }
+
+ /**
+ * Sets the minimum z distance for the light.
+ *
+ * @param minimumLightDistance
+ * the minimumLightDistance to set
+ */
+ public void setMinimumLightDistance(final double minimumLightDistance) {
+ _minimumLightDistance = minimumLightDistance;
+ }
+
+ /**
+ * Gets shadow color and transparency.
+ *
+ * @return the shadowColor
+ */
+ public ReadOnlyColorRGBA getShadowColor() {
+ return _shadowColor;
+ }
+
+ /**
+ * Sets shadow color and transparency.
+ *
+ * @param shadowColor
+ * the shadowColor to set
+ */
+ public void setShadowColor(final ReadOnlyColorRGBA shadowColor) {
+ _shadowColor.set(shadowColor);
+ }
+
+ public ShadowRenderCallback getShadowRenderCallback() {
+ return shadowRenderCallback;
+ }
+
+ public void setShadowRenderCallback(final ShadowRenderCallback callback) {
+ shadowRenderCallback = callback;
+ }
+
+ /**
+ * Clean up.
+ *
+ * @see com.ardor3d.renderer.pass.Pass#cleanUp()
+ */
+ @Override
+ public void cleanUp() {
+ super.cleanUp();
+
+ if (_shadowMapRenderer != null) {
+ _shadowMapRenderer.cleanup();
+ }
+ }
+
+ /**
+ * Remove the contents of the pass.
+ */
+ public void clear() {
+ _occluderNodes.clear();
+ _spatials.clear();
+ }
+
+ /**
+ * Simple clamp.
+ *
+ * @param val
+ * value to clamp
+ * @param from
+ * minimum value after clamping
+ * @param to
+ * maximum value after clamping
+ * @return Math.min(to, Math.max(from, val))
+ */
+ private double clamp(final double val, final double from, final double to) {
+ return Math.min(to, Math.max(from, val));
+ }
+
+ /**
+ * @return the updateMainCamera
+ */
+ public boolean isUpdateMainCamera() {
+ return _updateMainCamera;
+ }
+
+ /**
+ * @param updateMainCamera
+ * True (the default) if we want to copy the current rendering camera into this pass for use in shadow
+ * generation. False if we will manage our shadow camera elsewhere.
+ * @see #getPssmCam()
+ */
+ public void setUpdateMainCamera(final boolean updateMainCamera) {
+ _updateMainCamera = updateMainCamera;
+ }
+
+ /**
+ * @return the drawDebug
+ */
+ public boolean isDrawDebug() {
+ return _drawDebug;
+ }
+
+ /**
+ * @param drawDebug
+ * True if we want to draw camera and light frustums for debugging purposes. Default is false.
+ */
+ public void setDrawDebug(final boolean drawDebug) {
+ _drawDebug = drawDebug;
+ }
+
+ /**
+ * @return the drawShaderDebug
+ */
+ public boolean isDrawShaderDebug() {
+ return _drawShaderDebug;
+ }
+
+ /**
+ * @param drawShaderDebug
+ * True if we want to draw debug colors over the shadows, showing which level they come from.
+ */
+ public void setDrawShaderDebug(final boolean drawShaderDebug) {
+ _drawShaderDebug = drawShaderDebug;
+ }
+
+ /**
+ * @return the useSceneTexturing
+ */
+ public boolean isUseSceneTexturing() {
+ return _useSceneTexturing;
+ }
+
+ /**
+ * @param useSceneTexturing
+ * True if we want to factor in texturing to shadows; useful for casting shadows against alpha-tested
+ * textures. Default is false.
+ */
+ public void setUseSceneTexturing(final boolean useSceneTexturing) {
+ _useSceneTexturing = useSceneTexturing;
+ if (_shadowMapRenderer != null) {
+ if (!_useSceneTexturing) {
+ _shadowMapRenderer.enforceState(_noTexture);
+ } else {
+ _shadowMapRenderer.clearEnforcedState(RenderState.StateType.Texture);
+ }
+ }
+
+ }
+
+ public boolean isUseObjectCullFace() {
+ return _useObjectCullFace;
+ }
+
+ /**
+ * @param useObjectCullFace
+ * True if we want to use the culling set on the objects instead of always culling front face (which is
+ * done for shadow precision). Default is false.
+ */
+ public void setUseObjectCullFace(final boolean useObjectCullFace) {
+ _useObjectCullFace = useObjectCullFace;
+ if (_shadowMapRenderer != null) {
+ if (!_useObjectCullFace) {
+ _shadowMapRenderer.enforceState(_cullFrontFace);
+ } else {
+ _shadowMapRenderer.clearEnforcedState(StateType.Cull);
+ }
+ }
+ }
+
+ public boolean isRenderShadowedScene() {
+ return _renderShadowedScene;
+ }
+
+ /**
+ * @param renderShadowedScene
+ * When true (the default) the generated shadow map textures are drawn over the scene in a separate blend
+ * pass. If false, the shadows are generated, but not applied.
+ */
+ public void setRenderShadowedScene(final boolean renderShadowedScene) {
+ _renderShadowedScene = renderShadowedScene;
+ }
+
+ /**
+ * @return the camera used internally to generate shadows.
+ */
+ public PSSMCamera getPssmCam() {
+ return _pssmCam;
+ }
+
+ /**
+ * @return the texture store format to use for the shadow textures on the next call to init/setNumOfSplits.
+ */
+ public TextureStoreFormat getShadowTextureStoreFormat() {
+ return _shadowTextureStoreFormat;
+ }
+
+ /**
+ * @param shadowTextureStoreFormat
+ * - the texture store format to use for the shadow textures. Only has an affect if called prior to
+ * calling init on this pass (or if called before calling {@link #setNumOfSplits(int)}).
+ */
+ public void setShadowTextureStoreFormat(final TextureStoreFormat shadowTextureStoreFormat) {
+ _shadowTextureStoreFormat = shadowTextureStoreFormat;
+ }
+
+ /** The debug line frustum. */
+ private static Line lineFrustum;
+
+ /** The debug test cam. */
+ private static final PSSMCamera testCam = new PSSMCamera();
+
+ /** Debug bounding sphere */
+ private static final Sphere boundingSphere = new Sphere("bsphere", 10, 10, 1);
+ static {
+ boundingSphere.getSceneHints().setRenderBucketType(RenderBucketType.Skip);
+ boundingSphere.setRenderState(new WireframeState());
+ boundingSphere.setRenderState(new ZBufferState());
+ boundingSphere.updateWorldRenderStates(false);
+ }
+
+ /**
+ * Draw debug frustum.
+ *
+ * @param r
+ * the r
+ * @param cam
+ * the cam
+ * @param color
+ * the color
+ * @param drawOriginConnector
+ * whether or not to draw a connector
+ */
+ private static void drawFrustum(final Renderer r, final Camera cam, final ReadOnlyColorRGBA color,
+ final short pattern, final boolean drawOriginConnector) {
+ drawFrustum(r, cam, cam.getFrustumNear(), cam.getFrustumFar(), color, pattern, drawOriginConnector);
+ }
+
+ /**
+ * Draw debug frustum.
+ *
+ * @param r
+ * the r
+ * @param cam
+ * the cam
+ * @param fNear
+ * the f near
+ * @param fFar
+ * the f far
+ * @param color
+ * the color
+ * @param drawOriginConnector
+ * whether or not to draw a connector
+ */
+ private static void drawFrustum(final Renderer r, final Camera cam, final double fNear, final double fFar,
+ final ReadOnlyColorRGBA color, final short pattern, final boolean drawOriginConnector) {
+ if (lineFrustum == null) {
+ final FloatBuffer verts = BufferUtils.createVector3Buffer(24);
+ final FloatBuffer colors = BufferUtils.createColorBuffer(24);
+
+ lineFrustum = new Line("Lines", verts, null, colors, null);
+ lineFrustum.getMeshData().setIndexModes(
+ new IndexMode[] { IndexMode.LineLoop, IndexMode.LineLoop, IndexMode.Lines, IndexMode.Lines });
+ lineFrustum.getMeshData().setIndexLengths(new int[] { 4, 4, 8, 8 });
+ lineFrustum.setLineWidth(2);
+ lineFrustum.getSceneHints().setLightCombineMode(LightCombineMode.Off);
+
+ final BlendState lineBlendState = new BlendState();
+ lineBlendState.setEnabled(true);
+ lineBlendState.setBlendEnabled(true);
+ lineBlendState.setTestEnabled(true);
+ lineBlendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
+ lineBlendState.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
+ lineFrustum.setRenderState(lineBlendState);
+
+ final ZBufferState zstate = new ZBufferState();
+ lineFrustum.setRenderState(zstate);
+ lineFrustum.updateGeometricState(0.0);
+
+ lineFrustum.getSceneHints().setRenderBucketType(RenderBucketType.Skip);
+ }
+
+ lineFrustum.setDefaultColor(color);
+ lineFrustum.setStipplePattern(pattern);
+
+ testCam.set(cam);
+ testCam.update();
+ testCam.calculateFrustum(fNear, fFar);
+
+ final FloatBuffer colors = lineFrustum.getMeshData().getColorBuffer();
+ for (int i = 0; i < 16; i++) {
+ BufferUtils.setInBuffer(color, colors, i);
+ }
+ final float alpha = drawOriginConnector ? 0.4f : 0.0f;
+ for (int i = 16; i < 24; i++) {
+ colors.position(i * 4);
+ colors.put(color.getRed());
+ colors.put(color.getGreen());
+ colors.put(color.getBlue());
+ colors.put(alpha);
+ }
+
+ final FloatBuffer verts = lineFrustum.getMeshData().getVertexBuffer();
+ BufferUtils.setInBuffer(testCam._corners[0], verts, 0);
+ BufferUtils.setInBuffer(testCam._corners[1], verts, 1);
+ BufferUtils.setInBuffer(testCam._corners[2], verts, 2);
+ BufferUtils.setInBuffer(testCam._corners[3], verts, 3);
+
+ BufferUtils.setInBuffer(testCam._corners[4], verts, 4);
+ BufferUtils.setInBuffer(testCam._corners[5], verts, 5);
+ BufferUtils.setInBuffer(testCam._corners[6], verts, 6);
+ BufferUtils.setInBuffer(testCam._corners[7], verts, 7);
+
+ BufferUtils.setInBuffer(testCam._corners[0], verts, 8);
+ BufferUtils.setInBuffer(testCam._corners[4], verts, 9);
+ BufferUtils.setInBuffer(testCam._corners[1], verts, 10);
+ BufferUtils.setInBuffer(testCam._corners[5], verts, 11);
+ BufferUtils.setInBuffer(testCam._corners[2], verts, 12);
+ BufferUtils.setInBuffer(testCam._corners[6], verts, 13);
+ BufferUtils.setInBuffer(testCam._corners[3], verts, 14);
+ BufferUtils.setInBuffer(testCam._corners[7], verts, 15);
+
+ BufferUtils.setInBuffer(testCam.getLocation(), verts, 16);
+ BufferUtils.setInBuffer(testCam._corners[0], verts, 17);
+ BufferUtils.setInBuffer(testCam.getLocation(), verts, 18);
+ BufferUtils.setInBuffer(testCam._corners[1], verts, 19);
+ BufferUtils.setInBuffer(testCam.getLocation(), verts, 20);
+ BufferUtils.setInBuffer(testCam._corners[2], verts, 21);
+ BufferUtils.setInBuffer(testCam.getLocation(), verts, 22);
+ BufferUtils.setInBuffer(testCam._corners[3], verts, 23);
+
+ lineFrustum.draw(r);
+ }
+
+ public void setPssmShader(final GLSLShaderObjectsState pssmShader) {
+ _pssmShader = pssmShader;
+ }
+
+ public boolean isKeepMainShader() {
+ return _keepMainShader;
+ }
+
+ public void setKeepMainShader(final boolean keepMainShader) {
+ _keepMainShader = keepMainShader;
+ }
+
+ public void addBoundsReceiver(final Spatial spatial) {
+ _boundsReceiver.add(spatial);
+ }
+
+ public void setFiltering(final Filter filter) {
+ this.filter = filter;
+ }
+
+ public BlendState getDiscardShadowFragmentsBlendState() {
+ return _discardShadowFragments;
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ShadowRenderCallback.java b/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ShadowRenderCallback.java
index 931f3ca..0d3bc5d 100644
--- a/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ShadowRenderCallback.java
+++ b/ardor3d-effects/src/main/java/com/ardor3d/extension/shadow/map/ShadowRenderCallback.java
@@ -1,20 +1,20 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.shadow.map;
-
-import com.ardor3d.renderer.Camera;
-import com.ardor3d.renderer.Renderer;
-
-public interface ShadowRenderCallback {
-
- void onRender(int splitIndex, Renderer renderer, ParallelSplitShadowMapPass pass, Camera renderCamera);
-
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.shadow.map;
+
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Renderer;
+
+public interface ShadowRenderCallback {
+
+ void onRender(int splitIndex, Renderer renderer, ParallelSplitShadowMapPass pass, Camera renderCamera);
+
+}
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/add2textures.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/add2textures.frag
index e88109e..52ec17d 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/add2textures.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/add2textures.frag
@@ -1,21 +1,21 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform sampler2D tex1;
-uniform sampler2D tex2;
-
-varying vec2 texCoord;
-
-void main(void) {
- vec4 color1 = texture2D(tex1, texCoord);
- vec4 color2 = texture2D(tex2, texCoord);
-
- gl_FragColor = vec4(color1.rgb + color2.rgb, min(color1.a + color2.a, 1.0));
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+
+varying vec2 texCoord;
+
+void main(void) {
+ vec4 color1 = texture2D(tex1, texCoord);
+ vec4 color2 = texture2D(tex2, texCoord);
+
+ gl_FragColor = vec4(color1.rgb + color2.rgb, min(color1.a + color2.a, 1.0));
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.frag
index 09ec326..c42d1e1 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.frag
@@ -1,74 +1,74 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform float blurIntensityMultiplier;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec2 samples00 = vec2(-0.326212, -0.405805);
- vec2 samples01 = vec2(-0.840144, -0.073580);
- vec2 samples02 = vec2(-0.695914, 0.457137);
- vec2 samples03 = vec2(-0.203345, 0.620716);
- vec2 samples04 = vec2( 0.962340, -0.194983);
- vec2 samples05 = vec2( 0.473434, -0.480026);
- vec2 samples06 = vec2( 0.519456, 0.767022);
- vec2 samples07 = vec2( 0.185461, -0.893124);
- vec2 samples08 = vec2( 0.507431, 0.064425);
- vec2 samples09 = vec2( 0.896420, 0.412458);
- vec2 samples10 = vec2(-0.321940, -0.932615);
- vec2 samples11 = vec2(-0.791559, -0.597705);
-
- vec2 newCoord;
- vec4 sum = texture2D(RT, texCoord);
-
- newCoord = texCoord + sampleDist * samples00;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples01;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples02;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples03;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples04;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples05;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples06;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples07;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples08;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples09;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples10;
- sum += texture2D(RT, newCoord);
-
- newCoord = texCoord + sampleDist * samples11;
- sum += texture2D(RT, newCoord);
-
- sum /= 13.0;
- sum *= blurIntensityMultiplier;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform float blurIntensityMultiplier;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec2 samples00 = vec2(-0.326212, -0.405805);
+ vec2 samples01 = vec2(-0.840144, -0.073580);
+ vec2 samples02 = vec2(-0.695914, 0.457137);
+ vec2 samples03 = vec2(-0.203345, 0.620716);
+ vec2 samples04 = vec2( 0.962340, -0.194983);
+ vec2 samples05 = vec2( 0.473434, -0.480026);
+ vec2 samples06 = vec2( 0.519456, 0.767022);
+ vec2 samples07 = vec2( 0.185461, -0.893124);
+ vec2 samples08 = vec2( 0.507431, 0.064425);
+ vec2 samples09 = vec2( 0.896420, 0.412458);
+ vec2 samples10 = vec2(-0.321940, -0.932615);
+ vec2 samples11 = vec2(-0.791559, -0.597705);
+
+ vec2 newCoord;
+ vec4 sum = texture2D(RT, texCoord);
+
+ newCoord = texCoord + sampleDist * samples00;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples01;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples02;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples03;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples04;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples05;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples06;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples07;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples08;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples09;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples10;
+ sum += texture2D(RT, newCoord);
+
+ newCoord = texCoord + sampleDist * samples11;
+ sum += texture2D(RT, newCoord);
+
+ sum /= 13.0;
+ sum *= blurIntensityMultiplier;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.vert
index 02bda22..3e8fc35 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur.vert
@@ -1,19 +1,19 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 texCoord;
-
-void main(void)
-{
- vec2 Pos = sign(gl_Vertex.xy);
- gl_Position = vec4(Pos.xy, 0, 1);
- texCoord.x = 0.5 * (1.0 + Pos.x);
- texCoord.y = 0.5 * (1.0 + Pos.y);
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec2 Pos = sign(gl_Vertex.xy);
+ gl_Position = vec4(Pos.xy, 0, 1);
+ texCoord.x = 0.5 * (1.0 + Pos.x);
+ texCoord.y = 0.5 * (1.0 + Pos.y);
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal5.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal5.frag
index bb8d7db..d1f3aa1 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal5.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal5.frag
@@ -1,26 +1,26 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 1.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.5*sampleDist, texCoord.y)) * 2.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 3.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.5*sampleDist, texCoord.y)) * 2.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 1.0/9.0;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 1.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.5*sampleDist, texCoord.y)) * 2.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 3.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.5*sampleDist, texCoord.y)) * 2.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 1.0/9.0;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal7.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal7.frag
index 6ee9508..8cdcb5c 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal7.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal7.frag
@@ -1,28 +1,28 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 0.25/4.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.666*sampleDist, texCoord.y)) * 0.5/4.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.333*sampleDist, texCoord.y)) * 0.75/4.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 1.0/4.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.333*sampleDist, texCoord.y)) * 0.75/4.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.666*sampleDist, texCoord.y)) * 0.5/4.0;
- sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 0.25/4.0;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 0.25/4.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.666*sampleDist, texCoord.y)) * 0.5/4.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.333*sampleDist, texCoord.y)) * 0.75/4.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 1.0/4.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.333*sampleDist, texCoord.y)) * 0.75/4.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.666*sampleDist, texCoord.y)) * 0.5/4.0;
+ sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 0.25/4.0;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal9.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal9.frag
index d447dfa..c6acf9d 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal9.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_horizontal9.frag
@@ -1,30 +1,30 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 1.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.75*sampleDist, texCoord.y)) * 2.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.5*sampleDist, texCoord.y)) * 3.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x - 0.25*sampleDist, texCoord.y)) * 4.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 5.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.25*sampleDist, texCoord.y)) * 4.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.5*sampleDist, texCoord.y)) * 3.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x + 0.75*sampleDist, texCoord.y)) * 2.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 1.0/25.0;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x - 1.0*sampleDist, texCoord.y)) * 1.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.75*sampleDist, texCoord.y)) * 2.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.5*sampleDist, texCoord.y)) * 3.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x - 0.25*sampleDist, texCoord.y)) * 4.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 5.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.25*sampleDist, texCoord.y)) * 4.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.5*sampleDist, texCoord.y)) * 3.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x + 0.75*sampleDist, texCoord.y)) * 2.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x + 1.0*sampleDist, texCoord.y)) * 1.0/25.0;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5.frag
index ca44225..61a0eb4 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5.frag
@@ -1,29 +1,29 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform float blurIntensityMultiplier;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.5*sampleDist)) * 2.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 3.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.5*sampleDist)) * 2.0/9.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/9.0;
-
- sum *= blurIntensityMultiplier;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform float blurIntensityMultiplier;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.5*sampleDist)) * 2.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 3.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.5*sampleDist)) * 2.0/9.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/9.0;
+
+ sum *= blurIntensityMultiplier;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag
index 08f7fa1..48cf7f4 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical5_down.frag
@@ -1,26 +1,26 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 6.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 4.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 2.0*sampleDist)) * 3.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 3.0*sampleDist)) * 2.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 4.0*sampleDist)) * 1.0/16.0;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 6.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 4.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 2.0*sampleDist)) * 3.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 3.0*sampleDist)) * 2.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 4.0*sampleDist)) * 1.0/16.0;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical7.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical7.frag
index 385afc8..f0103c5 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical7.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical7.frag
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform float blurIntensityMultiplier;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.666*sampleDist)) * 2.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.333*sampleDist)) * 3.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 4.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.333*sampleDist)) * 3.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.666*sampleDist)) * 2.0/16.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/16.0;
-
- sum *= blurIntensityMultiplier;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform float blurIntensityMultiplier;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.666*sampleDist)) * 2.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.333*sampleDist)) * 3.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 4.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.333*sampleDist)) * 3.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.666*sampleDist)) * 2.0/16.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/16.0;
+
+ sum *= blurIntensityMultiplier;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical9.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical9.frag
index 55fbf26..cdd819c 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical9.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_blur_vertical9.frag
@@ -1,33 +1,33 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float sampleDist;
-uniform float blurIntensityMultiplier;
-uniform sampler2D RT;
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.75*sampleDist)) * 2.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.5*sampleDist)) * 3.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.25*sampleDist)) * 4.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 5.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.25*sampleDist)) * 4.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.5*sampleDist)) * 3.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.75*sampleDist)) * 2.0/25.0;
- sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/25.0;
-
- sum *= blurIntensityMultiplier;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float sampleDist;
+uniform float blurIntensityMultiplier;
+uniform sampler2D RT;
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 1.0*sampleDist)) * 1.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.75*sampleDist)) * 2.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.5*sampleDist)) * 3.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y - 0.25*sampleDist)) * 4.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y)) * 5.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.25*sampleDist)) * 4.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.5*sampleDist)) * 3.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 0.75*sampleDist)) * 2.0/25.0;
+ sum += texture2D(RT, vec2(texCoord.x, texCoord.y + 1.0*sampleDist)) * 1.0/25.0;
+
+ sum *= blurIntensityMultiplier;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.frag
index 88e4630..a64c171 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.frag
@@ -1,25 +1,25 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform float exposurePow;
-uniform float exposureCutoff;
-uniform sampler2D RT;
-
-varying vec2 vTexCoord;
-
-void main(void)
-{
- vec4 sum = texture2D(RT, vTexCoord);
- if ( (sum.r+sum.g+sum.b)/3.0 < exposureCutoff ) {
- sum = vec4(0.0);
- }
- sum = pow(sum,vec4(exposurePow));
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform float exposurePow;
+uniform float exposureCutoff;
+uniform sampler2D RT;
+
+varying vec2 vTexCoord;
+
+void main(void)
+{
+ vec4 sum = texture2D(RT, vTexCoord);
+ if ( (sum.r+sum.g+sum.b)/3.0 < exposureCutoff ) {
+ sum = vec4(0.0);
+ }
+ sum = pow(sum,vec4(exposurePow));
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.vert
index 1ed3f16..499ee56 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_extract.vert
@@ -1,19 +1,19 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 vTexCoord;
-
-void main(void)
-{
- vec2 Pos = sign(gl_Vertex.xy);
- gl_Position = vec4(Pos.xy, 0, 1);
- vTexCoord.x = 0.5 * (1.0 + Pos.x);
- vTexCoord.y = 0.5 * (1.0 + Pos.y);
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 vTexCoord;
+
+void main(void)
+{
+ vec2 Pos = sign(gl_Vertex.xy);
+ gl_Position = vec4(Pos.xy, 0, 1);
+ vTexCoord.x = 0.5 * (1.0 + Pos.x);
+ vTexCoord.y = 0.5 * (1.0 + Pos.y);
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.frag
index e33042b..7f1c2e0 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.frag
@@ -1,18 +1,18 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform sampler2D RT;
-
-varying vec2 vTexCoord;
-
-void main(void)
-{
- gl_FragColor = texture2D(RT, vTexCoord);
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform sampler2D RT;
+
+varying vec2 vTexCoord;
+
+void main(void)
+{
+ gl_FragColor = texture2D(RT, vTexCoord);
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.vert
index 1ed3f16..499ee56 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom/bloom_final.vert
@@ -1,19 +1,19 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 vTexCoord;
-
-void main(void)
-{
- vec2 Pos = sign(gl_Vertex.xy);
- gl_Position = vec4(Pos.xy, 0, 1);
- vTexCoord.x = 0.5 * (1.0 + Pos.x);
- vTexCoord.y = 0.5 * (1.0 + Pos.y);
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 vTexCoord;
+
+void main(void)
+{
+ vec2 Pos = sign(gl_Vertex.xy);
+ gl_Position = vec4(Pos.xy, 0, 1);
+ vTexCoord.x = 0.5 * (1.0 + Pos.x);
+ vTexCoord.y = 0.5 * (1.0 + Pos.y);
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom_extract.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom_extract.frag
index 42ccb9c..1a947e2 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom_extract.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/bloom_extract.frag
@@ -1,26 +1,26 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform sampler2D inputTex;
-uniform float exposureIntensity;
-uniform float exposureCutoff;
-
-varying vec2 texCoord;
-
-void main(void) {
- vec4 color = texture2D(inputTex, texCoord);
- float lum = dot(vec3(0.3086, 0.6094, 0.0820), color.rgb);
-
- if (lum < exposureCutoff ) {
- color = vec4(0.0, 0.0, 0.0, color.a);
- }
-
- gl_FragColor = vec4(color.rgb * exposureIntensity, color.a);
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform sampler2D inputTex;
+uniform float exposureIntensity;
+uniform float exposureCutoff;
+
+varying vec2 texCoord;
+
+void main(void) {
+ vec4 color = texture2D(inputTex, texCoord);
+ float lum = dot(vec3(0.3086, 0.6094, 0.0820), color.rgb);
+
+ if (lum < exposureCutoff ) {
+ color = vec4(0.0, 0.0, 0.0, color.a);
+ }
+
+ gl_FragColor = vec4(color.rgb * exposureIntensity, color.a);
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_horizontal9.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_horizontal9.frag
index 4ed36dc..c7df3be 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_horizontal9.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_horizontal9.frag
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform sampler2D inputTex;
-uniform float sampleDist;
-
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(inputTex, vec2(texCoord.x - 1.0 * sampleDist, texCoord.y)) * 0.04;
- sum += texture2D(inputTex, vec2(texCoord.x - 0.75 * sampleDist, texCoord.y)) * 0.08;
- sum += texture2D(inputTex, vec2(texCoord.x - 0.5 * sampleDist, texCoord.y)) * 0.12;
- sum += texture2D(inputTex, vec2(texCoord.x - 0.25 * sampleDist, texCoord.y)) * 0.16;
- sum += texture2D(inputTex, vec2(texCoord.x , texCoord.y)) * 0.20;
- sum += texture2D(inputTex, vec2(texCoord.x + 0.25 * sampleDist, texCoord.y)) * 0.16;
- sum += texture2D(inputTex, vec2(texCoord.x + 0.5 * sampleDist, texCoord.y)) * 0.12;
- sum += texture2D(inputTex, vec2(texCoord.x + 0.75 * sampleDist, texCoord.y)) * 0.08;
- sum += texture2D(inputTex, vec2(texCoord.x + 1.0 * sampleDist, texCoord.y)) * 0.04;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform sampler2D inputTex;
+uniform float sampleDist;
+
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(inputTex, vec2(texCoord.x - 1.0 * sampleDist, texCoord.y)) * 0.04;
+ sum += texture2D(inputTex, vec2(texCoord.x - 0.75 * sampleDist, texCoord.y)) * 0.08;
+ sum += texture2D(inputTex, vec2(texCoord.x - 0.5 * sampleDist, texCoord.y)) * 0.12;
+ sum += texture2D(inputTex, vec2(texCoord.x - 0.25 * sampleDist, texCoord.y)) * 0.16;
+ sum += texture2D(inputTex, vec2(texCoord.x , texCoord.y)) * 0.20;
+ sum += texture2D(inputTex, vec2(texCoord.x + 0.25 * sampleDist, texCoord.y)) * 0.16;
+ sum += texture2D(inputTex, vec2(texCoord.x + 0.5 * sampleDist, texCoord.y)) * 0.12;
+ sum += texture2D(inputTex, vec2(texCoord.x + 0.75 * sampleDist, texCoord.y)) * 0.08;
+ sum += texture2D(inputTex, vec2(texCoord.x + 1.0 * sampleDist, texCoord.y)) * 0.04;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_vertical9.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_vertical9.frag
index 73b3472..5640e04 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_vertical9.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/gausian_blur_vertical9.frag
@@ -1,31 +1,31 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-uniform sampler2D inputTex;
-uniform float sampleDist;
-
-varying vec2 texCoord;
-
-void main(void)
-{
- vec4 sum = vec4(0.0);
-
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 1.0 * sampleDist)) * 0.04;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.75 * sampleDist)) * 0.08;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.5 * sampleDist)) * 0.12;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.25 * sampleDist)) * 0.16;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y )) * 0.20;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.25 * sampleDist)) * 0.16;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.5 * sampleDist)) * 0.12;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.75 * sampleDist)) * 0.08;
- sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 1.0 * sampleDist)) * 0.04;
-
- gl_FragColor = sum;
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+uniform sampler2D inputTex;
+uniform float sampleDist;
+
+varying vec2 texCoord;
+
+void main(void)
+{
+ vec4 sum = vec4(0.0);
+
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 1.0 * sampleDist)) * 0.04;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.75 * sampleDist)) * 0.08;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.5 * sampleDist)) * 0.12;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y - 0.25 * sampleDist)) * 0.16;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y )) * 0.20;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.25 * sampleDist)) * 0.16;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.5 * sampleDist)) * 0.12;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 0.75 * sampleDist)) * 0.08;
+ sum += texture2D(inputTex, vec2(texCoord.x, texCoord.y + 1.0 * sampleDist)) * 0.04;
+
+ gl_FragColor = sum;
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.frag
index 9e268fb..93ded63 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.frag
@@ -1,77 +1,77 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-
-uniform sampler2D normalMap;
-uniform sampler2D reflection;
-uniform sampler2D dudvMap;
-
-uniform vec4 waterColor;
-uniform vec4 waterColorEnd;
-uniform bool abovewater;
-uniform bool useFadeToFogColor;
-//uniform float dudvPower; //0.005
-//uniform float dudvColorPower; //0.01
-//uniform float normalPower; //0.5
-//uniform float normalOffsetPower; //0.6
-
-void main()
-{
- float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
-
- vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
- vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
- dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
-
- vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
- normalVector = normalVector * 2.0 - 1.0;
- normalVector = normalize(normalVector);
- normalVector.xy *= 0.5;
-
- vec3 localView = normalize(viewTangetSpace);
- float fresnel = dot(normalVector, localView);
- if ( abovewater == false ) {
- fresnel = -fresnel;
- }
- fresnel *= 1.0 - fogDist;
- float fresnelTerm = 1.0 - fresnel;
- fresnelTerm *= fresnelTerm;
- fresnelTerm = fresnelTerm * 0.9 + 0.1;
-
- vec2 projCoord = viewCoords.xy / viewCoords.q;
- projCoord = (projCoord + 1.0) * 0.5;
- if ( abovewater == true ) {
- projCoord.x = 1.0 - projCoord.x;
- }
-
- projCoord += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoord = clamp(projCoord, 0.001, 0.999);
-
- vec4 reflectionColor = texture2D(reflection, projCoord);
- if ( abovewater == false ) {
- reflectionColor *= vec4(0.8,0.9,1.0,1.0);
- vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
- gl_FragColor = mix(endColor,waterColor,fogDist);
- }
- else {
- vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
- vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
-
- if( useFadeToFogColor == false) {
- gl_FragColor = mix(endColor,reflectionColor,fogDist);
- } else {
- gl_FragColor = mix(endColor,reflectionColor,fogDist) * (1.0-fogDist) + gl_Fog.color * fogDist;
- }
- }
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+
+uniform sampler2D normalMap;
+uniform sampler2D reflection;
+uniform sampler2D dudvMap;
+
+uniform vec4 waterColor;
+uniform vec4 waterColorEnd;
+uniform bool abovewater;
+uniform bool useFadeToFogColor;
+//uniform float dudvPower; //0.005
+//uniform float dudvColorPower; //0.01
+//uniform float normalPower; //0.5
+//uniform float normalOffsetPower; //0.6
+
+void main()
+{
+ float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
+
+ vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
+ vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
+ dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
+
+ vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
+ normalVector = normalVector * 2.0 - 1.0;
+ normalVector = normalize(normalVector);
+ normalVector.xy *= 0.5;
+
+ vec3 localView = normalize(viewTangetSpace);
+ float fresnel = dot(normalVector, localView);
+ if ( abovewater == false ) {
+ fresnel = -fresnel;
+ }
+ fresnel *= 1.0 - fogDist;
+ float fresnelTerm = 1.0 - fresnel;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm = fresnelTerm * 0.9 + 0.1;
+
+ vec2 projCoord = viewCoords.xy / viewCoords.q;
+ projCoord = (projCoord + 1.0) * 0.5;
+ if ( abovewater == true ) {
+ projCoord.x = 1.0 - projCoord.x;
+ }
+
+ projCoord += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoord = clamp(projCoord, 0.001, 0.999);
+
+ vec4 reflectionColor = texture2D(reflection, projCoord);
+ if ( abovewater == false ) {
+ reflectionColor *= vec4(0.8,0.9,1.0,1.0);
+ vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
+ gl_FragColor = mix(endColor,waterColor,fogDist);
+ }
+ else {
+ vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
+ vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
+
+ if( useFadeToFogColor == false) {
+ gl_FragColor = mix(endColor,reflectionColor,fogDist);
+ } else {
+ gl_FragColor = mix(endColor,reflectionColor,fogDist) * (1.0-fogDist) + gl_Fog.color * fogDist;
+ }
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.vert
index 62d4f91..75296f2 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader.vert
@@ -1,49 +1,49 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-
-//uniform vec3 cameraPos;
-uniform vec3 tangent;
-uniform vec3 binormal;
-uniform float normalTranslation, refractionTranslation;
-
-void main()
-{
- // Because we have a flat plane for water we already know the vectors for tangent space
-// vec3 normal = gl_Normal;
- vec3 normal = gl_NormalMatrix * gl_Normal;
- normal = normalize(normal);
- vec3 tangent2 = gl_NormalMatrix * tangent;
- tangent2 = normalize(tangent2);
- vec3 binormal2 = gl_NormalMatrix * binormal;
- binormal2 = normalize(binormal2);
-
- // Calculate the vector coming from the vertex to the camera
-// vec3 viewDir = cameraPos - gl_Vertex.xyz;
- vec4 v = gl_ModelViewMatrix * gl_Vertex;
- vec3 viewDir = -(v.xyz/v.w);
- viewDir = normalize(viewDir);
-
- // Compute tangent space for the view direction
- viewTangetSpace.x = dot(viewDir, tangent2);
- viewTangetSpace.y = dot(viewDir, binormal2);
- viewTangetSpace.z = dot(viewDir, normal);
-
- refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
- normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
-
- // This calculates our current projection coordinates
- viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
- gl_Position = viewCoords;
-}
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+
+//uniform vec3 cameraPos;
+uniform vec3 tangent;
+uniform vec3 binormal;
+uniform float normalTranslation, refractionTranslation;
+
+void main()
+{
+ // Because we have a flat plane for water we already know the vectors for tangent space
+// vec3 normal = gl_Normal;
+ vec3 normal = gl_NormalMatrix * gl_Normal;
+ normal = normalize(normal);
+ vec3 tangent2 = gl_NormalMatrix * tangent;
+ tangent2 = normalize(tangent2);
+ vec3 binormal2 = gl_NormalMatrix * binormal;
+ binormal2 = normalize(binormal2);
+
+ // Calculate the vector coming from the vertex to the camera
+// vec3 viewDir = cameraPos - gl_Vertex.xyz;
+ vec4 v = gl_ModelViewMatrix * gl_Vertex;
+ vec3 viewDir = -(v.xyz/v.w);
+ viewDir = normalize(viewDir);
+
+ // Compute tangent space for the view direction
+ viewTangetSpace.x = dot(viewDir, tangent2);
+ viewTangetSpace.y = dot(viewDir, binormal2);
+ viewTangetSpace.z = dot(viewDir, normal);
+
+ refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
+ normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
+
+ // This calculates our current projection coordinates
+ viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_Position = viewCoords;
+}
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.frag
index 039a30d..ffbed26 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.frag
@@ -1,89 +1,89 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-
-uniform sampler2D normalMap;
-uniform sampler2D reflection;
-uniform sampler2D dudvMap;
-uniform sampler2D refraction;
-uniform sampler2D depthMap;
-
-uniform vec4 waterColor;
-uniform vec4 waterColorEnd;
-uniform bool abovewater;
-uniform bool useFadeToFogColor;
-//uniform float dudvPower; //0.005
-//uniform float dudvColorPower; //0.01
-//uniform float normalPower; //0.5
-//uniform float normalOffsetPower; //0.6
-
-void main()
-{
- float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
-
- vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
- vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
- dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
-
- vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
- normalVector = normalVector * 2.0 - 1.0;
- normalVector = normalize(normalVector);
- normalVector.xy *= 0.5;
-
- vec3 localView = normalize(viewTangetSpace);
- float fresnel = dot(normalVector, localView);
- if ( abovewater == false ) {
- fresnel = -fresnel;
- }
- fresnel *= 1.0 - fogDist;
- float fresnelTerm = 1.0 - fresnel;
- fresnelTerm *= fresnelTerm;
- fresnelTerm = fresnelTerm * 0.9 + 0.1;
- fresnel = 1.0 - fresnelTerm;
-
- vec2 projCoord = viewCoords.xy / viewCoords.q;
- projCoord = (projCoord + 1.0) * 0.5;
- vec2 projCoordDepth = projCoord;
- if ( abovewater == true ) {
- projCoord.x = 1.0 - projCoord.x;
- }
-
- projCoord += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoord = clamp(projCoord, 0.001, 0.999);
-
- projCoordDepth += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoordDepth = clamp(projCoordDepth, 0.001, 0.999);
-
- vec4 reflectionColor = texture2D(reflection, projCoord);
- if ( abovewater == false ) {
- reflectionColor *= vec4(0.8,0.9,1.0,1.0);
- vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
- gl_FragColor = mix(endColor,waterColor,fogDist);
- }
- else {
- vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
- vec4 refractionColor = texture2D(refraction, projCoordDepth);
- float depth = texture2D(depthMap, projCoordDepth).r;
- depth = pow(depth,15.0);
- float invDepth = 1.0-depth;
-
- vec4 endColor = refractionColor*vec4(invDepth*fresnel) + waterColorNew*vec4(depth*fresnel);
-
- if( useFadeToFogColor == false) {
- gl_FragColor = endColor + reflectionColor * vec4(fresnelTerm);
- } else {
- gl_FragColor = (endColor + reflectionColor * vec4(fresnelTerm)) * (1.0-fogDist) + gl_Fog.color * fogDist;
- }
- }
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+
+uniform sampler2D normalMap;
+uniform sampler2D reflection;
+uniform sampler2D dudvMap;
+uniform sampler2D refraction;
+uniform sampler2D depthMap;
+
+uniform vec4 waterColor;
+uniform vec4 waterColorEnd;
+uniform bool abovewater;
+uniform bool useFadeToFogColor;
+//uniform float dudvPower; //0.005
+//uniform float dudvColorPower; //0.01
+//uniform float normalPower; //0.5
+//uniform float normalOffsetPower; //0.6
+
+void main()
+{
+ float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
+
+ vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
+ vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
+ dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
+
+ vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
+ normalVector = normalVector * 2.0 - 1.0;
+ normalVector = normalize(normalVector);
+ normalVector.xy *= 0.5;
+
+ vec3 localView = normalize(viewTangetSpace);
+ float fresnel = dot(normalVector, localView);
+ if ( abovewater == false ) {
+ fresnel = -fresnel;
+ }
+ fresnel *= 1.0 - fogDist;
+ float fresnelTerm = 1.0 - fresnel;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm = fresnelTerm * 0.9 + 0.1;
+ fresnel = 1.0 - fresnelTerm;
+
+ vec2 projCoord = viewCoords.xy / viewCoords.q;
+ projCoord = (projCoord + 1.0) * 0.5;
+ vec2 projCoordDepth = projCoord;
+ if ( abovewater == true ) {
+ projCoord.x = 1.0 - projCoord.x;
+ }
+
+ projCoord += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoord = clamp(projCoord, 0.001, 0.999);
+
+ projCoordDepth += (dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoordDepth = clamp(projCoordDepth, 0.001, 0.999);
+
+ vec4 reflectionColor = texture2D(reflection, projCoord);
+ if ( abovewater == false ) {
+ reflectionColor *= vec4(0.8,0.9,1.0,1.0);
+ vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
+ gl_FragColor = mix(endColor,waterColor,fogDist);
+ }
+ else {
+ vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
+ vec4 refractionColor = texture2D(refraction, projCoordDepth);
+ float depth = texture2D(depthMap, projCoordDepth).r;
+ depth = pow(depth,15.0);
+ float invDepth = 1.0-depth;
+
+ vec4 endColor = refractionColor*vec4(invDepth*fresnel) + waterColorNew*vec4(depth*fresnel);
+
+ if( useFadeToFogColor == false) {
+ gl_FragColor = endColor + reflectionColor * vec4(fresnelTerm);
+ } else {
+ gl_FragColor = (endColor + reflectionColor * vec4(fresnelTerm)) * (1.0-fogDist) + gl_Fog.color * fogDist;
+ }
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.vert
index 62d4f91..75296f2 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/flatwatershader_refraction.vert
@@ -1,49 +1,49 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-
-//uniform vec3 cameraPos;
-uniform vec3 tangent;
-uniform vec3 binormal;
-uniform float normalTranslation, refractionTranslation;
-
-void main()
-{
- // Because we have a flat plane for water we already know the vectors for tangent space
-// vec3 normal = gl_Normal;
- vec3 normal = gl_NormalMatrix * gl_Normal;
- normal = normalize(normal);
- vec3 tangent2 = gl_NormalMatrix * tangent;
- tangent2 = normalize(tangent2);
- vec3 binormal2 = gl_NormalMatrix * binormal;
- binormal2 = normalize(binormal2);
-
- // Calculate the vector coming from the vertex to the camera
-// vec3 viewDir = cameraPos - gl_Vertex.xyz;
- vec4 v = gl_ModelViewMatrix * gl_Vertex;
- vec3 viewDir = -(v.xyz/v.w);
- viewDir = normalize(viewDir);
-
- // Compute tangent space for the view direction
- viewTangetSpace.x = dot(viewDir, tangent2);
- viewTangetSpace.y = dot(viewDir, binormal2);
- viewTangetSpace.z = dot(viewDir, normal);
-
- refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
- normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
-
- // This calculates our current projection coordinates
- viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
- gl_Position = viewCoords;
-}
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+
+//uniform vec3 cameraPos;
+uniform vec3 tangent;
+uniform vec3 binormal;
+uniform float normalTranslation, refractionTranslation;
+
+void main()
+{
+ // Because we have a flat plane for water we already know the vectors for tangent space
+// vec3 normal = gl_Normal;
+ vec3 normal = gl_NormalMatrix * gl_Normal;
+ normal = normalize(normal);
+ vec3 tangent2 = gl_NormalMatrix * tangent;
+ tangent2 = normalize(tangent2);
+ vec3 binormal2 = gl_NormalMatrix * binormal;
+ binormal2 = normalize(binormal2);
+
+ // Calculate the vector coming from the vertex to the camera
+// vec3 viewDir = cameraPos - gl_Vertex.xyz;
+ vec4 v = gl_ModelViewMatrix * gl_Vertex;
+ vec3 viewDir = -(v.xyz/v.w);
+ viewDir = normalize(viewDir);
+
+ // Compute tangent space for the view direction
+ viewTangetSpace.x = dot(viewDir, tangent2);
+ viewTangetSpace.y = dot(viewDir, binormal2);
+ viewTangetSpace.z = dot(viewDir, normal);
+
+ refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
+ normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
+
+ // This calculates our current projection coordinates
+ viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_Position = viewCoords;
+}
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.frag
index 3975051..92a337e 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.frag
@@ -1,88 +1,88 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec2 foamCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-varying vec2 vnormal;
-varying vec4 vVertex;
-
-uniform sampler2D normalMap;
-uniform sampler2D reflection;
-uniform sampler2D dudvMap;
-uniform sampler2D foamMap;
-
-uniform vec4 waterColor;
-uniform vec4 waterColorEnd;
-uniform bool abovewater;
-uniform bool useFadeToFogColor;
-uniform float amplitude;
-//uniform float dudvPower; //0.005
-//uniform float dudvColorPower; //0.01
-//uniform float normalPower; //0.5
-//uniform float normalOffsetPower; //0.6
-
-void main()
-{
- float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
-
- vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
- vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
- dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
-
- vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
- normalVector = normalVector * 2.0 - 1.0;
- normalVector = normalize(normalVector);
- normalVector.xy *= 0.5;
-
- vec3 localView = normalize(viewTangetSpace);
- float fresnel = dot(normalVector, localView);
- fresnel *= 1.0 - fogDist;
- float fresnelTerm = 1.0 - fresnel;
- fresnelTerm *= fresnelTerm;
- fresnelTerm *= fresnelTerm;
- fresnelTerm = fresnelTerm * 0.9 + 0.1;
-
- vec2 projCoord = viewCoords.xy / viewCoords.q;
- projCoord = (projCoord + 1.0) * 0.5;
- if ( abovewater == true ) {
- projCoord.x = 1.0 - projCoord.x;
- }
-
- projCoord += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoord = clamp(projCoord, 0.001, 0.999);
-
- vec4 reflectionColor = texture2D(reflection, projCoord);
- if ( abovewater == false ) {
- reflectionColor *= vec4(0.8,0.9,1.0,1.0);
- vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
- gl_FragColor = mix(endColor,waterColor,fogDist);
- }
- else {
- vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
- vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
-
- float foamVal = (vVertex.y-vVertex.w) / (amplitude * 2.0);
- foamVal = clamp(foamVal,0.0,1.0);
- vec4 foamTex = texture2D(foamMap, foamCoords + vnormal * 0.6 + normalVector.xy * 0.05);
- float normLength = length(vnormal*5.0);
- foamVal *= 1.0-normLength;
- foamVal *= foamTex.a;
- endColor = mix(endColor,foamTex,clamp(foamVal,0.0,0.95));
-
- if( useFadeToFogColor == false) {
- gl_FragColor = mix(endColor,reflectionColor,fogDist);
- } else {
- gl_FragColor = mix(endColor,reflectionColor,fogDist) * (1.0-fogDist) + gl_Fog.color * fogDist;
- }
- }
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec2 foamCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+varying vec2 vnormal;
+varying vec4 vVertex;
+
+uniform sampler2D normalMap;
+uniform sampler2D reflection;
+uniform sampler2D dudvMap;
+uniform sampler2D foamMap;
+
+uniform vec4 waterColor;
+uniform vec4 waterColorEnd;
+uniform bool abovewater;
+uniform bool useFadeToFogColor;
+uniform float amplitude;
+//uniform float dudvPower; //0.005
+//uniform float dudvColorPower; //0.01
+//uniform float normalPower; //0.5
+//uniform float normalOffsetPower; //0.6
+
+void main()
+{
+ float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
+
+ vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
+ vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
+ dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
+
+ vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
+ normalVector = normalVector * 2.0 - 1.0;
+ normalVector = normalize(normalVector);
+ normalVector.xy *= 0.5;
+
+ vec3 localView = normalize(viewTangetSpace);
+ float fresnel = dot(normalVector, localView);
+ fresnel *= 1.0 - fogDist;
+ float fresnelTerm = 1.0 - fresnel;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm = fresnelTerm * 0.9 + 0.1;
+
+ vec2 projCoord = viewCoords.xy / viewCoords.q;
+ projCoord = (projCoord + 1.0) * 0.5;
+ if ( abovewater == true ) {
+ projCoord.x = 1.0 - projCoord.x;
+ }
+
+ projCoord += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoord = clamp(projCoord, 0.001, 0.999);
+
+ vec4 reflectionColor = texture2D(reflection, projCoord);
+ if ( abovewater == false ) {
+ reflectionColor *= vec4(0.8,0.9,1.0,1.0);
+ vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
+ gl_FragColor = mix(endColor,waterColor,fogDist);
+ }
+ else {
+ vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
+ vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
+
+ float foamVal = (vVertex.y-vVertex.w) / (amplitude * 2.0);
+ foamVal = clamp(foamVal,0.0,1.0);
+ vec4 foamTex = texture2D(foamMap, foamCoords + vnormal * 0.6 + normalVector.xy * 0.05);
+ float normLength = length(vnormal*5.0);
+ foamVal *= 1.0-normLength;
+ foamVal *= foamTex.a;
+ endColor = mix(endColor,foamTex,clamp(foamVal,0.0,0.95));
+
+ if( useFadeToFogColor == false) {
+ gl_FragColor = mix(endColor,reflectionColor,fogDist);
+ } else {
+ gl_FragColor = mix(endColor,reflectionColor,fogDist) * (1.0-fogDist) + gl_Fog.color * fogDist;
+ }
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.vert
index 1de2252..799bfaf 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader.vert
@@ -1,53 +1,53 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec2 foamCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-varying vec2 vnormal;
-varying vec4 vVertex;
-
-uniform vec3 cameraPos;
-uniform vec3 tangent;
-uniform vec3 binormal;
-uniform float normalTranslation, refractionTranslation;
-uniform float waterHeight;
-uniform float heightFalloffStart;
-uniform float heightFalloffSpeed;
-
-void main()
-{
- viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
- vVertex = gl_Vertex;
- float heightAdjust = 1.0 - clamp((viewCoords.z-heightFalloffStart)/heightFalloffSpeed,0.0,1.0);
- vVertex.y = mix(waterHeight,vVertex.y,heightAdjust);
- viewCoords = gl_ModelViewProjectionMatrix * vVertex;
- gl_Position = viewCoords;
- vVertex.w = waterHeight;
-
- // Because we have a flat plane for water we already know the vectors for tangent space
- vec3 normal = vec3(gl_Normal.x*heightAdjust,gl_Normal.y,gl_Normal.z*heightAdjust);
- vnormal = normal.xz * 0.15;
-
- // Calculate the vector coming from the vertex to the camera
- vec3 viewDir = cameraPos - gl_Vertex.xyz;
-
- // Compute tangent space for the view direction
- viewTangetSpace.x = dot(viewDir, tangent);
- viewTangetSpace.y = dot(viewDir, binormal);
- viewTangetSpace.z = dot(viewDir, normal);
-
- //todo test 0.8
- refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
- normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
- foamCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation*0.4);
-}
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec2 foamCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+varying vec2 vnormal;
+varying vec4 vVertex;
+
+uniform vec3 cameraPos;
+uniform vec3 tangent;
+uniform vec3 binormal;
+uniform float normalTranslation, refractionTranslation;
+uniform float waterHeight;
+uniform float heightFalloffStart;
+uniform float heightFalloffSpeed;
+
+void main()
+{
+ viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
+ vVertex = gl_Vertex;
+ float heightAdjust = 1.0 - clamp((viewCoords.z-heightFalloffStart)/heightFalloffSpeed,0.0,1.0);
+ vVertex.y = mix(waterHeight,vVertex.y,heightAdjust);
+ viewCoords = gl_ModelViewProjectionMatrix * vVertex;
+ gl_Position = viewCoords;
+ vVertex.w = waterHeight;
+
+ // Because we have a flat plane for water we already know the vectors for tangent space
+ vec3 normal = vec3(gl_Normal.x*heightAdjust,gl_Normal.y,gl_Normal.z*heightAdjust);
+ vnormal = normal.xz * 0.15;
+
+ // Calculate the vector coming from the vertex to the camera
+ vec3 viewDir = cameraPos - gl_Vertex.xyz;
+
+ // Compute tangent space for the view direction
+ viewTangetSpace.x = dot(viewDir, tangent);
+ viewTangetSpace.y = dot(viewDir, binormal);
+ viewTangetSpace.z = dot(viewDir, normal);
+
+ //todo test 0.8
+ refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
+ normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
+ foamCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation*0.4);
+}
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.frag b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.frag
index 16f2513..ca7fb59 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.frag
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.frag
@@ -1,101 +1,101 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec2 foamCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-varying vec2 vnormal;
-varying vec4 vVertex;
-
-uniform sampler2D normalMap;
-uniform sampler2D reflection;
-uniform sampler2D dudvMap;
-uniform sampler2D refraction;
-uniform sampler2D depthMap;
-uniform sampler2D foamMap;
-
-uniform vec4 waterColor;
-uniform vec4 waterColorEnd;
-uniform bool abovewater;
-uniform bool useFadeToFogColor;
-uniform float amplitude;
-//uniform float dudvPower; //0.005
-//uniform float dudvColorPower; //0.01
-//uniform float normalPower; //0.5
-//uniform float normalOffsetPower; //0.6
-
-void main()
-{
- float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
-
- vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
- vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
- dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
-
- vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
- normalVector = normalVector * 2.0 - 1.0;
- normalVector = normalize(normalVector);
- normalVector.xy *= 0.5;
-
- vec3 localView = normalize(viewTangetSpace);
- float fresnel = dot(normalVector, localView);
- fresnel *= 1.0 - fogDist;
- float fresnelTerm = 1.0 - fresnel;
- fresnelTerm *= fresnelTerm;
- fresnelTerm *= fresnelTerm;
- fresnelTerm = fresnelTerm * 0.9 + 0.1;
- fresnel = 1.0 - fresnelTerm;
-
- vec2 projCoord = viewCoords.xy / viewCoords.q;
- projCoord = (projCoord + 1.0) * 0.5;
- vec2 projCoordDepth = projCoord;
- if ( abovewater == true ) {
- projCoord.x = 1.0 - projCoord.x;
- }
-
- projCoord += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoord = clamp(projCoord, 0.001, 0.999);
-
- projCoordDepth += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
- projCoordDepth = clamp(projCoordDepth, 0.001, 0.999);
-
- vec4 reflectionColor = texture2D(reflection, projCoord);
- if ( abovewater == false ) {
- reflectionColor *= vec4(0.8,0.9,1.0,1.0);
- vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
- gl_FragColor = mix(endColor,waterColor,fogDist);
- }
- else {
- vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
- vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
-
- float foamVal = (vVertex.y-vVertex.w) / (amplitude * 2.0);
- foamVal = clamp(foamVal,0.0,1.0);
- vec4 foamTex = texture2D(foamMap, foamCoords + vnormal * 0.6 + normalVector.xy * 0.05);
- float normLength = length(vnormal*5.0);
- foamVal *= 1.0-normLength;
- foamVal *= foamTex.a;
- endColor = mix(endColor,foamTex,clamp(foamVal,0.0,0.95));
-
- vec4 refractionColor = texture2D(refraction, projCoordDepth);
- float depth = texture2D(depthMap, projCoordDepth).r;
- depth = pow(depth,15.0);
- float invDepth = 1.0-depth;
-
- endColor = refractionColor*vec4(invDepth*fresnel) + endColor*vec4(depth*fresnel);
- if( useFadeToFogColor == false) {
- gl_FragColor = endColor + reflectionColor * vec4(fresnelTerm);
- } else {
- gl_FragColor = (endColor + reflectionColor * vec4(fresnelTerm)) * (1.0-fogDist) + gl_Fog.color * fogDist;
- }
- }
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec2 foamCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+varying vec2 vnormal;
+varying vec4 vVertex;
+
+uniform sampler2D normalMap;
+uniform sampler2D reflection;
+uniform sampler2D dudvMap;
+uniform sampler2D refraction;
+uniform sampler2D depthMap;
+uniform sampler2D foamMap;
+
+uniform vec4 waterColor;
+uniform vec4 waterColorEnd;
+uniform bool abovewater;
+uniform bool useFadeToFogColor;
+uniform float amplitude;
+//uniform float dudvPower; //0.005
+//uniform float dudvColorPower; //0.01
+//uniform float normalPower; //0.5
+//uniform float normalOffsetPower; //0.6
+
+void main()
+{
+ float fogDist = clamp((viewCoords.z-gl_Fog.start)*gl_Fog.scale,0.0,1.0);
+
+ vec2 distOffset = texture2D(dudvMap, refrCoords).xy * 0.01;
+ vec3 dudvColor = texture2D(dudvMap, normCoords + distOffset).xyz;
+ dudvColor = normalize(dudvColor * 2.0 - 1.0) * 0.015;
+
+ vec3 normalVector = texture2D(normalMap, normCoords + distOffset * 0.6).xyz;
+ normalVector = normalVector * 2.0 - 1.0;
+ normalVector = normalize(normalVector);
+ normalVector.xy *= 0.5;
+
+ vec3 localView = normalize(viewTangetSpace);
+ float fresnel = dot(normalVector, localView);
+ fresnel *= 1.0 - fogDist;
+ float fresnelTerm = 1.0 - fresnel;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm *= fresnelTerm;
+ fresnelTerm = fresnelTerm * 0.9 + 0.1;
+ fresnel = 1.0 - fresnelTerm;
+
+ vec2 projCoord = viewCoords.xy / viewCoords.q;
+ projCoord = (projCoord + 1.0) * 0.5;
+ vec2 projCoordDepth = projCoord;
+ if ( abovewater == true ) {
+ projCoord.x = 1.0 - projCoord.x;
+ }
+
+ projCoord += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoord = clamp(projCoord, 0.001, 0.999);
+
+ projCoordDepth += (vnormal + dudvColor.xy * 0.5 + normalVector.xy * 0.2);
+ projCoordDepth = clamp(projCoordDepth, 0.001, 0.999);
+
+ vec4 reflectionColor = texture2D(reflection, projCoord);
+ if ( abovewater == false ) {
+ reflectionColor *= vec4(0.8,0.9,1.0,1.0);
+ vec4 endColor = mix(reflectionColor,waterColor,fresnelTerm);
+ gl_FragColor = mix(endColor,waterColor,fogDist);
+ }
+ else {
+ vec4 waterColorNew = mix(waterColor,waterColorEnd,fresnelTerm);
+ vec4 endColor = mix(waterColorNew,reflectionColor,fresnelTerm);
+
+ float foamVal = (vVertex.y-vVertex.w) / (amplitude * 2.0);
+ foamVal = clamp(foamVal,0.0,1.0);
+ vec4 foamTex = texture2D(foamMap, foamCoords + vnormal * 0.6 + normalVector.xy * 0.05);
+ float normLength = length(vnormal*5.0);
+ foamVal *= 1.0-normLength;
+ foamVal *= foamTex.a;
+ endColor = mix(endColor,foamTex,clamp(foamVal,0.0,0.95));
+
+ vec4 refractionColor = texture2D(refraction, projCoordDepth);
+ float depth = texture2D(depthMap, projCoordDepth).r;
+ depth = pow(depth,15.0);
+ float invDepth = 1.0-depth;
+
+ endColor = refractionColor*vec4(invDepth*fresnel) + endColor*vec4(depth*fresnel);
+ if( useFadeToFogColor == false) {
+ gl_FragColor = endColor + reflectionColor * vec4(fresnelTerm);
+ } else {
+ gl_FragColor = (endColor + reflectionColor * vec4(fresnelTerm)) * (1.0-fogDist) + gl_Fog.color * fogDist;
+ }
+ }
} \ No newline at end of file
diff --git a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.vert b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.vert
index 1de2252..799bfaf 100644
--- a/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.vert
+++ b/ardor3d-effects/src/main/resources/com/ardor3d/extension/effect/water/projectedwatershader_refraction.vert
@@ -1,53 +1,53 @@
-/**
- * Copyright (c) 2008-2010 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-varying vec2 refrCoords;
-varying vec2 normCoords;
-varying vec2 foamCoords;
-varying vec4 viewCoords;
-varying vec3 viewTangetSpace;
-varying vec2 vnormal;
-varying vec4 vVertex;
-
-uniform vec3 cameraPos;
-uniform vec3 tangent;
-uniform vec3 binormal;
-uniform float normalTranslation, refractionTranslation;
-uniform float waterHeight;
-uniform float heightFalloffStart;
-uniform float heightFalloffSpeed;
-
-void main()
-{
- viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
- vVertex = gl_Vertex;
- float heightAdjust = 1.0 - clamp((viewCoords.z-heightFalloffStart)/heightFalloffSpeed,0.0,1.0);
- vVertex.y = mix(waterHeight,vVertex.y,heightAdjust);
- viewCoords = gl_ModelViewProjectionMatrix * vVertex;
- gl_Position = viewCoords;
- vVertex.w = waterHeight;
-
- // Because we have a flat plane for water we already know the vectors for tangent space
- vec3 normal = vec3(gl_Normal.x*heightAdjust,gl_Normal.y,gl_Normal.z*heightAdjust);
- vnormal = normal.xz * 0.15;
-
- // Calculate the vector coming from the vertex to the camera
- vec3 viewDir = cameraPos - gl_Vertex.xyz;
-
- // Compute tangent space for the view direction
- viewTangetSpace.x = dot(viewDir, tangent);
- viewTangetSpace.y = dot(viewDir, binormal);
- viewTangetSpace.z = dot(viewDir, normal);
-
- //todo test 0.8
- refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
- normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
- foamCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation*0.4);
-}
+/**
+ * Copyright (c) 2008-2010 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+varying vec2 refrCoords;
+varying vec2 normCoords;
+varying vec2 foamCoords;
+varying vec4 viewCoords;
+varying vec3 viewTangetSpace;
+varying vec2 vnormal;
+varying vec4 vVertex;
+
+uniform vec3 cameraPos;
+uniform vec3 tangent;
+uniform vec3 binormal;
+uniform float normalTranslation, refractionTranslation;
+uniform float waterHeight;
+uniform float heightFalloffStart;
+uniform float heightFalloffSpeed;
+
+void main()
+{
+ viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
+ vVertex = gl_Vertex;
+ float heightAdjust = 1.0 - clamp((viewCoords.z-heightFalloffStart)/heightFalloffSpeed,0.0,1.0);
+ vVertex.y = mix(waterHeight,vVertex.y,heightAdjust);
+ viewCoords = gl_ModelViewProjectionMatrix * vVertex;
+ gl_Position = viewCoords;
+ vVertex.w = waterHeight;
+
+ // Because we have a flat plane for water we already know the vectors for tangent space
+ vec3 normal = vec3(gl_Normal.x*heightAdjust,gl_Normal.y,gl_Normal.z*heightAdjust);
+ vnormal = normal.xz * 0.15;
+
+ // Calculate the vector coming from the vertex to the camera
+ vec3 viewDir = cameraPos - gl_Vertex.xyz;
+
+ // Compute tangent space for the view direction
+ viewTangetSpace.x = dot(viewDir, tangent);
+ viewTangetSpace.y = dot(viewDir, binormal);
+ viewTangetSpace.z = dot(viewDir, normal);
+
+ //todo test 0.8
+ refrCoords = (gl_TextureMatrix[2] * gl_MultiTexCoord0).xy + vec2(0.0,refractionTranslation);
+ normCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation);
+ foamCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy + vec2(0.0,normalTranslation*0.4);
+}
diff --git a/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/MockPSSMCamera.java b/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/MockPSSMCamera.java
index 70dfa5e..664df03 100644
--- a/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/MockPSSMCamera.java
+++ b/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/MockPSSMCamera.java
@@ -1,19 +1,19 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.shadow.map;
-
-import com.ardor3d.math.Vector3;
-
-public class MockPSSMCamera extends PSSMCamera {
- public Vector3 getExtents() {
- return _extents;
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.shadow.map;
+
+import com.ardor3d.math.Vector3;
+
+public class MockPSSMCamera extends PSSMCamera {
+ public Vector3 getExtents() {
+ return _extents;
+ }
+}
diff --git a/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/TestPSSMCamera.java b/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/TestPSSMCamera.java
index fb8bdc0..de74a4f 100644
--- a/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/TestPSSMCamera.java
+++ b/ardor3d-effects/src/test/java/com/ardor3d/extension/shadow/map/TestPSSMCamera.java
@@ -1,59 +1,59 @@
-/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
- *
- * This file is part of Ardor3D.
- *
- * Ardor3D is free software: you can redistribute it and/or modify it
- * under the terms of its license which may be found in the accompanying
- * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
- */
-
-package com.ardor3d.extension.shadow.map;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-import com.ardor3d.bounding.BoundingBox;
-import com.ardor3d.bounding.BoundingSphere;
-import com.ardor3d.math.Vector3;
-
-public class TestPSSMCamera {
- @Test
- public void testBoxSphereCameraPack() {
- MockPSSMCamera camera = new MockPSSMCamera();
- camera.setLocation(0, 0, -10);
- camera.setFrustumPerspective(50, 1, 1, 100);
-
- final BoundingBox boundingBox = new BoundingBox();
- boundingBox.setCenter(new Vector3(0, 0, 10));
- boundingBox.setXExtent(2);
- boundingBox.setYExtent(2);
- boundingBox.setZExtent(2);
-
- camera.pack(boundingBox);
-
- final double boxNear1 = camera.getFrustumNear();
- final double boxFar1 = camera.getFrustumFar();
-
- Assert.assertEquals(new Vector3(2, 2, 2), camera.getExtents());
-
- camera = new MockPSSMCamera();
- camera.setLocation(0, 0, -10);
- camera.setFrustumPerspective(50, 1, 1, 100);
-
- final BoundingSphere boundingSphere = new BoundingSphere();
- boundingSphere.setCenter(new Vector3(0, 0, 10));
- boundingSphere.setRadius(2);
-
- camera.pack(boundingSphere);
-
- final double boxNear2 = camera.getFrustumNear();
- final double boxFar2 = camera.getFrustumFar();
-
- Assert.assertEquals(new Vector3(2, 2, 2), camera.getExtents());
-
- Assert.assertEquals(boxNear1, boxNear2);
- Assert.assertEquals(boxFar1, boxFar2);
- }
-}
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.shadow.map;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.ardor3d.bounding.BoundingBox;
+import com.ardor3d.bounding.BoundingSphere;
+import com.ardor3d.math.Vector3;
+
+public class TestPSSMCamera {
+ @Test
+ public void testBoxSphereCameraPack() {
+ MockPSSMCamera camera = new MockPSSMCamera();
+ camera.setLocation(0, 0, -10);
+ camera.setFrustumPerspective(50, 1, 1, 100);
+
+ final BoundingBox boundingBox = new BoundingBox();
+ boundingBox.setCenter(new Vector3(0, 0, 10));
+ boundingBox.setXExtent(2);
+ boundingBox.setYExtent(2);
+ boundingBox.setZExtent(2);
+
+ camera.pack(boundingBox);
+
+ final double boxNear1 = camera.getFrustumNear();
+ final double boxFar1 = camera.getFrustumFar();
+
+ Assert.assertEquals(new Vector3(2, 2, 2), camera.getExtents());
+
+ camera = new MockPSSMCamera();
+ camera.setLocation(0, 0, -10);
+ camera.setFrustumPerspective(50, 1, 1, 100);
+
+ final BoundingSphere boundingSphere = new BoundingSphere();
+ boundingSphere.setCenter(new Vector3(0, 0, 10));
+ boundingSphere.setRadius(2);
+
+ camera.pack(boundingSphere);
+
+ final double boxNear2 = camera.getFrustumNear();
+ final double boxFar2 = camera.getFrustumFar();
+
+ Assert.assertEquals(new Vector3(2, 2, 2), camera.getExtents());
+
+ Assert.assertEquals(boxNear1, boxNear2);
+ Assert.assertEquals(boxFar1, boxFar2);
+ }
+}