aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/all.tests1
-rw-r--r--tests/spec/arb_es2_compatibility/CMakeLists.gl.txt1
-rw-r--r--tests/spec/arb_es2_compatibility/arb_es2_compatibility-releaseshadercompiler-ge7.c126
-rw-r--r--tests/spec/arb_es2_compatibility/ge7.frag710
-rw-r--r--tests/spec/arb_es2_compatibility/ge7.vert814
5 files changed, 1652 insertions, 0 deletions
diff --git a/tests/all.tests b/tests/all.tests
index d0f29beb..164f9282 100644
--- a/tests/all.tests
+++ b/tests/all.tests
@@ -877,6 +877,7 @@ add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-getshaderprecisionf
add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-maxvectors')
add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-shadercompiler')
add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-releaseshadercompiler')
+add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-releaseshadercompiler-ge7')
add_plain_test(arb_es2_compatibility, 'arb_es2_compatibility-fixed-type')
add_plain_test(arb_es2_compatibility, 'fbo-missing-attachment-clear')
arb_es2_compatibility['FBO blit to missing attachment (ES2 completeness rules)'] = PlainExecTest(['fbo-missing-attachment-blit', '-auto', 'es2', 'to'])
diff --git a/tests/spec/arb_es2_compatibility/CMakeLists.gl.txt b/tests/spec/arb_es2_compatibility/CMakeLists.gl.txt
index 99937fa5..fe69ea3a 100644
--- a/tests/spec/arb_es2_compatibility/CMakeLists.gl.txt
+++ b/tests/spec/arb_es2_compatibility/CMakeLists.gl.txt
@@ -15,6 +15,7 @@ piglit_add_executable (arb_es2_compatibility-depthrangef arb_es2_compatibility-d
piglit_add_executable (arb_es2_compatibility-drawbuffers arb_es2_compatibility-drawbuffers.c)
piglit_add_executable (arb_es2_compatibility-maxvectors arb_es2_compatibility-maxvectors.c)
piglit_add_executable (arb_es2_compatibility-releaseshadercompiler arb_es2_compatibility-releaseshadercompiler.c)
+piglit_add_executable (arb_es2_compatibility-releaseshadercompiler-ge7 arb_es2_compatibility-releaseshadercompiler-ge7.c)
piglit_add_executable (arb_es2_compatibility-shadercompiler arb_es2_compatibility-shadercompiler.c)
piglit_add_executable (arb_es2_compatibility-getshaderprecisionformat arb_es2_compatibility-getshaderprecisionformat.c)
piglit_add_executable (arb_es2_compatibility-fixed-type arb_es2_compatibility-fixed-type.c)
diff --git a/tests/spec/arb_es2_compatibility/arb_es2_compatibility-releaseshadercompiler-ge7.c b/tests/spec/arb_es2_compatibility/arb_es2_compatibility-releaseshadercompiler-ge7.c
new file mode 100644
index 00000000..e713e511
--- /dev/null
+++ b/tests/spec/arb_es2_compatibility/arb_es2_compatibility-releaseshadercompiler-ge7.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net> (original program)
+ * Brian Paul (this variation on Eric's program)
+ *
+ */
+
+/** @file arb_es2_compatibility-releasecompiler-ge7.c
+ *
+ * This tests glReleaseShaderCompiler() between compilation and linking.
+ *
+ * At the time of writing, this causes Mesa to crash with Google Earth
+ * version 7 because the linker is trying to use data that was
+ * generated by the compiler but freed by glReleaseShaderCompiler().
+ *
+ * This test passes with NVIDIA's driver.
+ *
+ * The vertex/fragment shaders are captured from Google Earth v7.
+ * Simpler shaders don't always trigger the bug we're testing for.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+ config.supports_gl_compat_version = 10;
+
+ config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_ALPHA | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+#ifdef GL_ARB_ES2_compatibility
+
+void
+draw(void)
+{
+ GLuint vs, fs, prog;
+
+ vs = piglit_compile_shader(GL_VERTEX_SHADER,
+ "spec/arb_es2_compatibility/ge7.vert");
+ fs = piglit_compile_shader(GL_FRAGMENT_SHADER,
+ "spec/arb_es2_compatibility/ge7.frag");
+
+ /* NOTE: we're calling glReleaseShaderCompiler() between compiling
+ * and linking.
+ */
+ glReleaseShaderCompiler();
+
+ prog = piglit_link_simple_program(vs, fs);
+ piglit_link_check_status(prog);
+
+ glDeleteShader(vs);
+ glDeleteShader(fs);
+
+ glUseProgram(prog);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDeleteProgram(prog);
+}
+#endif
+
+enum piglit_result
+piglit_display(void)
+{
+#ifdef GL_ARB_ES2_compatibility
+ static const float green[] = {0.0, 1.0, 0.0, 0.0};
+ GLboolean pass = GL_TRUE;
+
+ glClearColor(0.5, 0.5, 0.5, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ draw();
+
+ pass &= piglit_probe_pixel_rgba(piglit_width / 4, piglit_height / 2,
+ green);
+
+ assert(!glGetError());
+
+ piglit_present_results();
+
+ return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+#else
+ return PIGLIT_SKIP;
+#endif /* GL_ARB_ES2_compatibility */
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+#ifdef GL_ARB_ES2_compatibility
+ static const float verts[] = {
+ -1.0, 1.0, 0.0, 1.0,
+ -1.0, -1.0, 0.0, 1.0,
+ +0.0, 1.0, 0.0, 1.0,
+ +0.0, -1.0, 0.0, 1.0,
+ };
+
+ piglit_require_gl_version(20);
+ piglit_require_extension("GL_ARB_ES2_compatibility");
+
+ glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4,
+ verts);
+ glEnableVertexAttribArray(0);
+#endif
+}
diff --git a/tests/spec/arb_es2_compatibility/ge7.frag b/tests/spec/arb_es2_compatibility/ge7.frag
new file mode 100644
index 00000000..2d354eab
--- /dev/null
+++ b/tests/spec/arb_es2_compatibility/ge7.frag
@@ -0,0 +1,710 @@
+//!GL2
+#define GE_PIXEL_SHADER
+#define GE_PRECISION mediump
+#define ATMOSPHERE_OFF
+#define GROUND
+#define SUN_OFF
+#define OVERLAY
+#define ENABLE_VERTEX_REJECT
+#if defined(GL_ES)
+precision GE_PRECISION float;
+#else
+#define lowp
+#define mediump
+#define highp
+#endif
+
+uniform mat4 ig_ModelViewMatrix;
+uniform mat4 ig_ModelViewProjectionMatrix;
+uniform mat4 ig_TextureMatrix;
+uniform vec4 ig_LightDirectionInModelSpace;
+uniform vec4 ig_env_atmosphere_custom_state_value;
+uniform lowp vec4 ig_env_atmosphere_custom_color_value;
+uniform lowp float alpha_ref_value;
+
+float saturate(float v) { return clamp(v, 0.0, 1.0); }
+vec2 saturate(vec2 v) { return clamp(v, 0.0, 1.0); }
+vec3 saturate(vec3 v) { return clamp(v, 0.0, 1.0); }
+vec4 saturate(vec4 v) { return clamp(v, 0.0, 1.0); }
+
+// Returns the quadrant portion of the given vertex flags.
+float getQuadrant(vec4 vertexQuadrant) {
+ return dot(vertexQuadrant, vec4(1.0, 2.0, 4.0, 8.0));
+}
+
+// Both getMasked methods assume that quadrantMask has a single 1 and the
+// rest are 0.
+
+vec4 getMaskedVertex(vec4 pos, vec4 quadrantMask, vec4 vertexQuadrant) {
+ return pos * dot(quadrantMask, vertexQuadrant);
+}
+
+float getMaskedAlpha(vec4 quadrantAlphas, vec4 vertexQuadrant) {
+ return dot(quadrantAlphas, vertexQuadrant);
+}
+
+// Computes a vertex color to show which quadrant a vertex is in. Also marks
+// vertices that would be rejected and error conditions (e.g. invalid
+// quadrant).
+vec4 getDebugVertexColor(vec4 quadrantMask, vec4 vertexQuadrant) {
+ vec4 color;
+ float quadrant = getQuadrant(vertexQuadrant);
+ if (quadrant == 1.0) {
+ // Red
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ } else if (quadrant == 2.0) {
+ // Green
+ color = vec4(0.0, 1.0, 0.0, 1.0);
+ } else if (quadrant == 4.0) {
+ // Blue
+ color = vec4(0.0, 0.0, 1.0, 1.0);
+ } else if (quadrant == 8.0) {
+ // Cyan
+ color = vec4(0.0, 1.0, 1.0, 1.0);
+ } else if (quadrant == 0.0) {
+ // Vertex didn't have a quadrant bit set. Mark as saturated Yellow.
+ color = vec4(10.0, 10.0, 0.0, 1.0);
+ } else if (quadrant == 15.0) {
+ // All quadrant bits were set. Mark as White.
+ color = vec4(10.0, 10.0, 10.0, 1.0);
+ } else {
+ // More than one quadrant bit was set or a quadrant bit was set to
+ // something other than 1.0, so flag verts in saturated Magenta.
+ color = vec4(10.0, 0.0, 10.0, 1.0);
+ }
+ // Make hidden quadrants dimmer.
+ if (dot(quadrantMask, vertexQuadrant) == 0.)
+ color *= .5;
+ return color;
+}
+
+#ifdef DEBUG_QUADRANT_COLORS
+// Used by the pixel shader to show quadrants, culled verts and error
+// conditions when DEBUG_QUADRANT_COLORS is defined.
+varying vec4 vout_debug_color;
+#endif
+
+// The \"discard\" instruction is not available for vertex shaders, so
+// this function needs to be excluded when parsing a vertex shader.
+#ifdef GE_PIXEL_SHADER
+
+// When debugging is on, modulates the pixel color by the debug color output
+// from the vertex shader. Otherwise, the given pixel color is returned
+// unchanged.
+vec4 computeDebugPixelColor(vec4 pixelShaderColor) {
+// OGL ES 2.0 does not support alpha test, so need to do it in the
+// shader.
+#if defined(GL_ES) && !defined(FORCE_NO_ALPHA_TEST)
+// Terrain and sky don't use alpha test.
+#if defined(OVERLAY) || defined(MODEL)
+ // alpha_ref_value is set by igVisualContext, and will be -1 if alpha test
+ // is off.
+ if (pixelShaderColor.a < alpha_ref_value) {
+ discard;
+ }
+#endif // defined(OVERLAY) || defined(MODEL)
+#endif // defined(GL_ES) && !defined(FORCE_NO_ALPHA_TEST)
+
+#ifdef DEBUG_QUADRANT_COLORS
+ return pixelShaderColor * vout_debug_color;
+#else
+ return pixelShaderColor;
+#endif
+}
+
+#endif // GE_PIXEL_SHADER
+// Constant g for phase function used for Mie scattering.
+const float gMieConst = -0.990;
+const float gMieConst2 = gMieConst * gMieConst;
+
+varying vec4 vout_texCoordAndFogFactor;
+#if defined(QUADRANT_ALPHAS)
+varying float vout_alpha;
+#endif
+
+uniform lowp sampler2D groundTexture;
+uniform lowp vec4 groundColor;
+
+#if defined(OVERLAY)
+uniform vec4 groundOverlayExtent;
+float GetMaskedOverlayAlpha(float alpha, vec2 texCoord) {
+ return ((texCoord.s - groundOverlayExtent.x) *
+ (groundOverlayExtent.y - texCoord.s) >= 0. &&
+ (texCoord.t - groundOverlayExtent.z) *
+ (groundOverlayExtent.w - texCoord.t) >= 0. ? alpha : 0.0);
+}
+
+#endif // defined(OVERLAY)
+
+#if defined(USE_IMPROVED_SHADER_VARIATION)
+// x: atmosphere density.
+// y: atmosphere angle falloff.
+// z: night intensity.
+// w: camera exposure.
+uniform vec4 atmosphereTweaks;
+
+#endif // defined(USE_IMPROVED_SHADER_VARIATION)
+
+//", '=' <repeats 30 times>, " ground sun off
+#if defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_OFF)
+
+#if !defined(USE_SIMPLIFIED_SHADER_VARIATION)
+varying vec4 vout_blendTexCoordAndRayleighT;
+#endif
+
+uniform lowp sampler2D groundRayleighMap;
+uniform vec4 groundSunOffPixelParams;
+uniform lowp vec4 groundFogColor;
+
+#if defined(DEBUG_GE_BUILD)
+uniform lowp vec4 sidedb_color;
+#endif
+
+void AtmosphereGroundSunOffFragShader() {
+ // Get the texture color for the object.
+ lowp vec4 texColor = texture2D(groundTexture, vout_texCoordAndFogFactor.st);
+
+#if defined(DEBUG_GE_BUILD)
+ if (sidedb_color.a > 0.0) {
+ texColor = mix(texColor, sidedb_color, 0.1);
+ }
+#endif
+ texColor *= groundColor;
+
+ lowp vec4 color;
+ #if defined(USE_SIMPLIFIED_SHADER_VARIATION)
+ color = texColor;
+ #else
+ // The rayleigh map's s-coordinate depends on camera height and is computed
+ // on the CPU.
+ float rayleighS = groundSunOffPixelParams.x;
+ lowp vec4 rayleigh = texture2D(groundRayleighMap, vec2(rayleighS, vout_blendTexCoordAndRayleighT.z));
+ texColor.rgb += rayleigh.rgb;
+ lowp float fogFactor = vout_texCoordAndFogFactor.w;
+ color.rgb = mix(groundFogColor.rgb, texColor.rgb, fogFactor);
+ color.a = texColor.a;
+ #endif
+
+ gl_FragColor = computeDebugPixelColor(color);
+}
+
+//", '=' <repeats 30 times>, " ground sun off overlay
+#if defined(OVERLAY)
+uniform lowp sampler2D groundRayleighOverlayMap;
+
+void AtmosphereGroundSunOffOverlayFragShader() {
+ // Get the texture color for the object. The projective component is to
+ // allow us to do Arbitrary Ground Overlays.
+ lowp vec4 texColor =
+ texture2DProj(groundTexture, vout_texCoordAndFogFactor.stp) *
+ groundColor;
+ // Note that we do not allow texture blend for overlays.
+ // Perform texture edge clamping for ground overlays by setting alpha to zero
+ // outside of texture coordinate range [0, 1]
+ vec2 stOverZ = vout_texCoordAndFogFactor.xy / vout_texCoordAndFogFactor.z;
+ texColor.a = GetMaskedOverlayAlpha(texColor.a, stOverZ);
+
+ // The rayleigh map's s-coordinate depends on camera height and is computed
+ // on the CPU.
+ float rayleighS = groundSunOffPixelParams.x;
+ lowp vec4 rayleigh = texture2D(
+ groundRayleighOverlayMap,
+ vec2(rayleighS, vout_blendTexCoordAndRayleighT.z));
+ texColor.rgb += rayleigh.rgb;
+ lowp float fogFactor = vout_texCoordAndFogFactor.w;
+ lowp vec4 color;
+ color.rgb = mix(groundFogColor.rgb, texColor.rgb, fogFactor);
+ color.a = texColor.a;
+ gl_FragColor = computeDebugPixelColor(color);
+}
+#endif // defined(OVERLAY)
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_OFF)
+
+//", '=' <repeats 30 times>, " ground sun on (default)
+#if defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON) && !defined(USE_IMPROVED_SHADER_VARIATION)
+varying vec3 vout_rayleigh;
+varying vec3 vout_adjustedMie;
+uniform vec4 fogColor;
+
+#if defined(MODEL)
+uniform float has_texture;
+uniform lowp vec4 global_color;
+#endif
+
+void AtmosphereGroundSunOnFragShader() {
+ // If texturing is off, use white as diffuse color. Otherwise use color
+ // from texture.
+#if defined(MODEL)
+ lowp vec4 texColor = mix(
+ global_color,
+ texture2D(groundTexture, vout_texCoordAndFogFactor.st) * global_color,
+ has_texture);
+#else
+ lowp vec4 texColor = ig_env_atmosphere_custom_state_value.y != 0.0 ?
+ texture2D(groundTexture, vout_texCoordAndFogFactor.st) * groundColor :
+ groundColor;
+#endif // defined(MODEL)
+ vec3 scatteredColor = vout_rayleigh.rgb + texColor.rgb * vout_adjustedMie.rgb;
+ float fogFactor = vout_texCoordAndFogFactor.w;
+ vec4 color;
+ color.rgb = mix(fogColor.rgb, scatteredColor, fogFactor);
+ color.a = texColor.a;
+ gl_FragColor = computeDebugPixelColor(color);
+}
+
+
+//", '=' <repeats 29 times>, " ground sun on overlay (default)
+#if defined(OVERLAY)
+// Similar to above, but sets output alpha to zero when the projected texture
+// coordinates are outside of the [0,1] range.
+void AtmosphereGroundSunOnOverlayFragShader() {
+ // Get the texture color for the object. The projective component is to
+ // allow us to do Arbitrary Ground Overlays.
+ // If texturing is off, use white as diffuse color. Otherwise use color
+ // from texture.
+ lowp vec4 texColor = (ig_env_atmosphere_custom_state_value.y == 0.0) ?
+ groundColor :
+ (texture2DProj(groundTexture, vout_texCoordAndFogFactor.xyz) *
+ groundColor);
+ // Perform texture edge clamping for ground overlays by setting alpha to zero
+ // outside of texture coordinate range [0, 1]
+ vec2 stOverZ = vout_texCoordAndFogFactor.xy / vout_texCoordAndFogFactor.z;
+ texColor.a = GetMaskedOverlayAlpha(texColor.a, stOverZ);
+
+ vec3 scatteredColor = vout_rayleigh.rgb + texColor.rgb * vout_adjustedMie.rgb;
+ float fogFactor = vout_texCoordAndFogFactor.w;
+ vec4 color;
+ color.rgb = mix(fogColor.rgb, scatteredColor, fogFactor);
+ color.a = texColor.a;
+ gl_FragColor = computeDebugPixelColor(color);
+}
+#endif // defined(OVERLAY)
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON) && !defined(USE_IMPROVED_SHADER_VARIATION)
+
+//", '=' <repeats 30 times>, " ground sun on (improved)
+#if defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON) && defined(USE_IMPROVED_SHADER_VARIATION)
+uniform vec3 worldOriginInView;
+// The direction vector to the light source.
+uniform vec4 cameraToSunDirAndExposure;
+// xyz: Extra ambient color that is stronger during sunsets (and sunrises).
+// w: density used in fog exp2 function.
+uniform vec4 sunsetAmbientAndFogDensity;
+uniform vec4 fogColor;
+
+varying vec4 vout_viewPosAndNormalDotSun;
+#if defined(MORPH_VERTICES)
+varying vec4 vout_blendTexCoord;
+#endif // defined(MORPH_VERTICES)
+
+// Implements the abstract function defined in atmosphere.glsllib.
+// Returns a fading factor to attenuate the atmospheric effects when the camera
+// altitude decreases, unless the view zenith angle gets close to the horizon
+// angle.
+float atmosphereTweak(float r, float mu) {
+ float r0 = max(kMinCameraRadius, cameraAndSunState.x);
+ float muHoriz = -sqrt(1.0 - 1.0 / (r * r));
+ float angleFalloff = pow((1.0 + mu) / (1.0 + muHoriz), atmosphereTweaks.y);
+ return clamp(angleFalloff, 0.1, 1.0) * atmosphereTweaks.x;
+}
+
+vec4 ImprovedAtmosphereGroundSunOnAboveWater(vec4 texColor) {
+ // Computes the ground albedo, i.e. the proportion of incident ligth reflected
+ // by the ground, for each r,g,b wavelength, divided by pi. Ideally the ground
+ // texture would directly contain this physical quantity, but in fact it
+ // contains some uncalibrated values. Assuming that these values correctly
+ // represent the albedo, and that they are simply gamma corrected as in almost
+ // all images with a gamma value of 2.2, we can compute the albedo with a
+ // pow(color.rgb, 2.2) or approximate it with a square to avoid a costly pow
+ // function:
+ vec3 albedoOverPi = texColor.rgb * texColor.rgb * (0.55 / kPi);
+
+ // Computes the fragment position in geocentric coordinates.
+ vec3 groundPos = vout_viewPosAndNormalDotSun.xyz - worldOriginInView.xyz;
+
+ // Computes the radiance of the Sun reaching groundPos, relatively to the
+ // outer Sun radiance. This is the transmittance of the atmosphere from the
+ // ground to the top atmosphere boundary in the Sun direction.
+ float gR = length(groundPos);
+ float gMuS = dot(groundPos, cameraToSunDirAndExposure.xyz) / gR;
+ vec3 sunRadiance = atmoTex(gR, gMuS).rgb;
+
+ // Computes the irradiance due to the sky dome (excluding the Sun).
+ vec3 skyIrradiance = skyTex(gR, gMuS) * atmosphereTweaks.x;
+ // Tweaks the sky irradiance to avoid a dark ground during night.
+ float night = smoothstep(0.0, 0.2, -gMuS) * atmosphereTweaks.z;
+ vec3 gSkyIrradiance = max(skyIrradiance, vec3(0.002, 0.005, 0.01) * night);
+
+ // Computes the radiance reflected by the ground (using a Lambertian BRDF).
+ vec3 groundL = albedoOverPi *
+ (max(vout_viewPosAndNormalDotSun.w, 0.0) * sunRadiance + gSkyIrradiance);
+
+ vec3 pixel = aerialPerspective(groundL, -worldOriginInView, groundPos,
+ cameraToSunDirAndExposure.xyz, atmosphereTweaks.w);
+ return vec4(pixel, texColor.a);
+}
+
+vec4 ImprovedAtmosphereGroundSunOnBelowWater(vec4 texColor) {
+ // The following shading is completely ad-hoc and not physically-based at all.
+ // For instance distant water is always blue, even at night, which is of
+ // course wrong. Also the Sun light is not attenuated with depth, so that the
+ // sea bottom is always visible (in reality everything becomes completely dark
+ // at a few dozens meters below the surface).
+ texColor.rgb *= 0.66 * max(vout_viewPosAndNormalDotSun.w, 0.33);
+ float fogDistSq = dot(vout_viewPosAndNormalDotSun.xyz,
+ vout_viewPosAndNormalDotSun.xyz);
+ float fogFactor = exp(-2.0 * sunsetAmbientAndFogDensity.w * sqrt(fogDistSq));
+ return vec4(mix(fogColor.rgb, texColor.rgb, fogFactor), texColor.a);
+}
+
+void ImprovedAtmosphereGroundSunOnFragShader() {
+#if defined(OVERLAY)
+ // Get the texture color for the object. The projective component is to
+ // allow us to do Arbitrary Ground Overlays.
+ // If texturing is off, use white as diffuse color. Otherwise use color
+ // from texture.
+ lowp vec4 texColor = (ig_env_atmosphere_custom_state_value.y == 0.0) ?
+ vec4(1.0) : texture2DProj(groundTexture, vout_texCoordAndFogFactor.xyz);
+ // Perform texture edge clamping for ground overlays by setting alpha to zero
+ // outside of texture coordinate range [0, 1]
+ vec2 stOverZ = vout_texCoordAndFogFactor.xy / vout_texCoordAndFogFactor.z;
+ texColor.a = GetMaskedOverlayAlpha(texColor.a, stOverZ);
+#else
+ // If texturing is off, use white as diffuse color. Otherwise use color
+ // from texture.
+ vec4 texColor;
+ if (ig_env_atmosphere_custom_state_value.y != 0.0) {
+ texColor = texture2D(groundTexture, vout_texCoordAndFogFactor.st);
+ #if defined(MORPH_VERTICES)
+ float blend_param = blendUnpopPixelParams[0];
+ if (blend_param != 0.) {
+ // We are blending between 2 textures.
+ vec4 blendBlendColor = texture2D(blendTexture, vout_blendTexCoord.st);
+ // Compute final pixel color, blend between texture 1 and texture 2
+ texColor = mix(texColor, blendBlendColor, blend_param);
+ }
+ #endif // defined(MORPH_VERTICES)
+ } else {
+ texColor = vec4(1.0);
+ }
+#endif
+
+ vec4 color;
+ // TODO(ebruneton): water level may not always be exactly at r=1,
+ // how can we detect that?
+ if (cameraAndSunState.x < 1.0) {
+ color = ImprovedAtmosphereGroundSunOnBelowWater(texColor);
+ } else {
+ color = ImprovedAtmosphereGroundSunOnAboveWater(texColor);
+ }
+ #if defined(MORPH_VERTICES)
+ float unpop_alpha = blendUnpopPixelParams[1];
+ color.a *= unpop_alpha;
+ #endif // defined(MORPH_VERTICES)
+ gl_FragColor = computeDebugPixelColor(color);
+}
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON) && defined(USE_IMPROVED_SHADER_VARIATION)
+
+//", '=' <repeats 32 times>, " sky sun off", '=' <repeats 26 times>, "
+#if defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_OFF)
+varying vec4 vout_rayleighT;
+uniform vec4 skySunOffPixelParams;
+uniform lowp sampler2D skyMap;
+
+void AtmosphereSkySunOffFragShader() {
+ // The rayleigh map's s-coordinate depends on camera height and is computed
+ // on the CPU.
+ float rayleighS = skySunOffPixelParams.x;
+ lowp vec4 color = texture2D(skyMap, vec2(rayleighS, vout_rayleighT.x));
+ gl_FragColor = color;
+}
+#endif // defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_OFF)
+
+//", '=' <repeats 32 times>, " sky sun on (default)", '=' <repeats 22 times>, "
+#if defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON) && !defined(USE_IMPROVED_SHADER_VARIATION)
+varying vec4 vout_rayleighColorAndSkyOpacity;
+varying vec4 vout_vertToCameraDir;
+// The direction vector to the light source in View coordinate system.
+uniform vec4 cameraToSunDirAndExposure;
+// xyz: Attribute for Mie color corresponding to the brightest spot in the
+// sky (i.e. usually the sun's front color during the day, and black
+// during the night).
+// This is computed on the CPU in double floating precision to avoid
+// precision problems on the GPU.
+// w: Sun strength: [0, 1] where 0 = no sun, 1 = full strength.
+uniform vec4 brightestMieColorAndSunStrength;
+
+// Calculates the Rayleigh phase function.
+float getRayleighPhase(float cosAngle2) {
+ return 0.75 + 0.75 * cosAngle2;
+}
+
+// Calculates the Mie phase function.
+float getMiePhase(float cosAngle, float cosAngle2) {
+ return 1.5 * ((1.0 - gMieConst2) / (2.0 + gMieConst2)) * (1.0 + cosAngle2) /
+ pow(1.0 + gMieConst2 - 2.0 * gMieConst * cosAngle, 1.5);
+}
+
+// Returns the luminance of an RGB color.
+float getLuminance(vec3 color) {
+ const vec3 luminance = vec3(0.3, 0.59, 0.11);
+ return dot(luminance, color);
+}
+
+void AtmosphereSkySunOnFragShader() {
+ // Variables needed to compute Rayleigh and Mie phases.
+ float cosAngle = dot(cameraToSunDirAndExposure.xyz,
+ vout_vertToCameraDir.xyz) / length(vout_vertToCameraDir.xyz);
+ // Tweak cosAngle by sunStrength. This dims the sun strength for lower
+ // values of sunStrength.
+ cosAngle *= brightestMieColorAndSunStrength.w;
+ float cosAngle2 = cosAngle * cosAngle;
+ // Compute final color using Rayleigh and Mie phases.
+ // The alpha component gets overwritten later.
+ vec4 color;
+ color.rgb = getRayleighPhase(cosAngle2) * vout_rayleighColorAndSkyOpacity.rgb +
+ getMiePhase(cosAngle, cosAngle2) * brightestMieColorAndSunStrength.rgb;
+ // Tone HDR using constant exposure for the whole scene.
+ color.rgb = vec3(1.0) - exp(color.rgb * -cameraToSunDirAndExposure.w);
+ // Use color's luminance to compute its opacity.
+ float luminanceAlphaComponent = 2.0 * getLuminance(color.rgb);
+ color.a = luminanceAlphaComponent + vout_rayleighColorAndSkyOpacity.a;
+ gl_FragColor = color;
+}
+#endif // defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON) && !defined(USE_IMPROVED_SHADER_VARIATION)
+
+//", '=' <repeats 32 times>, " sky sun on (improved)", '=' <repeats 22 times>, "
+#if defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON) && defined(USE_IMPROVED_SHADER_VARIATION)
+
+// The radius of the atmosphere mesh, divided by the Earth radius.
+const float kAtmosphereMeshRadius = (6378.0 + 170.0) / 6378.0;
+
+uniform vec3 worldOriginInView;
+// The direction vector to the light source.
+uniform vec4 cameraToSunDirAndExposure;
+
+varying vec3 vout_viewPos; // Vertex position in view coordinates.
+varying vec3 vout_sunPos; // Vertex position in Sun coordinates.
+
+// Implements the abstract function defined in atmosphere.glsllib.
+float atmosphereTweak(float r, float mu) {
+ return atmosphereTweaks.x;
+}
+
+// Computes the final pixel color and alpha value from its radiance. The color
+// is computed with a tone mapping operator to map the high dynamic range of the
+// radiance values to the low dynamic range of the screen. The alpha value is
+// used to approximate the correct compositing, which should in theory occur
+// before tone mapping, and not after as we do for stars (see below). This alpha
+// value is computed with an adhoc formula so that stars only appear in the very
+// dark areas of the sky (i.e at night).
+vec4 fragColor(vec3 pixelL) {
+ pixelL = toneMapping(pixelL, atmosphereTweaks.w);
+ return vec4(pixelL, dot(pixelL, vec3(2.0)));
+}
+
+void ImprovedAtmosphereSkySunOnFragShader() {
+ // Computes the view ray direction in view and Sun coordinates.
+ vec3 viewViewRayDir = normalize(vout_viewPos);
+ vec3 sunViewRayDir = normalize(vout_sunPos);
+
+ // Computes the radiance of the background behind the atmosphere. This should
+ // includes the Sun, the Moon and the stars, but here we only take the Sun
+ // into account. The Moon would not be difficult to handle, but rendering the
+ // stars here would require a very high res skymap. Instead, we render them
+ // with points, before rendering the sky, and we approximate the correct
+ // compositing, toneMapping(starL * transmittance + inscatterL), with alpha
+ // blending, i.e. with toneMapping(inscatterL) + (1 - a) * starL. We compute
+ // alpha with an adhoc formula based on toneMapping(inscatterL) -- see the
+ // fragColor function.
+ vec3 backgroundL = outerSunRadiance(sunViewRayDir);
+
+ // Computes the camera to Earth center distance r, the view direction zenith
+ // angle cosinus mu, the Sun zenith angle cosinus muS, and the phase angle
+ // cosinus nu.
+ float r = cameraAndSunState.x;
+ float rMu = -dot(worldOriginInView.xyz, viewViewRayDir);
+ float rMuS = -dot(worldOriginInView.xyz, cameraToSunDirAndExposure.xyz);
+ float nu = dot(viewViewRayDir, cameraToSunDirAndExposure.xyz);
+ bool hitAtmosphere = true;
+
+ // If the camera is outside the atmosphere, moves it to the entry point of the
+ // view ray inside the atmosphere, if it exists (otherwise the view ray does
+ // not traverse the atmosphere, and so we can return the background radiance).
+ if (r > kAtmosphereRadius) {
+ // Computes the distance from the view ray to the Earth center, squared.
+ float hSq = r * r - rMu * rMu;
+ // Computes the distance to the view ray entry point in the atmosphere.
+ float delta = kAtmosphereRadius * kAtmosphereRadius - hSq;
+ float distanceToAtmosphereEntryPoint = -rMu - sqrt(delta);
+ if (delta < 0.0 || distanceToAtmosphereEntryPoint < 0.0) {
+ // The view ray does not hit the atmosphere, return the background color,
+ // i.e the Sun color. In order to avoid discontinuities when switching
+ // from the Sun color computed here, to the Sun color resulting from the
+ // Sun billboard, we use an alpha value going from 1 at kAtmosphereRadius
+ // to 0 at kAtmosphereMeshRadius.
+ const float kAtmosphereRadiusSq = kAtmosphereRadius * kAtmosphereRadius;
+ const float kMeshRadiusSq = kAtmosphereMeshRadius * kAtmosphereMeshRadius;
+ float a = (kMeshRadiusSq - hSq) / (kMeshRadiusSq - kAtmosphereRadiusSq);
+ gl_FragColor = vec4(toneMapping(backgroundL, atmosphereTweaks.w) * a, a);
+ hitAtmosphere = false;
+ } else {
+ // Moves the camera to the view ray entry point inside the atmosphere.
+ r = kAtmosphereRadius;
+ rMu += distanceToAtmosphereEntryPoint;
+ rMuS += distanceToAtmosphereEntryPoint * nu;
+ }
+ }
+
+ if (hitAtmosphere) {
+ // Computes the light which is scattered towards the viewer along the view
+ // ray, and the transmittance of the atmosphere along this ray.
+ vec3 transmittance;
+ vec3 inscatterL = inscatter(r, rMu / r, rMuS / r, nu, atmosphereTweaks.w,
+ transmittance);
+
+ // The pixel radiance is the background radiance, multiplied by the
+ // atmosphere transmittance and augmented by the inscattered light.
+ vec3 pixelL = backgroundL * transmittance + inscatterL;
+
+ gl_FragColor = fragColor(pixelL);
+ }
+}
+#endif // defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON) && defined(USE_IMPROVED_SHADER_VARIATION)
+
+// ", '=' <repeats 65 times>, "
+#if defined(ATMOSPHERE_OFF) && defined(SUN_OFF)
+varying vec4 vout_groundTexCoord; // Transformed texture coordinate.
+
+void NoAtmosphereSunOffFragShader() {
+ vec4 diffuseColor = texture2D(groundTexture, vout_groundTexCoord.st);
+ gl_FragColor = computeDebugPixelColor(diffuseColor);
+}
+#endif // defined(ATMOSPHERE_OFF) && defined(SUN_OFF)
+
+// ", '=' <repeats 68 times>, "
+#if defined(ATMOSPHERE_OFF) && defined(SUN_ON)
+varying vec4 vout_transformedCoords;
+varying float vout_diffuse_factor;
+
+void NoAtmosphereSunOnFragShader() {
+ // Get the texture color for the object.
+ vec4 diffuseColor = texture2D(groundTexture, vout_transformedCoords.xy);
+ diffuseColor.rgb *= vout_diffuse_factor;
+ gl_FragColor = computeDebugPixelColor(diffuseColor);
+}
+#endif // defined(ATMOSPHERE_OFF) && defined(SUN_ON)
+
+// ", '=' <repeats 67 times>, "
+#if defined(ATMOSPHERE_OFF) && defined(GROUND) && defined(OVERLAY)
+varying vec4 vout_texCoord;
+
+void NoAtmosphereGroundOverlayFragShader() {
+ // Get the texture color for the object. The projective component is to
+ // allow us to do Arbitrary Ground Overlays.
+ vec4 texColor = (texture2DProj(groundTexture, vout_texCoord.xyw)) *
+ groundColor;
+
+ // Compute projected texture coordinates
+ vec2 stOverW = vout_texCoord.xy / vout_texCoord.w;
+ // Zero out alpha outside of texture edges.
+ texColor.a = GetMaskedOverlayAlpha(texColor.a, stOverW);
+ gl_FragColor = computeDebugPixelColor(texColor);
+}
+#endif // defined(ATMOSPHERE_OFF) && defined(GROUND) && defined(OVERLAY)
+
+// ", '=' <repeats 64 times>, "
+// Forward-declare top-level functions. (This may fix some pre-processor issues
+// when loading the shaders on Mali embedded GPUs.)
+void AtmosphereGroundSunOnOverlayFragShader();
+void AtmosphereGroundSunOnFragShader();
+void AtmosphereGroundSunOffOverlayFragShader();
+void AtmosphereGroundSunOffFragShader();
+void AtmosphereSkySunOnFragShader();
+void AtmosphereSkySunOffFragShader();
+void ImprovedAtmosphereGroundSunOnFragShader();
+void ImprovedAtmosphereSkySunOnFragShader();
+void NoAtmosphereSunOnFragShader();
+void NoAtmosphereSunOffFragShader();
+void NoAtmosphereGroundOverlayFragShader();
+
+void main()
+{
+ // All #elif directives have been replaced with #else + nested #if.
+ // Do not use #elif directives in shader files because they cause errors
+ // when loaded on Mali-400 based devices. See bug #6662252.
+#if defined(ATMOSPHERE_ON)
+ #if defined(GROUND)
+ #if defined(SUN_ON)
+ #if defined(OVERLAY)
+ #if defined(USE_IMPROVED_SHADER_VARIATION)
+ ImprovedAtmosphereGroundSunOnFragShader();
+ #else
+ AtmosphereGroundSunOnOverlayFragShader();
+ #endif
+ #else
+ #if defined(USE_IMPROVED_SHADER_VARIATION)
+ ImprovedAtmosphereGroundSunOnFragShader();
+ #else
+ AtmosphereGroundSunOnFragShader();
+ #endif
+ #endif
+ #else
+ #if defined(SUN_OFF)
+ #if defined(OVERLAY)
+ AtmosphereGroundSunOffOverlayFragShader();
+ #else
+ AtmosphereGroundSunOffFragShader();
+ #endif
+ #else
+ #error Invalid shader config 1
+ #endif
+ #endif
+ #if defined(QUADRANT_ALPHAS)
+ gl_FragColor.a *= vout_alpha;
+ #endif
+ #else
+ #if defined(SKY)
+ #if defined(SUN_ON)
+ #if defined(USE_IMPROVED_SHADER_VARIATION)
+ ImprovedAtmosphereSkySunOnFragShader();
+ #else
+ AtmosphereSkySunOnFragShader();
+ #endif
+ #else
+ #if defined(SUN_OFF)
+ AtmosphereSkySunOffFragShader();
+ #else
+ #error Invalid shader config 2
+ #endif
+ #endif
+ #else
+ #if defined(USE_IMPROVED_SHADER_VARIATION)
+ gl_FragColor = computeInscatter(gl_FragCoord.xy, atmosphereTweaks.w);
+ #else
+ #error Invalid shader config 3
+ #endif
+ #endif
+ #endif
+#elif defined(ATMOSPHERE_OFF)
+ #if defined(GROUND) && defined(OVERLAY)
+ NoAtmosphereGroundOverlayFragShader();
+ #else
+ #if defined(SUN_ON)
+ NoAtmosphereSunOnFragShader();
+ #elif defined(SUN_OFF)
+ NoAtmosphereSunOffFragShader();
+ #else
+ #error Invalid shader config 4
+ #endif
+ #endif
+ #if defined(QUADRANT_ALPHAS)
+ gl_FragColor.a *= vout_alpha;
+ #endif
+#else
+ #error Invalid shader config 6
+#endif
+
+ // Added by BrianP
+ gl_FragColor = vec4(0, 1, 0, 0);
+}
+
diff --git a/tests/spec/arb_es2_compatibility/ge7.vert b/tests/spec/arb_es2_compatibility/ge7.vert
new file mode 100644
index 00000000..2fc7a324
--- /dev/null
+++ b/tests/spec/arb_es2_compatibility/ge7.vert
@@ -0,0 +1,814 @@
+//!GL2
+#define GE_VERTEX_SHADER
+#define GE_PRECISION mediump
+#define ATMOSPHERE_OFF
+#define GROUND
+#define SUN_OFF
+#define OVERLAY
+#define ENABLE_VERTEX_REJECT
+#if defined(GL_ES)
+precision GE_PRECISION float;
+#else
+#define lowp
+#define mediump
+#define highp
+#endif
+
+uniform mat4 ig_ModelViewMatrix;
+uniform mat4 ig_ModelViewProjectionMatrix;
+uniform mat4 ig_TextureMatrix;
+uniform vec4 ig_LightDirectionInModelSpace;
+uniform vec4 ig_env_atmosphere_custom_state_value;
+uniform lowp vec4 ig_env_atmosphere_custom_color_value;
+uniform lowp float alpha_ref_value;
+
+float saturate(float v) { return clamp(v, 0.0, 1.0); }
+vec2 saturate(vec2 v) { return clamp(v, 0.0, 1.0); }
+vec3 saturate(vec3 v) { return clamp(v, 0.0, 1.0); }
+vec4 saturate(vec4 v) { return clamp(v, 0.0, 1.0); }
+
+// Returns the quadrant portion of the given vertex flags.
+float getQuadrant(vec4 vertexQuadrant) {
+ return dot(vertexQuadrant, vec4(1.0, 2.0, 4.0, 8.0));
+}
+
+// Both getMasked methods assume that quadrantMask has a single 1 and the
+// rest are 0.
+
+vec4 getMaskedVertex(vec4 pos, vec4 quadrantMask, vec4 vertexQuadrant) {
+ return pos * dot(quadrantMask, vertexQuadrant);
+}
+
+float getMaskedAlpha(vec4 quadrantAlphas, vec4 vertexQuadrant) {
+ return dot(quadrantAlphas, vertexQuadrant);
+}
+
+// Computes a vertex color to show which quadrant a vertex is in. Also marks
+// vertices that would be rejected and error conditions (e.g. invalid
+// quadrant).
+vec4 getDebugVertexColor(vec4 quadrantMask, vec4 vertexQuadrant) {
+ vec4 color;
+ float quadrant = getQuadrant(vertexQuadrant);
+ if (quadrant == 1.0) {
+ // Red
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ } else if (quadrant == 2.0) {
+ // Green
+ color = vec4(0.0, 1.0, 0.0, 1.0);
+ } else if (quadrant == 4.0) {
+ // Blue
+ color = vec4(0.0, 0.0, 1.0, 1.0);
+ } else if (quadrant == 8.0) {
+ // Cyan
+ color = vec4(0.0, 1.0, 1.0, 1.0);
+ } else if (quadrant == 0.0) {
+ // Vertex didn't have a quadrant bit set. Mark as saturated Yellow.
+ color = vec4(10.0, 10.0, 0.0, 1.0);
+ } else if (quadrant == 15.0) {
+ // All quadrant bits were set. Mark as White.
+ color = vec4(10.0, 10.0, 10.0, 1.0);
+ } else {
+ // More than one quadrant bit was set or a quadrant bit was set to
+ // something other than 1.0, so flag verts in saturated Magenta.
+ color = vec4(10.0, 0.0, 10.0, 1.0);
+ }
+ // Make hidden quadrants dimmer.
+ if (dot(quadrantMask, vertexQuadrant) == 0.)
+ color *= .5;
+ return color;
+}
+
+#ifdef DEBUG_QUADRANT_COLORS
+// Used by the pixel shader to show quadrants, culled verts and error
+// conditions when DEBUG_QUADRANT_COLORS is defined.
+varying vec4 vout_debug_color;
+#endif
+
+// The \"discard\" instruction is not available for vertex shaders, so
+// this function needs to be excluded when parsing a vertex shader.
+#ifdef GE_PIXEL_SHADER
+
+// When debugging is on, modulates the pixel color by the debug color output
+// from the vertex shader. Otherwise, the given pixel color is returned
+// unchanged.
+vec4 computeDebugPixelColor(vec4 pixelShaderColor) {
+// OGL ES 2.0 does not support alpha test, so need to do it in the
+// shader.
+#if defined(GL_ES) && !defined(FORCE_NO_ALPHA_TEST)
+// Terrain and sky don't use alpha test.
+#if defined(OVERLAY) || defined(MODEL)
+ // alpha_ref_value is set by igVisualContext, and will be -1 if alpha test
+ // is off.
+ if (pixelShaderColor.a < alpha_ref_value) {
+ discard;
+ }
+#endif // defined(OVERLAY) || defined(MODEL)
+#endif // defined(GL_ES) && !defined(FORCE_NO_ALPHA_TEST)
+
+#ifdef DEBUG_QUADRANT_COLORS
+ return pixelShaderColor * vout_debug_color;
+#else
+ return pixelShaderColor;
+#endif
+}
+
+#endif // GE_PIXEL_SHADER
+#if defined(PACKED_VERTS)
+#define igv_Vertex ig_VertexAttr0
+#define igv_MultiTexCoord0 ig_VertexAttr1
+attribute vec3 igv_Vertex;
+attribute vec2 igv_MultiTexCoord0;
+#else
+#define igv_Vertex ig_Vertex
+#define igv_MultiTexCoord0 ig_MultiTexCoord0
+attribute vec4 igv_Vertex;
+attribute vec4 igv_MultiTexCoord0;
+#endif
+
+attribute vec3 ig_Normal;
+attribute vec4 ig_Color;
+
+uniform vec3 worldOriginInView;
+uniform vec4 dirToCameraAndFogDensity;
+uniform vec4 groundSunOffVertexParams;
+uniform vec4 projScalingFactor;
+uniform vec4 quadrantMask;
+
+#if defined(SUN_ON)
+// The direction vector to the light source.
+uniform vec4 cameraToSunDirAndExposure;
+// .y has Normalized Camera Dot Light
+// .z has Max Camera Angle subtended by planet
+// .w has Camera Height * Camera Height
+uniform vec4 cameraLightInfo;
+// .x has ground shader start depth
+// .y has scatter power coefficient
+// .z has rayleighToneDown Coefficient
+// .w has atmosphere rayleigh opacity alpha
+uniform vec4 startupConsts;
+// xyz: Extra ambient color that is stronger during sunsets (and sunrises).
+// w: density used in fog exp2 function.
+uniform vec4 sunsetAmbientAndFogDensity;
+#endif
+
+#if defined(ATMOSPHERE_ON) && defined(GROUND)
+// XYZ: The x, y, and w-coordinates of the projective rayleighTure coordinate.
+// We use projective rayleighTures for Arbitrary Ground Overlays.
+// W: fog_factor between 0 (no fog) and 1 (full fog).
+varying vec4 vout_texCoordAndFogFactor;
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND)
+
+#if defined(QUADRANT_ALPHAS)
+uniform vec4 quadrantAlphas; // Alpha 0-1 per quadrant.
+// TODO(jrohlf): Combine with vec4 if possible.
+varying float vout_alpha; // Single alpha for entire tri, 0-1.
+#endif
+
+//", '=' <repeats 22 times>, " Constants ", '=' <repeats 33 times>, "
+// The number of sample points taken along the ray.
+const int samples = 2;
+// Reciprocal of the sun light color.
+const vec3 invWavelength = 1.0 /
+ vec3(0.17850625, 0.10556001, 0.050906640625);
+// Altitude of Atmosphere in km
+const float atmosphereAltiude = 170.0;
+// Radius of planet in km
+const float planetRadius = 6378.0;
+// Relative Radius of the planet.
+const float innerRadius = 1.0;
+const float innerRadius2 = innerRadius * innerRadius;
+// Radius of the outer atmosphere.
+const float outerRadius = innerRadius + (atmosphereAltiude / planetRadius);
+const float outerRadius2 = outerRadius * outerRadius;
+// Rayleigh scattering constant.
+const float kr = 0.0025;
+// Brightness of the sun.
+const float eSun = 25.0;
+// Mie scattering constant.
+const float km = 0.001;
+// Pi.
+const float pi = 3.1415926535897932384626433832795;
+// Convenience constants.
+const float krESun = kr * eSun;
+const float kmESun = km * eSun;
+const float kr4Pi = kr * 4.0 * pi;
+const float km4Pi = km * 4.0 * pi;
+
+// The scale depth (the altitude at which the average atmospheric density is
+// found).
+const float scaleDepth = 0.15;
+const float invScaleDepth = 1.0 / scaleDepth;
+// Reciprocal of the atmosphere's depth.
+const float atmosphereDepthInv = 1.0 / (outerRadius - innerRadius);
+const float scaleOverScaleDepth = atmosphereDepthInv / scaleDepth;
+
+// In Fixed function, we use a trick of Sun's color to be of intensity
+// 3.0 to get better correlation between time of day and nDotL.
+// Using the same trick in shaders.
+const float kSunColor = 3.0;
+
+// Transparent color used for hiding white seams behind terrain cracks.
+// Note: all four components must be 0.0 due to the (more or less) additive
+// blending function.
+const vec4 kTransparent = vec4(0.0);
+
+//", '=' <repeats 22 times>, " Functions ", '=' <repeats 30 times>, "
+// The scale equation calculated by Vernier's Graphical Analysis.
+float scale(float cosAngle) {
+ float x = 1.0 - cosAngle;
+ return scaleDepth *
+ exp(-0.00287 + x * (0.459 + x * (3.83 + x * (-6.80 + x * 5.25))));
+}
+
+// Returns the near intersection point of a line and a sphere centered around
+// the origin.
+float getNearIntersection(vec3 vertPos, vec3 rayDir, float distance2, float fRadius2) {
+ float b = 2.0 * dot(vertPos, rayDir);
+ float c = distance2 - fRadius2;
+ float determ = max(0.0, b * b - 4.0 * c);
+ return 0.5 * (-b - sqrt(determ));
+}
+
+// Returns the far intersection point of a line and a sphere centered around
+// the origin.
+float getFarIntersection(vec3 vertPos, vec3 rayDir, float distance2, float fRadius2) {
+ float b = 2.0 * dot(vertPos, rayDir);
+ float c = distance2 - fRadius2;
+ float determ = max(0.0, b * b - 4.0 * c);
+ return 0.5 * (-b + sqrt(determ));
+}
+
+// Returns the luminance of an RGB color.
+float getLuminance(vec3 color) {
+ const vec3 luminance = vec3(0.3, 0.59, 0.11);
+ return dot(luminance, color);
+}
+
+//", '=' <repeats 30 times>, " ground sun off vertex
+#if defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_OFF)
+
+// Multiplier for rayleigh result; when 0, scattering calculation are omitted
+uniform vec4 rayleighAttenuator;
+
+#if !defined(USE_SIMPLIFIED_SHADER_VARIATION)
+// Texcoord for blending between 2 textures on same geometry and rayleighT
+// param stuffed in z component.
+varying vec4 vout_blendTexCoordAndRayleighT;
+#endif
+
+// Vertex shader program.
+void AtmosphereGroundSunOffVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ vec4 texCoord = vec4(igv_MultiTexCoord0.xy, 0.0, 1.0);
+
+#if !defined(USE_SIMPLIFIED_SHADER_VARIATION)
+ // We project the vertex direction (from the planet origin) onto the
+ // camera direction (from the planet origin) to compute the rayleigh
+ // map's t-coordinate.
+ vec3 posInView = (ig_ModelViewMatrix * projScalingFactor.x * position).xyz;
+ vec3 dirToPos = normalize(posInView - worldOriginInView);
+ vec3 dirToCamera = dirToCameraAndFogDensity.xyz;
+ float projected_length = dot(dirToCamera, dirToPos);
+ float rayleighTTranslation = groundSunOffVertexParams.x;
+ float rayleighTScale = groundSunOffVertexParams.y;
+ float rayleighT = (projected_length + rayleighTTranslation) *
+ rayleighTScale;
+ rayleighT = rayleighT * rayleighAttenuator.x + (1.0 - rayleighAttenuator.x);
+#endif
+
+ vec4 vert_pos_clip = ig_ModelViewProjectionMatrix * position;
+
+#if !defined(USE_SIMPLIFIED_SHADER_VARIATION)
+ // Compute fog factor.
+ float fogDensity = dirToCameraAndFogDensity.w;
+ float fogTemp = fogDensity * vert_pos_clip.z;
+ float fogFactor = exp(-(fogTemp * fogTemp));
+ vout_texCoordAndFogFactor.w = fogFactor;
+#endif
+
+ vec4 transformedTexCoord = ig_TextureMatrix * texCoord;
+ vout_texCoordAndFogFactor.xyz = transformedTexCoord.xyw;
+#if !defined(USE_SIMPLIFIED_SHADER_VARIATION)
+ vout_blendTexCoordAndRayleighT.x = rayleighT;
+ vout_blendTexCoordAndRayleighT.y = rayleighT;
+ vout_blendTexCoordAndRayleighT.z = rayleighT;
+ vout_blendTexCoordAndRayleighT.w = rayleighT;
+#endif
+
+ gl_Position = vert_pos_clip;
+}
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_OFF)
+
+//", '=' <repeats 33 times>, " Ground sun on
+
+#if defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON)
+
+// has_lighting tracks the igVisualContext lighting enabled state.
+// Diorama buildings that do not have normals have lighting turned off in the
+// scene-graph and should do lighting using the vertex normal.
+// Detecting 0-length normals in the shader does not appear to
+// work for diormam buildings (perhaps because the normal data is garbage,
+// instead of being absent like it is in the terrain data).
+// TODO(baustin): Remove the has_lighting test once the 0-length check can be
+// made to work for diorama buildings.
+uniform float has_lighting;
+
+#if defined(USE_IMPROVED_SHADER_VARIATION)
+// Vertex position in view coordinates and dot product between normal and Sun.
+varying vec4 vout_viewPosAndNormalDotSun;
+#else
+// Vertex shader's output.
+// RGB: The Rayleigh color.
+varying vec3 vout_rayleigh;
+// RGB: The adjusted Mie color.
+varying vec3 vout_adjustedMie;
+#endif
+
+// Vertex shader program.
+void AtmosphereGroundSunOnVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ vec4 texCoord = vec4(igv_MultiTexCoord0.xy, 0.0, 1.0);
+ vec3 normal = ig_Normal;
+
+ // projScalingFactor is some kind of hack to handle poor precision on
+ // some platforms, I dunno the details.
+ mat4 hackedModelView = ig_ModelViewMatrix * projScalingFactor.x;
+
+ highp vec4 posInView = hackedModelView * position;
+ // Compute vertex's color using its position projected at sea level.
+ // This avoids artifacts when the vertex is outside the frustum and makes
+ // it easier to compute the distance to the horizon.
+ highp vec3 unprojectedVertPos = posInView.xyz - worldOriginInView;
+ highp vec3 vertNorm = normalize(unprojectedVertPos);
+
+ // If normals are not supplied or lighting is turned off, use sphere normals.
+ highp vec3 normToUse = vertNorm;
+ if (has_lighting == 1.0) {
+ highp float normalLen = dot(normal.xyz, normal.xyz);
+ // Not sure how fast this if-test is.
+ // TODO(jrohlf,baustin): See if ? or mix() might be faster (mix() isn't
+ // working for diorama buildings, possibly because the normals aren't
+ // normalized.
+ if (normalLen > 0.0) {
+ // NOTE: normal xform should use inverse transpose but I don't think we
+ // have any scales in modelview.
+ normToUse = (hackedModelView * vec4(normal, 0.0)).xyz;
+ normToUse = normalize(normToUse);
+ }
+ }
+
+ highp float nDotL = dot(normToUse, cameraToSunDirAndExposure.xyz);
+
+#if !defined(USE_IMPROVED_SHADER_VARIATION)
+ // Multiply by Sun Color which is really high intensity and saturate
+ nDotL = saturate(kSunColor * nDotL);
+
+ // Create new coordinate system with the view orientation but world origin.
+ // All computation is done in this new coordinate system.
+ highp vec3 cameraPos = -worldOriginInView;
+ highp float cameraHeight = cameraLightInfo.x;
+ highp float cameraHeight2 = cameraLightInfo.w;
+
+ // Get the ray from the camera to the vertex and its length.
+ highp vec3 rayDir = unprojectedVertPos - cameraPos;
+ highp float farDist = length(rayDir);
+ rayDir /= farDist;
+
+ highp vec3 startPos = cameraPos;
+ // Initial scattering offset.
+ highp float startDepth = startupConsts.x;
+ // We use power function to create gradient for limiting rayleigh
+ // affect closer horizon. Lower the exponent, more scattering we
+ // get all over planet. To get scattering glow on planet when viewed
+ // from distance, horizonExp depends on altitude.
+ highp float horizonExp = startupConsts.y;
+ // Since we have not using exposure function in fragment shader for
+ // ground, rayleigh component adds to the existing color and the result
+ // tends to saturate much too soon. Hence we add a tonedown scale which
+ // is function of altitude and proximity to horizon.
+ highp float rayleighToneDownScale = startupConsts.z;
+
+ // Calculate where our ray hits the atmosphere to find the point where
+ // we start accumulating its color.
+ // TODO(quarup): Get rid of this conditional.
+ if (cameraHeight >= outerRadius) {
+ // Camera is outside the atmosphere.
+ // Calculate the closest intersection of the ray with the outer atmosphere
+ // (which is the near point of the ray passing through the atmosphere).
+ highp float nearDist = getNearIntersection(cameraPos, rayDir, cameraHeight2, outerRadius2);
+ // Ray's start position within the atmosphere.
+ startPos += rayDir * nearDist;
+ // Ray's distance within the atmosphere.
+ farDist -= nearDist;
+ }
+
+ // Initialize constants needed for the scattering equations.
+ // vertNorm is normalized
+ highp float cameraAngle = max(0.0, dot(-rayDir, vertNorm));
+ highp float lightAngle = dot(cameraToSunDirAndExposure.xyz, vertNorm);
+ highp float cameraScale = scale(cameraAngle);
+ highp float lightScale = scale(lightAngle);
+ highp float cameraOffset = startDepth * cameraScale;
+ highp float scaleSum = lightScale + cameraScale;
+
+ // Initialize the scattering loop variables.
+ highp float sampleLength = farDist / float(samples);
+ highp float scaledLength = sampleLength * atmosphereDepthInv;
+ highp vec3 sampleRay = rayDir * sampleLength;
+ highp vec3 samplePoint = startPos + sampleRay * 0.5;
+
+ // Now loop through sample points on the ray and accumulate the color
+ // using the scattering equations (including surface-scattering).
+ highp vec3 frontColor = vec3(0.0, 0.0, 0.0);
+ highp vec3 attenuate;
+ for(int i = 0; i < samples; i++) {
+ highp float sampleHeight = length(samplePoint);
+ highp float sampleDepth =
+ exp(scaleOverScaleDepth * (innerRadius - sampleHeight));
+ highp float sampleScatter = sampleDepth * scaleSum - cameraOffset;
+ attenuate = exp(-sampleScatter * (invWavelength * kr4Pi + km4Pi));
+ frontColor += attenuate * (sampleDepth * scaledLength);
+ samplePoint += sampleRay;
+ }
+
+ // Compute how \"close\" the vertex is to the horizon. Vertices close
+ // to the horizon correspond to one, and vertices under the camera
+ // correspond to zero.
+ highp float closeToHorizon = 1.0 - cameraAngle;
+ highp float closeToCamera = 1.0 - closeToHorizon*closeToHorizon;
+ // Compute rayleigh scale factor. Higher closer to horizon and
+ // at higher altitudes.
+ highp float scaledRayleighFactor = rayleighToneDownScale * pow(closeToHorizon, horizonExp);
+
+ // Base ambient color for dark shaded ground objects.
+ highp vec3 kBaseAmbientColor = vec3(0.12, 0.12, 0.15);
+ // Add ambient light to geometry with low N.L shading. This allows the
+ // user to always see the dark areas of mountains, buildings, etc.
+ highp float darkShadedAmbientFactor = 1.0 - nDotL;
+ // Compute night ambient color factor so that it is strongest at night
+ // (i.e. low attenuate luminance) and weakest during the day
+ // (i.e. high attenuate luminance). This allows the user to always see
+ // ground objects at night.
+ highp float nightAmbientTemp = getLuminance(attenuate);
+ highp float nightAmbientFactor = 1.0 - nightAmbientTemp * nightAmbientTemp;
+ // Compute ambient contribution. Make ambient light stronger
+ // for nearby vertices, which creates a \"head lamp\" effect.
+ highp float ambientFactor =
+ closeToCamera * (darkShadedAmbientFactor + nightAmbientFactor);
+ highp vec3 headlampAmbientContribution = kBaseAmbientColor * ambientFactor;
+ // The extra sunset ambient contribution keeps the planet from looking too
+ // dark during sunset and sunrise.
+ highp vec3 sunsetAmbient = sunsetAmbientAndFogDensity.xyz;
+ highp vec3 ambientContribution = headlampAmbientContribution + sunsetAmbient;
+
+ // Compute how close to noon it is.
+ highp float closeToNoon = cameraLightInfo.y;
+ // When it is close to noon, add light close to the camera in order
+ // to show full contrast of the textures near the user.
+ highp float closeToNoonFactor = closeToCamera * closeToNoon;
+
+ // Compute fog factor.
+ highp float fogDensity = sunsetAmbientAndFogDensity.w;
+ highp float fogTemp = fogDensity * farDist;
+ highp float fogFactor = exp(-(fogTemp * fogTemp));
+#endif
+
+ // Transform vertex position.
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+#if defined(USE_IMPROVED_SHADER_VARIATION)
+ vout_viewPosAndNormalDotSun = vec4(posInView.xyz, nDotL);
+ float fogFactor = 0.0;
+#else
+ // Compute Rayleigh color and make it strongest at the horizon.
+ const vec3 kMaxRayleighContribution = vec3(0.5, 0.5, 0.8);
+ vout_rayleigh.rgb = min(kMaxRayleighContribution,
+ frontColor * (invWavelength * krESun + kmESun) * scaledRayleighFactor);
+ // Compute Mie color.
+ highp vec3 mieColor = attenuate;
+ highp vec3 adjustedMieColor = saturate(
+ (mieColor + vec3(closeToNoonFactor)) * nDotL + ambientContribution);
+ vout_adjustedMie.rgb = adjustedMieColor;
+#endif
+ // Set transformed texture coordinates.
+ highp vec4 transformedTexCoord = ig_TextureMatrix * texCoord;
+ vout_texCoordAndFogFactor.xyz = transformedTexCoord.xyw;
+ vout_texCoordAndFogFactor.w = fogFactor;
+}
+#endif // defined(ATMOSPHERE_ON) && defined(GROUND) && defined(SUN_ON)
+
+//", '=' <repeats 38 times>, " sky sun off
+
+#if defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_OFF)
+
+uniform vec4 skySunOffVertexParams;
+
+// X: Rayleigh map's t-coordinate.
+varying vec4 vout_rayleighT;
+
+// Vertex shader program.
+void AtmosphereSkySunOffVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+
+ // From the position's Y-coordinate (in atmosphere space), we can
+ // compute its rayleigh color from the rayleigh map.
+ float rayleighTTranslation = skySunOffVertexParams.x;
+ float rayleighTScale = skySunOffVertexParams.y;
+ // Look-up's t-coordinate.
+ float rayleighT = (position.y + rayleighTTranslation) * rayleighTScale;
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+
+ // Clamp vertex depth to the far plane. This forces the sky to always
+ // be drawn even if the far plane is closer than the outer atmosphere.
+ // Some drivers have problems when z == w, so ensure z is strictly smaller.
+ gl_Position.z = min(gl_Position.z, gl_Position.w * 0.99999);
+
+ vout_rayleighT = vec4(rayleighT);
+}
+#endif // defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_OFF)
+
+//", '=' <repeats 39 times>, " sky sun on
+#if defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON)
+
+#if defined(USE_IMPROVED_SHADER_VARIATION)
+// Transformation from view to Sun coordinates. This coordinate system is
+// centered on the Earth and its z axis points towards the Sun.
+uniform mat4 viewToSun;
+
+varying vec3 vout_viewPos; // Vertex position in view coordinates.
+varying vec3 vout_sunPos; // Vertex position in Sun coordinates.
+#else
+varying vec4 vout_rayleighColorAndSkyOpacity; // The Rayleigh color
+varying vec4 vout_vertToCameraDir; // Dir from ray to camera.
+#endif
+
+// Vertex shader program.
+void AtmosphereSkySunOnVertexShader() {
+
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ // projScalingFactor is some kind of hack to handle poor precision on
+ // some platforms, I dunno the details.
+ mat4 hackedModelView = ig_ModelViewMatrix * projScalingFactor.x;
+
+#if !defined(USE_IMPROVED_SHADER_VARIATION)
+ // Make up a new coordinate system with the view orientation but world origin.
+ // All computation is done in this new coordinate system.
+ vec3 cameraPos = -worldOriginInView;
+ float cameraHeight = cameraLightInfo.x;
+ float cameraHeightInv = 1.0 / cameraHeight;
+ float cameraHeight2 = cameraLightInfo.w;
+ vec4 posInView = hackedModelView * position;
+ vec3 vertPos = posInView.xyz - worldOriginInView;
+
+ // Get the ray from the camera to the vertex and its length (which is the
+ // far point of the ray passing through the atmosphere).
+ vec3 rayDir = vertPos - cameraPos;
+ float farDist = length(rayDir);
+ rayDir /= farDist;
+
+ vec3 startPos;
+ float startAngle;
+ float startOffset;
+ // Calculate where our ray hits the atmosphere to find the point where
+ // we start accumulating its color.
+ // TODO(quarup): Get rid of this conditional.
+ if (cameraHeight < outerRadius) {
+ // If we're inside the atmosphere, then start accumulating from the
+ // camera position.
+ startPos = cameraPos;
+ // Initial scattering constants.
+ float startDepth = exp(scaleOverScaleDepth * (innerRadius - cameraHeight));
+ startAngle = dot(rayDir, startPos) * cameraHeightInv;
+ startOffset = startDepth * scale(startAngle);
+ } else {
+ // Camera is outside the atmosphere.
+ // Calculate the closest intersection of the ray with the outer atmosphere
+ // (which is the near point of the ray passing through the atmosphere).
+ float nearDist = getNearIntersection(cameraPos, rayDir, cameraHeight2, outerRadius2);
+ // Ray's start position within the atmosphere.
+ startPos = cameraPos + rayDir * nearDist;
+ // Ray's distance within the atmosphere.
+ farDist -= nearDist;
+ // Initial scattering constants.
+ startAngle = dot(rayDir, startPos) / outerRadius;
+ float startDepth = exp(-invScaleDepth);
+ startOffset = startDepth * scale(startAngle);
+ }
+
+ // Initialize the scattering loop variables.
+ float sampleLength = farDist / float(samples);
+ float scaledLength = sampleLength * atmosphereDepthInv;
+ vec3 sampleRay = rayDir * sampleLength;
+ vec3 samplePoint = startPos + sampleRay * 0.5;
+
+ // Now loop through sample points on the ray and accumulate the color
+ // using the scattering equations.
+ vec3 frontColor = vec3(0.0, 0.0, 0.0);
+ vec3 attenuate;
+ for(int i = 0; i < samples; i++) {
+ // TODO(quarup): Simplify this.
+ float sampleHeight = length(samplePoint);
+ float sampleDepth = exp(scaleOverScaleDepth * (innerRadius - sampleHeight));
+ float lightAngle = dot(cameraToSunDirAndExposure.xyz, samplePoint), sampleHeight;
+ float cameraAngle = dot(rayDir, samplePoint) / sampleHeight;
+ float sampleScatter =
+ (startOffset + sampleDepth*(scale(lightAngle) - scale(cameraAngle)));
+ attenuate = exp(-sampleScatter * (invWavelength * kr4Pi + km4Pi));
+ frontColor += attenuate * (sampleDepth * scaledLength);
+ samplePoint += sampleRay;
+ }
+#endif
+
+ // Finally, scale the Mie and Rayleigh colors and set up the varying
+ // variables for the pixel shader.
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+
+ // Clamp vertex depth to the far plane. This forces the sky to always
+ // be drawn even if the far plane is closer than the outer atmosphere.
+ // Some drivers have problems when z == w, so ensure z is strictly smaller.
+ gl_Position.z = min(gl_Position.z, gl_Position.w * 0.99999);
+
+#if defined(USE_IMPROVED_SHADER_VARIATION)
+ vout_viewPos = (hackedModelView * position).xyz;
+ vout_sunPos = (viewToSun * vec4(vout_viewPos, 0.0)).xyz;
+#else
+ // Handle White Seams here.
+ // Idea is that we make the part of sphere occluded by planet transparent.
+ // Therefore terrain cracks show the color buffer's clear color instead.
+ // (Note: opaque colors (instead of transparent) are distorted by the HDR
+ // tonemap computation and the (more or less) additive blending function.)
+ // cosAngleByPlanet: cosine of angle subtended by planet at camera
+ // cosVertAngle : cosine of angle subtended by current vertex at camera
+ float cosAngleByPlanet = cameraLightInfo.z;
+ float cosVertAngle = -dot(rayDir, cameraPos) * cameraHeightInv;
+ vec4 computedRayleighColorAndSkyOpacity =
+ vec4(frontColor * (invWavelength * krESun), startupConsts.w);
+ vout_rayleighColorAndSkyOpacity = cosVertAngle > cosAngleByPlanet ?
+ kTransparent : computedRayleighColorAndSkyOpacity;
+ vout_vertToCameraDir.xyz = cameraPos - vertPos;
+ // Fix for a driver bug on ATI Mobility FireGL V3200 (Driver 8.362.0.0)
+ // for OpenGL mode.
+ // Problem: The textures looked distorted.
+ // Reason: Two sets of shaders (atmosphere_ground and atomsphere_model_space)
+ // used different length of TEXCOORD1 with my last change. With this
+ // change, TEXCOORD1.w in atmosphere_groud fragment shader was getting
+ // 0 irrespective of whatever value you set in vertexshader. It seems
+ // that some validation for length of texture coordinates was missing
+ // in driver when fragment programs were switched.
+ // Workaround: Add TEXCOORD1.w back in all shaders. Avoid any computation by
+ //", ' ' <repeats 13 times>, "just setting it to 1.0
+ vout_vertToCameraDir.w = 1.0;
+#endif
+}
+#endif // defined(ATMOSPHERE_ON) && defined(SKY) && defined(SUN_ON)
+
+// ", '=' <repeats 74 times>, "
+#if defined(ATMOSPHERE_ON)
+ #if defined(GROUND)
+ void AtmosphereGroundVertexShader() {
+ #if defined(SUN_ON)
+ AtmosphereGroundSunOnVertexShader();
+ #elif defined(SUN_OFF)
+ AtmosphereGroundSunOffVertexShader();
+ #else
+ #error Invalid shader config 1
+ #endif
+ #if defined(ENABLE_VERTEX_REJECT)
+ gl_Position = getMaskedVertex(gl_Position, quadrantMask, ig_Color);
+ #endif
+ #if defined(DEBUG_QUADRANT_COLORS)
+ vout_debug_color = getDebugVertexColor(quadrantMask, ig_Color);
+ #endif
+ #if defined(QUADRANT_ALPHAS)
+ vout_alpha = getMaskedAlpha(quadrantAlphas, ig_Color);
+ #endif
+ }
+ #elif defined(SKY)
+ void AtmosphereSkyVertexShader() {
+ #if defined(SUN_ON)
+ AtmosphereSkySunOnVertexShader();
+ #elif defined(SUN_OFF)
+ AtmosphereSkySunOffVertexShader();
+ #else
+ #error Invalid shader config 2
+ #endif
+ }
+ #elif defined(USE_IMPROVED_SHADER_VARIATION)
+ void AtmosphereLookupTableShader() {
+ gl_Position = vec4(igv_Vertex.xy, 0.0, 1.0);
+ }
+ #endif
+#endif // ATMOSPHERE_ON
+
+
+#if defined(ATMOSPHERE_OFF)
+//", '=' <repeats 35 times>, " Sun off
+#if defined(SUN_OFF)
+varying vec4 vout_groundTexCoord; // Transformed texture coordinate.
+
+// Vertex shader program.
+void NoAtmosphereSunOffVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ vec4 groundTexCoord = vec4(igv_MultiTexCoord0.xy, 0.0, 1.0);
+
+ // Transform coordinate and texture coordinates.
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+ vout_groundTexCoord = ig_TextureMatrix * groundTexCoord;
+}
+#endif // SUNOFF
+
+//", '=' <repeats 35 times>, " Sun on
+#if defined(SUN_ON)
+// xy: base texture coordinates.
+// zw: blend texture coordinates.
+varying vec4 vout_transformedCoords; // Transformed texture coordinate.
+// x: diffuse factor that contains N.L and ambient contribution.
+varying float vout_diffuse_factor;
+
+// Vertex shader program.
+void NoAtmosphereSunOnVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ vec4 groundTexCoord = vec4(igv_MultiTexCoord0.xy, 0.0, 1.0);
+ vec3 normal = ig_Normal;
+
+ // normalLen should be 0 if normals not supplied or 1 if supplied - assumes
+ // normals are normalized. This allows us to use multiplies instead
+ // of slow if or ?. TODO(jrohlf): See if ? might be faster.
+ highp float normalLen = dot(normal.xyz, normal.xyz);
+ // If normals not supplied use sphere normals.
+ // NOTE: normal xform should use inverse transpose but I don't think we
+ // have any scales in modelview.
+ highp vec3 normToUse = mix(
+ (ig_ModelViewMatrix * position).xyz - worldOriginInView,
+ (ig_ModelViewMatrix * vec4(normal, 0.)).xyz,
+ normalLen);
+ normToUse = normalize(normToUse);
+ highp float nDotL = dot(normToUse, cameraToSunDirAndExposure.xyz);
+ // When atmosphere shaders are off, the ambient contribution comes in
+ // the \"exposure\" variable.
+ float ambient_light = cameraToSunDirAndExposure.w;
+ // Transform coordinate and texture coordinates.
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+ vout_transformedCoords.xy = (ig_TextureMatrix * groundTexCoord).xy;
+ vout_transformedCoords.zw = vec2(0.0, 0.0);
+ vout_diffuse_factor = min(1.0, ambient_light + max(0.0, nDotL));
+}
+#endif // SUN_ON
+
+//", '=' <repeats 26 times>, " Ground overlay no atmosphere
+#if defined(GROUND) && defined(OVERLAY)
+varying vec4 vout_texCoord;
+void NoAtmosphereGroundOverlayVertexShader() {
+ vec4 position = vec4(igv_Vertex.xyz, 1.0);
+ vec4 texCoord = vec4(igv_MultiTexCoord0.xy, 0.0, 1.0);
+
+ // Very simple pixel shader, handles modelview/projection matrix and
+ // texture matrix just like fixed function, but when specifying a pixel
+ // shader, we must have a vertex shader.
+ gl_Position = ig_ModelViewProjectionMatrix * position;
+ vout_texCoord = ig_TextureMatrix * texCoord;
+}
+#endif // GROUND AND OVERLAY
+#endif // ATMOSPHERE_OFF
+
+// ", '=' <repeats 74 times>, "
+void main() {
+#if defined(ATMOSPHERE_ON)
+ #if defined(GROUND)
+ AtmosphereGroundVertexShader();
+ #elif defined(SKY)
+ AtmosphereSkyVertexShader();
+ #elif defined(USE_IMPROVED_SHADER_VARIATION)
+ AtmosphereLookupTableShader();
+ #else
+ #error Invalid shader config 3
+ #endif
+#elif defined(ATMOSPHERE_OFF)
+ #if defined(GROUND) && defined(OVERLAY)
+ NoAtmosphereGroundOverlayVertexShader();
+ #else
+ #if defined(SUN_ON)
+ NoAtmosphereSunOnVertexShader();
+ #elif defined(SUN_OFF)
+ NoAtmosphereSunOffVertexShader();
+ #else
+ #error Invalid shader config 4
+ #endif
+ #endif
+ #if defined(ENABLE_VERTEX_REJECT)
+ gl_Position =
+ getMaskedVertex(gl_Position, quadrantMask, ig_Color);
+ #endif
+ #if defined(DEBUG_QUADRANT_COLORS)
+ vout_debug_color = getDebugVertexColor(quadrantMask, ig_Color);
+ #endif
+ #if defined(QUADRANT_ALPHAS)
+ vout_alpha = getMaskedAlpha(quadrantAlphas, ig_Color);
+ #endif
+#else
+ #error Invalid shader config 6
+#endif
+
+ // Added by BrianP:
+ gl_Position = gl_Vertex;
+}
+