shadermanager.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:83k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // shadermanager.cpp
  2. //
  3. // Copyright (C) 2001-2007, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include "celutil/util.h"
  10. #include "gl.h"
  11. #include "glext.h"
  12. #include "shadermanager.h"
  13. #include <cmath>
  14. #include <iostream>
  15. #include <fstream>
  16. #include <sstream>
  17. #include <iomanip>
  18. #include <cstdio>
  19. #include <cassert>
  20. using namespace std;
  21. // GLSL on Mac OS X appears to have a bug that precludes us from using structs
  22. // #define USE_GLSL_STRUCTS
  23. ShaderManager g_ShaderManager;
  24. static const char* errorVertexShaderSource =
  25.     "void main(void) {n"
  26.     "   gl_Position = ftransform();n"
  27.     "}n";
  28. static const char* errorFragmentShaderSource =
  29.     "void main(void) {n"
  30.     "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);n"
  31.     "}n";
  32. static const string CommonHeader("#version 110n");
  33. ShaderManager&
  34. GetShaderManager()
  35. {
  36.     return g_ShaderManager;
  37. }
  38. ShaderProperties::ShaderProperties() :
  39.     nLights(0),
  40.     texUsage(0),
  41.     lightModel(DiffuseModel),
  42.     shadowCounts(0),
  43.     effects(0)
  44. {
  45. }
  46. bool
  47. ShaderProperties::usesShadows() const
  48. {
  49.     return  (texUsage & RingShadowTexture) != 0 ||
  50.              (texUsage & CloudShadowTexture) != 0 ||
  51.              shadowCounts != 0;
  52. }
  53. bool
  54. ShaderProperties::usesFragmentLighting() const
  55. {
  56.     if ((texUsage & NormalTexture) != 0 || lightModel == PerPixelSpecularModel)
  57.         return true;
  58.     else
  59.         return false;
  60. }
  61. unsigned int
  62. ShaderProperties::getShadowCountForLight(unsigned int i) const
  63. {
  64.     return (shadowCounts >> i * 2) & 3;
  65. }
  66. void
  67. ShaderProperties::setShadowCountForLight(unsigned int light, unsigned int n)
  68. {
  69.     assert(n <= MaxShaderShadows);
  70.     assert(light < MaxShaderLights);
  71.     if (n <= MaxShaderShadows && light < MaxShaderLights)
  72.     {
  73.         shadowCounts &= ~(3 << light * 2);
  74.         shadowCounts |= n << light * 2;
  75.     }
  76. }
  77. bool
  78. ShaderProperties::hasShadowsForLight(unsigned int light) const
  79. {
  80.     assert(light < MaxShaderLights);
  81.     return getShadowCountForLight(light) != 0 ||
  82.             (texUsage & (RingShadowTexture | CloudShadowTexture)) != 0;
  83. }
  84. // Returns true if diffuse, specular, bump, and night textures all use the
  85. // same texture coordinate set.
  86. bool
  87. ShaderProperties::hasSharedTextureCoords() const
  88. {
  89.     return (texUsage & SharedTextureCoords) != 0;
  90. }
  91. bool
  92. ShaderProperties::hasSpecular() const
  93. {
  94.     switch (lightModel)
  95.     {
  96.     case SpecularModel:
  97.     case PerPixelSpecularModel:
  98.         return true;
  99.     default:
  100.         return false;
  101.     }
  102. }
  103. bool
  104. ShaderProperties::hasScattering() const
  105. {
  106.     return (texUsage & Scattering) != 0;
  107. }
  108. bool
  109. ShaderProperties::isViewDependent() const
  110. {
  111.     switch (lightModel)
  112.     {
  113.     case DiffuseModel:
  114.     case ParticleDiffuseModel:
  115.     case EmissiveModel:
  116.         return false;
  117.     default:
  118.         return true;
  119.     }
  120. }
  121. bool
  122. ShaderProperties::usesTangentSpaceLighting() const
  123. {
  124.     return (texUsage & NormalTexture) != 0;
  125. }
  126. bool operator<(const ShaderProperties& p0, const ShaderProperties& p1)
  127. {
  128.     if (p0.texUsage < p1.texUsage)
  129.         return true;
  130.     else if (p1.texUsage < p0.texUsage)
  131.         return false;
  132.     if (p0.nLights < p1.nLights)
  133.         return true;
  134.     else if (p1.nLights < p0.nLights)
  135.         return false;
  136.     if (p0.shadowCounts < p1.shadowCounts)
  137.         return true;
  138.     else if (p1.shadowCounts < p0.shadowCounts)
  139.         return false;
  140.     if (p0.effects < p1.effects)
  141.         return true;
  142.     else if (p1.effects < p0.effects)
  143.         return false;
  144.     return (p0.lightModel < p1.lightModel);
  145. }
  146. ShaderManager::ShaderManager()
  147. {
  148. #if defined(_DEBUG) || defined(DEBUG)
  149.     // Only write to shader log file if this is a debug build
  150.     if (g_shaderLogFile == NULL)
  151. #ifdef _WIN32
  152.         g_shaderLogFile = new ofstream("shaders.log");
  153. #else
  154.         g_shaderLogFile = new ofstream("/tmp/celestia-shaders.log");
  155. #endif
  156. #endif
  157. }
  158. ShaderManager::~ShaderManager()
  159. {
  160. }
  161. CelestiaGLProgram*
  162. ShaderManager::getShader(const ShaderProperties& props)
  163. {
  164.     map<ShaderProperties, CelestiaGLProgram*>::iterator iter = shaders.find(props);
  165.     if (iter != shaders.end())
  166.     {
  167.         // Shader already exists
  168.         return iter->second;
  169.     }
  170.     else
  171.     {
  172.         // Create a new shader and add it to the table of created shaders
  173.         CelestiaGLProgram* prog = buildProgram(props);
  174.         shaders[props] = prog;
  175.         return prog;
  176.     }
  177. }
  178. static string
  179. LightProperty(unsigned int i, const char* property)
  180. {
  181.     char buf[64];
  182. #ifndef USE_GLSL_STRUCTS
  183.     sprintf(buf, "light%d_%s", i, property);
  184. #else
  185.     sprintf(buf, "lights[%d].%s", i, property);
  186. #endif
  187.     return string(buf);
  188. }
  189. static string
  190. FragLightProperty(unsigned int i, const char* property)
  191. {
  192.     char buf[64];
  193.     sprintf(buf, "light%s%d", property, i);
  194.     return string(buf);
  195. }
  196. #if 0
  197. static string
  198. IndexedParameter(const char* name, unsigned int index)
  199. {
  200.     char buf[64];
  201.     sprintf(buf, "%s%d", name, index);
  202.     return string(buf);
  203. }
  204. #endif
  205. static string
  206. IndexedParameter(const char* name, unsigned int index0, unsigned int index1)
  207. {
  208.     char buf[64];
  209.     sprintf(buf, "%s%d_%d", name, index0, index1);
  210.     return string(buf);
  211. }
  212. static string
  213. RingShadowTexCoord(unsigned int index)
  214. {
  215.     char buf[64];
  216.     sprintf(buf, "ringShadowTexCoord.%c", "xyzw"[index]);
  217.     return string(buf);
  218. }
  219. static string
  220. CloudShadowTexCoord(unsigned int index)
  221. {
  222.     char buf[64];
  223.     sprintf(buf, "cloudShadowTexCoord%d", index);
  224.     return string(buf);
  225. }
  226. static string
  227. VarScatterInVS()
  228. {
  229.     return string("gl_FrontSecondaryColor.rgb");
  230. }
  231. static string
  232. VarScatterInFS()
  233. {
  234.     return string("gl_SecondaryColor.rgb");
  235. }
  236. static void
  237. DumpShaderSource(ostream& out, const std::string& source)
  238. {
  239.     bool newline = true;
  240.     unsigned int lineNumber = 0;
  241.     for (unsigned int i = 0; i < source.length(); i++)
  242.     {
  243.         if (newline)
  244.         {
  245.             lineNumber++;
  246.             out << setw(3) << lineNumber << ": ";
  247.             newline = false;
  248.         }
  249.         out << source[i];
  250.         if (source[i] == 'n')
  251.             newline = true;
  252.     }
  253.     out.flush();
  254. }
  255. static string
  256. DeclareLights(const ShaderProperties& props)
  257. {
  258.     if (props.nLights == 0)
  259.         return string("");
  260. #ifndef USE_GLSL_STRUCTS
  261.     ostringstream stream;
  262.     for (unsigned int i = 0; i < props.nLights; i++)
  263.     {
  264.         stream << "uniform vec3 light" << i << "_direction;n";
  265.         stream << "uniform vec3 light" << i << "_diffuse;n";
  266.         stream << "uniform vec3 light" << i << "_specular;n";
  267.         stream << "uniform vec3 light" << i << "_halfVector;n";
  268.         if (props.texUsage & ShaderProperties::NightTexture)
  269.             stream << "uniform float light" << i << "_brightness;n";
  270.     }
  271. #else
  272.     stream << "uniform struct {n";
  273.     stream << "   vec3 direction;n";
  274.     stream << "   vec3 diffuse;n";
  275.     stream << "   vec3 specular;n";
  276.     stream << "   vec3 halfVector;n";
  277.     if (props.texUsage & ShaderProperties::NightTexture)
  278.         stream << "   float brightness;n";
  279.     stream << "} lights[%d];n";
  280. #endif
  281.     return stream.str();
  282. }
  283. static string
  284. SeparateDiffuse(unsigned int i)
  285. {
  286.     // Used for packing multiple diffuse factors into the diffuse color.
  287.     char buf[32];
  288.     sprintf(buf, "diffFactors.%c", "xyzw"[i & 3]);
  289.     return string(buf);
  290. }
  291. static string
  292. SeparateSpecular(unsigned int i)
  293. {
  294.     // Used for packing multiple specular factors into the specular color.
  295.     char buf[32];
  296.     sprintf(buf, "specFactors.%c", "xyzw"[i & 3]);
  297.     return string(buf);
  298. }
  299. // Used by rings shader
  300. static string
  301. ShadowDepth(unsigned int i)
  302. {
  303.     char buf[32];
  304.     sprintf(buf, "shadowDepths.%c", "xyzw"[i & 3]);
  305.     return string(buf);
  306. }
  307. static string
  308. TexCoord2D(unsigned int i)
  309. {
  310.     char buf[64];
  311.     sprintf(buf, "gl_MultiTexCoord%d.st", i);
  312.     return string(buf);
  313. }
  314. // Tangent space light direction
  315. static string
  316. LightDir_tan(unsigned int i)
  317. {
  318.     char buf[32];
  319.     sprintf(buf, "lightDir_tan_%d", i);
  320.     return string(buf);
  321. }
  322. static string
  323. LightHalfVector(unsigned int i)
  324. {
  325.     char buf[32];
  326.     sprintf(buf, "lightHalfVec%d", i);
  327.     return string(buf);
  328. }
  329. static string
  330. ScatteredColor(unsigned int i)
  331. {
  332.     char buf[32];
  333.     sprintf(buf, "scatteredColor%d", i);
  334.     return string(buf);
  335. }
  336. static string
  337. TangentSpaceTransform(const string& dst, const string& src)
  338. {
  339.     string source;
  340.     source += dst + ".x = dot(tangent, " + src + ");n";
  341.     source += dst + ".y = dot(-bitangent, " + src + ");n";
  342.     source += dst + ".z = dot(gl_Normal, " + src + ");n";
  343.     return source;
  344. }
  345. static string
  346. NightTextureBlend()
  347. {
  348. #if 1
  349.     // Output the blend factor for night lights textures
  350.     return string("totalLight = 1.0 - totalLight;n"
  351.                   "totalLight = totalLight * totalLight * totalLight * totalLight;n");
  352. #else
  353.     // Alternate night light blend function; much sharper falloff near terminator.
  354.     return string("totalLight = clamp(10.0 * (0.1 - totalLight), 0.0, 1.0);n");
  355. #endif
  356. }
  357. // Return true if the color sum from all light sources should be computed in
  358. // the vertex shader, and false if it will be done by the pixel shader.
  359. static bool
  360. VSComputesColorSum(const ShaderProperties& props)
  361. {
  362.     return !props.usesShadows() && props.lightModel != ShaderProperties::PerPixelSpecularModel;
  363. }
  364. static string
  365. AssignDiffuse(unsigned int lightIndex, const ShaderProperties& props)
  366. {
  367.     if (VSComputesColorSum(props))
  368.         return string("diff.rgb += ") + LightProperty(lightIndex, "diffuse") + " * ";
  369.     else
  370.         return SeparateDiffuse(lightIndex)  + " = ";
  371. }
  372. // Values used in generated shaders:
  373. //    N - surface normal
  374. //    V - view vector: the normalized direction from vertex to eye
  375. //    L - light direction: normalized direction from vertex to light
  376. //    H - half vector for Blinn-Phong lighting: normalized, bisects L and V
  377. //    R - reflected light direction
  378. //    NL - dot product of light and normal vectors
  379. //    NV - dot product of light and view vectors
  380. //    NH - dot product of light and half vectors
  381. static string
  382. AddDirectionalLightContrib(unsigned int i, const ShaderProperties& props)
  383. {
  384.     string source;
  385.     if (props.lightModel == ShaderProperties::ParticleDiffuseModel)
  386.     {
  387.         // The ParticleDiffuse model doesn't use a surface normal; vertices
  388.         // are lit as if they were infinitesimal spherical particles,
  389.         // unaffected by light direction except when considering shadows.
  390.         source += "NL = 1.0;n";
  391.     }
  392.     else
  393.     {
  394.         source += "NL = max(0.0, dot(gl_Normal, " +
  395.             LightProperty(i, "direction") + "));n";
  396.     }
  397.     if (props.lightModel == ShaderProperties::SpecularModel)
  398.     {
  399.         source += "H = normalize(" + LightProperty(i, "direction") + " + normalize(eyePosition - gl_Vertex.xyz));n";
  400.         source += "NH = max(0.0, dot(gl_Normal, H));n";
  401.         // The calculation below uses the infinite viewer approximation. It's slightly faster,
  402.         // but results in less accurate rendering.
  403.         // source += "NH = max(0.0, dot(gl_Normal, " + LightProperty(i, "halfVector") + "));n";
  404.     }
  405.     if (props.usesTangentSpaceLighting())
  406.     {
  407.         source += TangentSpaceTransform(LightDir_tan(i), LightProperty(i, "direction"));
  408.         // Diffuse color is computed in the fragment shader
  409.     }
  410.     else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  411.     {
  412.         source += SeparateDiffuse(i) + " = NL;n";
  413.         // Specular is computed in the fragment shader; half vectors are required
  414.         // for the calculation
  415.         source += LightHalfVector(i) + " = " + LightProperty(i, "direction") + " + eyeDir;n";
  416.     }
  417.     else if (props.lightModel == ShaderProperties::OrenNayarModel)
  418.     {
  419.         source += "float cosAlpha = min(NV, NL);n";
  420.         source += "float cosBeta = max(NV, NL);n";
  421.         source += "float sinAlpha = sqrt(1.0 - cosAlpha * cosAlpha);n";
  422.         source += "float sinBeta = sqrt(1.0 - cosBeta * cosBeta);n";
  423.         source += "float tanBeta = sinBeta / cosBeta;n";
  424.         source += "float cosAzimuth = dot(normalize(eye - gl_Normal * NV), normalize(light - gl_Normal * NL));n";
  425.         // TODO: precalculate these constants; place them in uniform values
  426.         source += "float roughness2 = 0.7 * 0.7;n";
  427.         source += "float A = 1.0f - (0.5f * roughness2) / (roughness2 + 0.33);n";
  428.         source += "float B = (0.45f * roughness2) / (roughness2 + 0.09);n";
  429.         // TODO: add normalization factor so that max brightness is always 1
  430.         // TODO: add gamma correction
  431.         source += "float d = NL * (A + B * sinAlpha * tanBeta * max(0.0, cosAzimuth));n";
  432.         if (props.usesShadows())
  433.         {
  434.             source += SeparateDiffuse(i) += " = d;n";
  435.         }
  436.         else
  437.         {
  438.             source += "diff.rgb += " + LightProperty(i, "diffuse") + " * d;n";
  439.         }
  440.     }
  441.     else if (props.lightModel == ShaderProperties::LunarLambertModel)
  442.     {
  443.         source += AssignDiffuse(i, props) + " mix(NL, NL / (max(NV, 0.001) + NL), lunarLambert);n";
  444.     }
  445.     else if (props.usesShadows())
  446.     {
  447.         // When there are shadows, we need to track the diffuse contributions
  448.         // separately for each light.
  449.         source += SeparateDiffuse(i) + " = NL;n";
  450.         if (props.hasSpecular())
  451.         {
  452.             source += SeparateSpecular(i) + " = pow(NH, shininess);n";
  453.         }
  454.     }
  455.     else
  456.     {
  457.         source += "diff.rgb += " + LightProperty(i, "diffuse") + " * NL;n";
  458.         if (props.hasSpecular())
  459.         {
  460.             source += "spec.rgb += " + LightProperty(i, "specular") +
  461.                 " * (pow(NH, shininess) * NL);n";
  462.         }
  463.     }
  464.     if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
  465.     {
  466.         source += "totalLight += NL * " + LightProperty(i, "brightness") + ";n";
  467.     }
  468.     return source;
  469. }
  470. static string
  471. BeginLightSourceShadows(const ShaderProperties& props, unsigned int light)
  472. {
  473.     string source;
  474.     if (props.usesTangentSpaceLighting())
  475.     {
  476.         if (props.hasShadowsForLight(light))
  477.             source += "shadow = 1.0;n";
  478.     }
  479.     else
  480.     {
  481.         source += "shadow = " + SeparateDiffuse(light) + ";n";
  482.     }
  483.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  484.     {
  485.         source += "shadow *= (1.0 - texture2D(ringTex, vec2(" +
  486.             RingShadowTexCoord(light) + ", 0.0)).a);n";
  487.     }
  488.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  489.     {
  490.         source += "shadow *= (1.0 - texture2D(cloudShadowTex, " +
  491.             CloudShadowTexCoord(light) + ").a * 0.75);n";
  492.     }
  493.     return source;
  494. }
  495. // Calculate the depth of an eclipse shadow at the current fragment. Eclipse
  496. // shadows are circular, decreasing in depth from maxDepth at the center to
  497. // zero at the edge of the penumbra.
  498. // Eclipse shadows are approximate. They assume that the both the sun and
  499. // occluding body are spherical. An oblate planet is treated as if its polar
  500. // radius were equal to its equatorial radius. This produces quite accurate
  501. // eclipses for major moons around giant planets, which orbit close to the
  502. // equatorial plane of the planet.
  503. //
  504. // The radius of the shadow umbra and penumbra are computed accurately
  505. // (to the limit of the spherical approximation.) The maximum shadow depth
  506. // is also calculated accurately. However, the shadow falloff from from
  507. // the umbra to the edge of the penumbra is approximated as linear.
  508. static string
  509. Shadow(unsigned int light, unsigned int shadow)
  510. {
  511.     string source;
  512.     source += "shadowCenter.s = dot(vec4(position_obj, 1.0), " +
  513.         IndexedParameter("shadowTexGenS", light, shadow) + ") - 0.5;n";
  514.     source += "shadowCenter.t = dot(vec4(position_obj, 1.0), " +
  515.         IndexedParameter("shadowTexGenT", light, shadow) + ") - 0.5;n";
  516.     // The shadow shadow consists of a circular region of constant depth (maxDepth),
  517.     // surrounded by a ring of linear falloff from maxDepth to zero. For a total
  518.     // eclipse, maxDepth is zero. In reality, the falloff function is much more complex:
  519.     // to calculate the exact amount of sunlight blocked, we need to calculate the
  520.     // a circle-circle intersection area. 
  521.     // (See http://mathworld.wolfram.com/Circle-CircleIntersection.html)
  522.     
  523.     // The code generated below will compute:
  524.     // r = 2 * sqrt(dot(shadowCenter, shadowCenter));
  525.     // shadowR = clamp((r - 1) * shadowFalloff, 0, shadowMaxDepth)
  526.     source += "shadowR = clamp((2.0 * sqrt(dot(shadowCenter, shadowCenter)) - 1.0) * " +
  527.         IndexedParameter("shadowFalloff", light, shadow) + ", 0.0, " +
  528.         IndexedParameter("shadowMaxDepth", light, shadow) + ");n";
  529.     
  530.     source += "shadow *= 1.0 - shadowR;n";
  531.     return source;
  532. }
  533. static string
  534. ShadowsForLightSource(const ShaderProperties& props, unsigned int light)
  535. {
  536.     string source = BeginLightSourceShadows(props, light);
  537.     for (unsigned int i = 0; i < props.getShadowCountForLight(light); i++)
  538.         source += Shadow(light, i);
  539.     return source;
  540. }
  541. static string
  542. ScatteringPhaseFunctions(const ShaderProperties&)
  543. {
  544.     string source;
  545.     // Evaluate the Mie and Rayleigh phase functions; both are functions of the cosine
  546.     // of the angle between the view vector and light vector
  547.     source += "    float phMie = (1.0 - mieK * mieK) / ((1.0 - mieK * cosTheta) * (1.0 - mieK * cosTheta));n";
  548.     // Ignore Rayleigh phase function and treat Rayleigh scattering as isotropic
  549.     // source += "    float phRayleigh = (1.0 + cosTheta * cosTheta);n";
  550.     source += "    float phRayleigh = 1.0;n";
  551.     return source;
  552. }
  553. static string
  554. AtmosphericEffects(const ShaderProperties& props)
  555. {
  556.     string source;
  557.     source += "{n";
  558.     // Compute the intersection of the view direction and the cloud layer (currently assumed to be a sphere)
  559.     source += "    float rq = dot(eyePosition, eyeDir);n";
  560.     source += "    float qq = dot(eyePosition, eyePosition) - atmosphereRadius.y;n";
  561.     source += "    float d = sqrt(rq * rq - qq);n";
  562.     source += "    vec3 atmEnter = eyePosition + min(0.0, (-rq + d)) * eyeDir;n";
  563.     source += "    vec3 atmLeave = gl_Vertex.xyz;n";
  564.     source += "    vec3 atmSamplePoint = (atmEnter + atmLeave) * 0.5;n";
  565.     //source += "    vec3 atmSamplePoint = atmEnter * 0.2 + atmLeave * 0.8;n";
  566.     // Compute the distance through the atmosphere from the sample point to the sun
  567.     source += "    vec3 atmSamplePointSun = atmEnter * 0.5 + atmLeave * 0.5;n";
  568.     source += "    rq = dot(atmSamplePointSun, " + LightProperty(0, "direction") + ");n";
  569.     source += "    qq = dot(atmSamplePointSun, atmSamplePointSun) - atmosphereRadius.y;n";
  570.     source += "    d = sqrt(rq * rq - qq);n";
  571.     source += "    float distSun = -rq + d;n";
  572.     source += "    float distAtm = length(atmEnter - atmLeave);n";
  573.     // Compute the density of the atmosphere at the sample point; it falls off exponentially
  574.     // with the height above the planet's surface.
  575. #if 0
  576.     source += "    float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
  577.     source += "    float density = exp(-h * mieH);n";
  578. #else
  579.     source += "    float density = 0.0;n";
  580.     source += "    atmSamplePoint = atmEnter * 0.333 + atmLeave * 0.667;n";
  581.     //source += "    atmSamplePoint = atmEnter * 0.1 + atmLeave * 0.9;n";
  582.     source += "    float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
  583.     source += "    density += exp(-h * mieH);n";
  584.     source += "    atmSamplePoint = atmEnter * 0.667 + atmLeave * 0.333;n";
  585.     //source += "    atmSamplePoint = atmEnter * 0.9 + atmLeave * 0.1;n";
  586.     source += "    h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
  587.     source += "    density += exp(-h * mieH);n";
  588. #endif
  589.     bool hasAbsorption = true;
  590.     if (hasAbsorption)
  591.     {
  592.         source += "    vec3 sunColor = exp(-extinctionCoeff * density * distSun);n";
  593.         source += "    vec3 ex = exp(-extinctionCoeff * density * distAtm);n";
  594.     }
  595.     else
  596.     {
  597.         source += "    vec3 sunColor = exp(-scatterCoeffSum * density * distSun);n";
  598.         source += "    vec3 ex = exp(-scatterCoeffSum * density * distAtm);n";
  599.     }
  600.     string scatter;
  601.     if (hasAbsorption)
  602.     {
  603.         scatter = "(1.0 - exp(-scatterCoeffSum * density * distAtm))";
  604.     }
  605.     else
  606.     {
  607.         // If there's no absorption, the extinction coefficients are just the scattering coefficients,
  608.         // so there's no need to recompute the scattering.
  609.         scatter = "(1.0 - ex)";
  610.     }
  611.     // If we're rendering the sky dome, compute the phase functions in the fragment shader
  612.     // rather than the vertex shader in order to avoid artifacts from coarse tessellation.
  613.     if (props.lightModel == ShaderProperties::AtmosphereModel)
  614.     {
  615.         source += "    scatterEx = ex;n";
  616.         source += "    " + ScatteredColor(0) + " = sunColor * " + scatter + ";n";
  617.     }
  618.     else
  619.     {
  620.         source += "    float cosTheta = dot(eyeDir, " + LightProperty(0, "direction") + ");n";
  621.         source += ScatteringPhaseFunctions(props);
  622.         source += "    scatterEx = ex;n";
  623.         source += "    " + VarScatterInVS() + " = (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * sunColor * " + scatter + ";n";
  624.     }
  625.     // Optional exposure control
  626.     //source += "    1.0 - (scatterIn * exp(-5.0 * max(scatterIn.x, max(scatterIn.y, scatterIn.z))));n";
  627.     source += "}n";
  628.     return source;
  629. }
  630. #if 0
  631. // Integrate the atmosphere by summation--slow, but higher quality
  632. static string
  633. AtmosphericEffects(const ShaderProperties& props, unsigned int nSamples)
  634. {
  635.     string source;
  636.     source += "{n";
  637.     // Compute the intersection of the view direction and the cloud layer (currently assumed to be a sphere)
  638.     source += "    float rq = dot(eyePosition, eyeDir);n";
  639.     source += "    float qq = dot(eyePosition, eyePosition) - atmosphereRadius.y;n";
  640.     source += "    float d = sqrt(rq * rq - qq);n";
  641.     source += "    vec3 atmEnter = eyePosition + min(0.0, (-rq + d)) * eyeDir;n";
  642.     source += "    vec3 atmLeave = gl_Vertex.xyz;n";
  643.     source += "    vec3 step = (atmLeave - atmEnter) * (1.0 / 10.0);n";
  644.     source += "    float stepLength = length(step);n";
  645.     source += "    vec3 atmSamplePoint = atmEnter + step * 0.5;n";
  646.     source += "    vec3 scatter = vec3(0.0, 0.0, 0.0);n";
  647.     source += "    vec3 ex = vec3(1.0);n";
  648.     source += "    float tau = 0.0;n";
  649.     source += "    for (int i = 0; i < 10; ++i) {n";
  650.     // Compute the distance through the atmosphere from the sample point to the sun
  651.     source += "        rq = dot(atmSamplePoint, " + LightProperty(0, "direction") + ");n";
  652.     source += "        qq = dot(atmSamplePoint, atmSamplePoint) - atmosphereRadius.y;n";
  653.     source += "        d = sqrt(rq * rq - qq);n";
  654.     source += "        float distSun = -rq + d;n";
  655.     // Compute the density of the atmosphere at the sample point; it falls off exponentially
  656.     // with the height above the planet's surface.
  657.     source += "        float h = max(0.0, length(atmSamplePoint) - atmosphereRadius.z);n";
  658.     source += "        float d = exp(-h * mieH);n";
  659.     source += "        tau += d * stepLength;n";
  660.     source += "        vec3 sunColor = exp(-extinctionCoeff * d * distSun);n";
  661.     source += "        ex = exp(-extinctionCoeff * tau);n";
  662.     source += "        scatter += ex * sunColor * d * 0.1;n";
  663.     source += "        atmSamplePoint += step;n";
  664.     source += "    }n";
  665.     // If we're rendering the sky dome, compute the phase functions in the fragment shader
  666.     // rather than the vertex shader in order to avoid artifacts from coarse tessellation.
  667.     if (props.lightModel == ShaderProperties::AtmosphereModel)
  668.     {
  669.         source += "    scatterEx = ex;n";
  670.         source += "    " + ScatteredColor(i) + " = scatter;n";
  671.     }
  672.     else
  673.     {
  674.         source += "    float cosTheta = dot(eyeDir, " + LightProperty(0, "direction") + ");n";
  675.         source += ScatteringPhaseFunctions(props);
  676.         source += "    scatterEx = ex;n";
  677.         source += "    " + VarScatterInVS() + " = (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * scatter;n";
  678.     }
  679.     // Optional exposure control
  680.     //source += "    1.0 - (" + VarScatterInVS() + " * exp(-5.0 * max(scatterIn.x, max(scatterIn.y, scatterIn.z))));n";
  681.     source += "}n";
  682.     return source;
  683. }
  684. #endif
  685. string
  686. ScatteringConstantDeclarations(const ShaderProperties& /*props*/)
  687. {
  688.     string source;
  689.     source += "uniform vec3 atmosphereRadius;n";
  690.     source += "uniform float mieCoeff;n";
  691.     source += "uniform float mieH;n";
  692.     source += "uniform float mieK;n";
  693.     source += "uniform vec3 rayleighCoeff;n";
  694.     source += "uniform float rayleighH;n";
  695.     source += "uniform vec3 scatterCoeffSum;n";
  696.     source += "uniform vec3 invScatterCoeffSum;n";
  697.     source += "uniform vec3 extinctionCoeff;n";
  698.     return source;
  699. }
  700. string
  701. TextureSamplerDeclarations(const ShaderProperties& props)
  702. {
  703.     string source;
  704.     // Declare texture samplers
  705.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  706.     {
  707.         source += "uniform sampler2D diffTex;n";
  708.     }
  709.     if (props.texUsage & ShaderProperties::NormalTexture)
  710.     {
  711.         source += "uniform sampler2D normTex;n";
  712.     }
  713.     if (props.texUsage & ShaderProperties::SpecularTexture)
  714.     {
  715.         source += "uniform sampler2D specTex;n";
  716.     }
  717.     if (props.texUsage & ShaderProperties::NightTexture)
  718.     {
  719.         source += "uniform sampler2D nightTex;n";
  720.     }
  721.     if (props.texUsage & ShaderProperties::EmissiveTexture)
  722.     {
  723.         source += "uniform sampler2D emissiveTex;n";
  724.     }
  725.     if (props.texUsage & ShaderProperties::OverlayTexture)
  726.     {
  727.         source += "uniform sampler2D overlayTex;n";
  728.     }
  729.     return source;
  730. }
  731. string
  732. TextureCoordDeclarations(const ShaderProperties& props)
  733. {
  734.     string source;
  735.     if (props.hasSharedTextureCoords())
  736.     {
  737.         // If the shared texture coords flag is set, use the diffuse texture
  738.         // coordinate for sampling all the texture maps.
  739.         if (props.texUsage & (ShaderProperties::DiffuseTexture  |
  740.                               ShaderProperties::NormalTexture   |
  741.                               ShaderProperties::SpecularTexture |
  742.                               ShaderProperties::NightTexture    |
  743.                               ShaderProperties::EmissiveTexture |
  744.                               ShaderProperties::OverlayTexture))
  745.         {
  746.             source += "varying vec2 diffTexCoord;n";
  747.         }
  748.     }
  749.     else
  750.     {
  751.         if (props.texUsage & ShaderProperties::DiffuseTexture)
  752.             source += "varying vec2 diffTexCoord;n";
  753.         if (props.texUsage & ShaderProperties::NormalTexture)
  754.             source += "varying vec2 normTexCoord;n";
  755.         if (props.texUsage & ShaderProperties::SpecularTexture)
  756.             source += "varying vec2 specTexCoord;n";
  757.         if (props.texUsage & ShaderProperties::NightTexture)
  758.             source += "varying vec2 nightTexCoord;n";
  759.         if (props.texUsage & ShaderProperties::EmissiveTexture)
  760.             source += "varying vec2 emissiveTexCoord;n";
  761.         if (props.texUsage & ShaderProperties::OverlayTexture)
  762.             source += "varying vec2 overlayTexCoord;n";
  763.     }
  764.     return source;
  765. }
  766. string
  767. PointSizeCalculation()
  768. {
  769.     return string("gl_PointSize = pointScale * pointSize / length(vec3(gl_ModelViewMatrix * gl_Vertex));n");
  770. }
  771. GLVertexShader*
  772. ShaderManager::buildVertexShader(const ShaderProperties& props)
  773. {
  774.     string source = CommonHeader;
  775.     source += DeclareLights(props);
  776.     if (props.lightModel == ShaderProperties::SpecularModel)
  777.         source += "uniform float shininess;n";
  778.     source += "uniform vec3 eyePosition;n";
  779.     source += TextureCoordDeclarations(props);
  780.     source += "uniform float textureOffset;n";
  781.     if (props.hasScattering())
  782.     {
  783.         source += ScatteringConstantDeclarations(props);
  784.     }
  785.     if (props.isViewDependent() || props.hasScattering())
  786.     {
  787.         source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  788.         if (!props.usesTangentSpaceLighting())
  789.             source += "float NV = dot(gl_Normal, eyeDir);n";
  790.     }
  791.     if (props.texUsage & ShaderProperties::PointSprite)
  792.     {
  793.         source += "uniform float pointScale;n";
  794.         source += "attribute float pointSize;n";
  795.     }
  796.     if (props.usesTangentSpaceLighting())
  797.     {
  798.         source += "attribute vec3 tangent;n";
  799.         for (unsigned int i = 0; i < props.nLights; i++)
  800.         {
  801.             source += "varying vec3 " + LightDir_tan(i) + ";n";
  802.         }
  803.         if (props.isViewDependent() &&
  804.             props.lightModel != ShaderProperties::SpecularModel)
  805.         {
  806.             source += "varying vec3 eyeDir_tan;n";
  807.         }
  808.     }
  809.     else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  810.     {
  811.         source += "varying vec4 diffFactors;n";
  812.         source += "varying vec3 normal;n";
  813.         for (unsigned int i = 0; i < props.nLights; i++)
  814.         {
  815.             source += "varying vec3 " + LightHalfVector(i) + ";n";
  816.         }
  817.     }
  818.     else if (props.usesShadows())
  819.     {
  820.         source += "varying vec4 diffFactors;n";
  821.         if (props.lightModel == ShaderProperties::SpecularModel)
  822.         {
  823.             source += "varying vec4 specFactors;n";
  824.             source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  825.         }
  826.     }
  827.     else
  828.     {
  829.         source += "uniform vec3 ambientColor;n";
  830.         source += "uniform float opacity;n";
  831.         source += "varying vec4 diff;n";
  832.         if (props.lightModel == ShaderProperties::SpecularModel)
  833.         {
  834.             source += "varying vec4 spec;n";
  835.             source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  836.         }
  837.     }
  838.     // If this shader uses tangent space lighting, the diffuse term
  839.     // will be calculated in the fragment shader and we won't need
  840.     // the lunar-Lambert term here in the vertex shader.
  841.     if (!props.usesTangentSpaceLighting())
  842.     {
  843.         if (props.lightModel == ShaderProperties::LunarLambertModel)
  844.             source += "uniform float lunarLambert;n";
  845.     }
  846.     // Miscellaneous lighting values
  847.     if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
  848.     {
  849.         source += "varying float totalLight;n";
  850.     }
  851.     if (props.hasScattering())
  852.     {
  853.         //source += "varying vec3 scatterIn;n";
  854.         source += "varying vec3 scatterEx;n";
  855.     }
  856.     // Shadow parameters
  857.     if (props.shadowCounts != 0)
  858.     {
  859.         source += "varying vec3 position_obj;n";
  860.     }
  861.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  862.     {
  863.         source += "uniform float ringWidth;n";
  864.         source += "uniform float ringRadius;n";
  865.         source += "varying vec4 ringShadowTexCoord;n";
  866.     }
  867.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  868.     {
  869.         source += "uniform float cloudShadowTexOffset;n";
  870.         source += "uniform float cloudHeight;n";
  871.         for (unsigned int i = 0; i < props.nLights; i++)
  872.             source += "varying vec2 " + CloudShadowTexCoord(i) + ";n";
  873.     }
  874.     // Begin main() function
  875.     source += "nvoid main(void)n{n";
  876.     source += "float NL;n";
  877.     if (props.lightModel == ShaderProperties::SpecularModel)
  878.     {
  879.         source += "float NH;n";
  880.         source += "vec3 H;n";
  881.     }
  882.     if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
  883.     {
  884.         source += "totalLight = 0.0;n";
  885.     }
  886.     if (props.usesTangentSpaceLighting())
  887.     {
  888.         source += "vec3 bitangent = cross(gl_Normal, tangent);n";
  889.         if (props.isViewDependent() &&
  890.             props.lightModel != ShaderProperties::SpecularModel)
  891.         {
  892.             source += TangentSpaceTransform("eyeDir_tan", "eyeDir");
  893.         }
  894.     }
  895.     else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  896.     {
  897.         source += "normal = gl_Normal;n";
  898.     }
  899.     else if (props.usesShadows())
  900.     {
  901.     }
  902.     else
  903.     {
  904.         source += "diff = vec4(ambientColor, opacity);n";
  905.         if (props.hasSpecular())
  906.             source += "spec = vec4(0.0, 0.0, 0.0, 0.0);n";
  907.     }
  908.     for (unsigned int i = 0; i < props.nLights; i++)
  909.     {
  910.         source += AddDirectionalLightContrib(i, props);
  911.     }
  912.     if ((props.texUsage & ShaderProperties::NightTexture) && VSComputesColorSum(props))
  913.     {
  914.         source += NightTextureBlend();
  915.     }
  916.     unsigned int nTexCoords = 0;
  917.     // Output the texture coordinates. Use just a single texture coordinate if all textures are mapped
  918.     // identically. The texture offset is added for cloud maps; specular and night texture are not offset
  919.     // because cloud layers never have these textures.
  920.     if (props.hasSharedTextureCoords())
  921.     {
  922.         if (props.texUsage & (ShaderProperties::DiffuseTexture  |
  923.                               ShaderProperties::NormalTexture   |
  924.                               ShaderProperties::SpecularTexture |
  925.                               ShaderProperties::NightTexture    |
  926.                               ShaderProperties::EmissiveTexture |
  927.                               ShaderProperties::OverlayTexture))
  928.         {
  929.             source += "diffTexCoord = " + TexCoord2D(nTexCoords) + ";n";
  930.             source += "diffTexCoord.x += textureOffset;n";
  931.         }
  932.     }
  933.     else
  934.     {
  935.         if (props.texUsage & ShaderProperties::DiffuseTexture)
  936.         {
  937.             source += "diffTexCoord = " + TexCoord2D(nTexCoords) + " + vec2(textureOffset, 0.0);n";
  938.             nTexCoords++;
  939.         }
  940.         if (!props.hasSharedTextureCoords())
  941.         {
  942.             if (props.texUsage & ShaderProperties::NormalTexture)
  943.             {
  944.                 source += "normTexCoord = " + TexCoord2D(nTexCoords) + " + vec2(textureOffset, 0.0);n";
  945.                 nTexCoords++;
  946.             }
  947.             if (props.texUsage & ShaderProperties::SpecularTexture)
  948.             {
  949.                 source += "specTexCoord = " + TexCoord2D(nTexCoords) + ";n";
  950.                 nTexCoords++;
  951.             }
  952.             if (props.texUsage & ShaderProperties::NightTexture)
  953.             {
  954.                 source += "nightTexCoord = " + TexCoord2D(nTexCoords) + ";n";
  955.                 nTexCoords++;
  956.             }
  957.             if (props.texUsage & ShaderProperties::EmissiveTexture)
  958.             {
  959.                 source += "emissiveTexCoord = " + TexCoord2D(nTexCoords) + ";n";
  960.                 nTexCoords++;
  961.             }
  962.         }
  963.     }
  964.     // Shadow texture coordinates are generated in the shader
  965.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  966.     {
  967.         source += "vec3 ringShadowProj;n";
  968.         for (unsigned int j = 0; j < props.nLights; j++)
  969.         {
  970.             source += "ringShadowProj = gl_Vertex.xyz + " +
  971.                 LightProperty(j, "direction") +
  972.                 " * max(0.0, gl_Vertex.y / -" +
  973.                 LightProperty(j, "direction") + ".y);n";
  974.             source += RingShadowTexCoord(j) +
  975.                 " = (length(ringShadowProj) - ringRadius) * ringWidth;n";
  976.         }
  977.     }
  978.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  979.     {
  980.         for (unsigned int j = 0; j < props.nLights; j++)
  981.         {
  982.             source += "{n";
  983.             // A cheap way to calculate cloud shadow texture coordinates that doesn't correctly account
  984.             // for sun angle.
  985.             source += "    " + CloudShadowTexCoord(j) + " = vec2(diffTexCoord.x + cloudShadowTexOffset, diffTexCoord.y);n";
  986.             // Disabled: there are too many problems with this approach,
  987.             // though it should theoretically work. The inverse trig
  988.             // approximations produced by the shader compiler are crude
  989.             // enough that visual anomalies are apparent. And in the current
  990.             // GeForce 8800 driver, this shader produces an internal compiler
  991.             // error. Cloud shadows are trivial if the cloud texture is a cube
  992.             // map. Also, DX10 capable hardware could efficiently perform
  993.             // the rect-to-spherical conversion in the pixel shader with an
  994.             // fp32 texture serving as a lookup table.
  995. #if 0
  996.             // Compute the intersection of the sun direction and the cloud layer (currently assumed to be a sphere)
  997.             source += "    float rq = dot(" + LightProperty(j, "direction") + ", gl_Vertex.xyz);n";
  998.             source += "    float qq = dot(gl_Vertex.xyz, gl_Vertex.xyz) - cloudHeight * cloudHeight;n";
  999.             source += "    float d = sqrt(rq * rq - qq);n";
  1000.             source += "    vec3 cloudSpherePos = (gl_Vertex.xyz + (-rq + d) * " + LightProperty(j, "direction") + ");n";
  1001.             //source += "    vec3 cloudSpherePos = gl_Vertex.xyz;n";
  1002.             // Find the texture coordinates at this point on the sphere by converting from rectangular to spherical; this is an
  1003.             // expensive calculation to perform per vertex.
  1004.             source += "    float invPi = 1.0 / 3.1415927;n";
  1005.             source += "    " + CloudShadowTexCoord(j) + ".y = 0.5 - asin(cloudSpherePos.y) * invPi;n";
  1006.             source += "    float u = fract(atan(cloudSpherePos.x, cloudSpherePos.z) * (invPi * 0.5) + 0.75);n";
  1007.             source += "    if (diffTexCoord.x < 0.25 && u > 0.5) u -= 1.0;n";
  1008.             source += "    else if (diffTexCoord.x > 0.75 && u < 0.5) u += 1.0;n";
  1009.             source += "    " + CloudShadowTexCoord(j) + ".x = u + cloudShadowTexOffset;n";
  1010. #endif
  1011.             source += "}n";
  1012.         }
  1013.     }
  1014.     if (props.hasScattering())
  1015.     {
  1016.         source += AtmosphericEffects(props);
  1017.     }
  1018.     if ((props.texUsage & ShaderProperties::OverlayTexture) && !props.hasSharedTextureCoords())
  1019.     {
  1020.         source += "overlayTexCoord = " + TexCoord2D(nTexCoords) + ";n";
  1021.         nTexCoords++;
  1022.     }
  1023.     if (props.shadowCounts != 0)
  1024.     {
  1025.         source += "position_obj = gl_Vertex.xyz;n";
  1026.     }
  1027.     if ((props.texUsage & ShaderProperties::PointSprite) != 0)
  1028.         source += PointSizeCalculation();
  1029.     source += "gl_Position = ftransform();n";
  1030.     source += "}n";
  1031.     if (g_shaderLogFile != NULL)
  1032.     {
  1033.         *g_shaderLogFile << "Vertex shader source:n";
  1034.         DumpShaderSource(*g_shaderLogFile, source);
  1035.         *g_shaderLogFile << 'n';
  1036.     }
  1037.     GLVertexShader* vs = NULL;
  1038.     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
  1039.     if (status != ShaderStatus_OK)
  1040.         return NULL;
  1041.     else
  1042.         return vs;
  1043. }
  1044. GLFragmentShader*
  1045. ShaderManager::buildFragmentShader(const ShaderProperties& props)
  1046. {
  1047.     string source = CommonHeader;
  1048.     string diffTexCoord("diffTexCoord");
  1049.     string specTexCoord("specTexCoord");
  1050.     string nightTexCoord("nightTexCoord");
  1051.     string emissiveTexCoord("emissiveTexCoord");
  1052.     string normTexCoord("normTexCoord");
  1053.     if (props.hasSharedTextureCoords())
  1054.     {
  1055.         specTexCoord     = diffTexCoord;
  1056.         nightTexCoord    = diffTexCoord;
  1057.         normTexCoord     = diffTexCoord;
  1058.         emissiveTexCoord = diffTexCoord;
  1059.     }
  1060.     source += TextureSamplerDeclarations(props);
  1061.     source += TextureCoordDeclarations(props);
  1062.     // Declare lighting parameters
  1063.     if (props.usesTangentSpaceLighting())
  1064.     {
  1065.         source += "uniform vec3 ambientColor;n";
  1066.         source += "uniform float opacity;n";
  1067.         source += "vec4 diff = vec4(ambientColor, opacity);n";
  1068.         if (props.isViewDependent())
  1069.         {
  1070.             if (props.lightModel == ShaderProperties::SpecularModel)
  1071.             {
  1072.                 // Specular model is sort of a hybrid: all the view-dependent lighting is
  1073.                 // handled in the vertex shader, and the fragment shader is view-independent
  1074.                 source += "varying vec4 specFactors;n";
  1075.                 source += "vec4 spec = vec4(0.0);n";
  1076.             }
  1077.             else
  1078.             {
  1079.                 source += "varying vec3 eyeDir_tan;n";  // tangent space eye vector
  1080.                 source += "vec4 spec = vec4(0.0);n";
  1081.                 source += "uniform float shininess;n";
  1082.             }
  1083.         }
  1084.         if (props.lightModel == ShaderProperties::LunarLambertModel)
  1085.             source += "uniform float lunarLambert;n";
  1086.         for (unsigned int i = 0; i < props.nLights; i++)
  1087.         {
  1088.             source += "varying vec3 " + LightDir_tan(i) + ";n";
  1089.             source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
  1090.             if (props.hasSpecular())
  1091.             {
  1092.                 source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
  1093.             }
  1094.             if (props.texUsage & ShaderProperties::NightTexture)
  1095.             {
  1096.                 source += "uniform float " + FragLightProperty(i, "brightness") + ";n";
  1097.             }
  1098.         }
  1099.     }
  1100.     else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  1101.     {
  1102.         source += "uniform vec3 ambientColor;n";
  1103.         source += "uniform float opacity;n";
  1104.         source += "varying vec4 diffFactors;n";
  1105.         source += "vec4 diff = vec4(ambientColor, opacity);n";
  1106.         source += "varying vec3 normal;n";
  1107.         source += "vec4 spec = vec4(0.0);n";
  1108.         source += "uniform float shininess;n";
  1109.         for (unsigned int i = 0; i < props.nLights; i++)
  1110.         {
  1111.             source += "varying vec3 " + LightHalfVector(i) + ";n";
  1112.             source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
  1113.             source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
  1114.         }
  1115.     }
  1116.     else if (props.usesShadows())
  1117.     {
  1118.         source += "uniform vec3 ambientColor;n";
  1119.         source += "uniform float opacity;n";
  1120.         source += "vec4 diff = vec4(ambientColor, opacity);n";
  1121.         source += "varying vec4 diffFactors;n";
  1122.         if (props.lightModel == ShaderProperties::SpecularModel)
  1123.         {
  1124.             source += "varying vec4 specFactors;n";
  1125.             source += "vec4 spec = vec4(0.0);n";
  1126.         }
  1127.         for (unsigned int i = 0; i < props.nLights; i++)
  1128.         {
  1129.             source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
  1130.             if (props.lightModel == ShaderProperties::SpecularModel)
  1131.                 source += "uniform vec3 " + FragLightProperty(i, "specColor") + ";n";
  1132.         }
  1133.     }
  1134.     else
  1135.     {
  1136.         source += "varying vec4 diff;n";
  1137.         if (props.lightModel == ShaderProperties::SpecularModel)
  1138.         {
  1139.             source += "varying vec4 spec;n";
  1140.         }
  1141.     }
  1142.     if (props.hasScattering())
  1143.     {
  1144.         //source += "varying vec3 scatterIn;n";
  1145.         source += "varying vec3 scatterEx;n";
  1146.     }
  1147.     if ((props.texUsage & ShaderProperties::NightTexture))
  1148.     {
  1149. #ifdef USE_HDR
  1150.         source += "uniform float nightLightScale;n";
  1151. #endif
  1152.         if (VSComputesColorSum(props))
  1153.         {
  1154.             source += "varying float totalLight;n";
  1155.         }
  1156.     }
  1157.     // Declare shadow parameters
  1158.     if (props.shadowCounts != 0)
  1159.     {
  1160.         source += "varying vec3 position_obj;n";
  1161.         for (unsigned int i = 0; i < props.nLights; i++)
  1162.         {
  1163.             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
  1164.             {
  1165.                 source += "uniform vec4 " +
  1166.                     IndexedParameter("shadowTexGenS", i, j) + ";n";
  1167.                 source += "uniform vec4 " +
  1168.                     IndexedParameter("shadowTexGenT", i, j) + ";n";
  1169.                 source += "uniform float " +
  1170.                     IndexedParameter("shadowFalloff", i, j) + ";n";
  1171.                 source += "uniform float " +
  1172.                     IndexedParameter("shadowMaxDepth", i, j) + ";n";
  1173.             }
  1174.         }
  1175.     }
  1176.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  1177.     {
  1178.         source += "uniform sampler2D ringTex;n";
  1179.         source += "varying vec4 ringShadowTexCoord;n";
  1180.     }
  1181.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  1182.     {
  1183.         source += "uniform sampler2D cloudShadowTex;n";
  1184.         for (unsigned int i = 0; i < props.nLights; i++)
  1185.             source += "varying vec2 " + CloudShadowTexCoord(i) + ";n";
  1186.     }
  1187.     source += "nvoid main(void)n{n";
  1188.     source += "vec4 color;n";
  1189.     if (props.usesShadows())
  1190.     {
  1191.         // Temporaries required for shadows
  1192.         source += "float shadow;n";
  1193.         if (props.shadowCounts != 0)
  1194.         {
  1195.             source += "vec2 shadowCenter;n";
  1196.             source += "float shadowR;n";
  1197.         }
  1198.     }
  1199.     // Sum the illumination from each light source, computing a total diffuse and specular
  1200.     // contributions from all sources.
  1201.     if (props.usesTangentSpaceLighting())
  1202.     {
  1203.         // Get the normal in tangent space. Ordinarily it comes from the normal texture, but if one
  1204.         // isn't provided, we'll simulate a smooth surface by using a constant (in tangent space)
  1205.         // normal of [ 0 0 1 ]
  1206.         if (props.texUsage & ShaderProperties::NormalTexture)
  1207.         {
  1208.             if (props.texUsage & ShaderProperties::CompressedNormalTexture)
  1209.             {
  1210.                 source += "vec3 n;n";
  1211.                 source += "n.xy = texture2D(normTex, " + normTexCoord + ".st).ag * 2.0 - vec2(1.0, 1.0);n";
  1212.                 source += "n.z = sqrt(1.0 - n.x * n.x - n.y * n.y);n";
  1213.             }
  1214.             else
  1215.             {
  1216.                 // TODO: normalizing the filtered normal texture value noticeably improves the appearance; add
  1217.                 // an option for this.
  1218.                 //source += "vec3 n = normalize(texture2D(normTex, " + normTexCoord + ".st).xyz * 2.0 - vec3(1.0, 1.0, 1.0));n";
  1219.                 source += "vec3 n = texture2D(normTex, " + normTexCoord + ".st).xyz * 2.0 - vec3(1.0, 1.0, 1.0);n";
  1220.             }
  1221.         }
  1222.         else
  1223.         {
  1224.             source += "vec3 n = vec3(0.0, 0.0, 1.0);n";
  1225.         }
  1226.         source += "float l;n";
  1227.         if (props.isViewDependent())
  1228.         {
  1229.             source += "vec3 V = normalize(eyeDir_tan);n";
  1230.             if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  1231.             {
  1232.                 source += "vec3 H;n";
  1233.                 source += "float NH;n";
  1234.             }
  1235.             else if (props.lightModel == ShaderProperties::LunarLambertModel)
  1236.             {
  1237.                 source += "float NV = dot(n, V);n";
  1238.             }
  1239.         }
  1240.         source += "float NL;n";
  1241.         for (unsigned i = 0; i < props.nLights; i++)
  1242.         {
  1243.             // Bump mapping with self shadowing
  1244.             // TODO: normalize the light direction (optionally--not as important for finely tesselated
  1245.             // geometry like planet spheres.)
  1246.             // source += LightDir_tan(i) + " = normalize(" + LightDir(i)_tan + ");n";
  1247.             source += "NL = dot(" + LightDir_tan(i) + ", n);n";
  1248.             if (props.lightModel == ShaderProperties::LunarLambertModel)
  1249.             {
  1250.                 source += "NL = max(0.0, NL);n";
  1251.                 source += "l = mix(NL, (NL / (max(NV, 0.001) + NL)), lunarLambert) * clamp(" + LightDir_tan(i) + ".z * 8.0, 0.0, 1.0);n";
  1252.             }
  1253.             else
  1254.             {
  1255.                 source += "l = max(0.0, dot(" + LightDir_tan(i) + ", n)) * clamp(" + LightDir_tan(i) + ".z * 8.0, 0.0, 1.0);n";
  1256.             }
  1257.             if ((props.texUsage & ShaderProperties::NightTexture) &&
  1258.                 !VSComputesColorSum(props))
  1259.             {
  1260.                 if (i == 0)
  1261.                     source += "float totalLight = ";
  1262.                 else
  1263.                     source += "totalLight += ";
  1264.                 source += "l * " + FragLightProperty(i, "brightness") + ";n";
  1265.             }
  1266.             string illum;
  1267.             if (props.hasShadowsForLight(i))
  1268.                 illum = string("l * shadow");
  1269.             else
  1270.                 illum = string("l");
  1271.             if (props.hasShadowsForLight(i))
  1272.                 source += ShadowsForLightSource(props, i);
  1273.             source += "diff.rgb += " + illum + " * " +
  1274.                 FragLightProperty(i, "color") + ";n";
  1275.             if (props.lightModel == ShaderProperties::SpecularModel && props.usesShadows())
  1276.             {
  1277.                 source += "spec.rgb += " + illum + " * " + SeparateSpecular(i) +
  1278.                     " * " + FragLightProperty(i, "specColor") +
  1279.                     ";n";
  1280.             }
  1281.             else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  1282.             {
  1283.                 source += "H = normalize(eyeDir_tan + " + LightDir_tan(i) + ");n";
  1284.                 source += "NH = max(0.0, dot(n, H));n";
  1285.                 source += "spec.rgb += " + illum + " * pow(NH, shininess) * " + FragLightProperty(i, "specColor") + ";n";
  1286.             }
  1287.         }
  1288.     }
  1289.     else if (props.lightModel == ShaderProperties::PerPixelSpecularModel)
  1290.     {
  1291.         source += "float NH;n";
  1292.         source += "vec3 n = normalize(normal);n";
  1293.         // Sum the contributions from each light source
  1294.         for (unsigned i = 0; i < props.nLights; i++)
  1295.         {
  1296.             string illum;
  1297.             if (props.hasShadowsForLight(i))
  1298.                 illum = string("shadow");
  1299.             else
  1300.                 illum = SeparateDiffuse(i);
  1301.             if (props.hasShadowsForLight(i))
  1302.                 source += ShadowsForLightSource(props, i);
  1303.             source += "diff.rgb += " + illum + " * " + FragLightProperty(i, "color") + ";n";
  1304.             source += "NH = max(0.0, dot(n, normalize(" + LightHalfVector(i) + ")));n";
  1305.             source += "spec.rgb += " + illum + " * pow(NH, shininess) * " + FragLightProperty(i, "specColor") + ";n";
  1306.         }
  1307.     }
  1308.     else if (props.usesShadows())
  1309.     {
  1310.         // Sum the contributions from each light source
  1311.         for (unsigned i = 0; i < props.nLights; i++)
  1312.         {
  1313.             source += ShadowsForLightSource(props, i);
  1314.             source += "diff.rgb += shadow * " +
  1315.                 FragLightProperty(i, "color") + ";n";
  1316.             if (props.lightModel == ShaderProperties::SpecularModel)
  1317.             {
  1318.                 source += "spec.rgb += shadow * " + SeparateSpecular(i) +
  1319.                     " * " +
  1320.                     FragLightProperty(i, "specColor") + ";n";
  1321.             }
  1322.         }
  1323.     }
  1324.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1325.     {
  1326.         if (props.texUsage & ShaderProperties::PointSprite)
  1327.             source += "color = texture2D(diffTex, gl_TexCoord[0].st);n";
  1328.         else
  1329.             source += "color = texture2D(diffTex, " + diffTexCoord + ".st);n";
  1330.     }
  1331.     else
  1332.     {
  1333.         source += "color = vec4(1.0, 1.0, 1.0, 1.0);n";
  1334.     }
  1335.     // Mix in the overlay color with the base color
  1336.     if (props.texUsage & ShaderProperties::OverlayTexture)
  1337.     {
  1338.         source += "vec4 overlayColor = texture2D(overlayTex, overlayTexCoord.st);n";
  1339.         source += "color.rgb = mix(color.rgb, overlayColor.rgb, overlayColor.a);n";
  1340.     }
  1341.     if (props.hasSpecular())
  1342.     {
  1343.         // Add in the specular color
  1344.         if (props.texUsage & ShaderProperties::SpecularInDiffuseAlpha)
  1345.             source += "gl_FragColor = color * diff + float(color.a) * spec;n";
  1346.         else if (props.texUsage & ShaderProperties::SpecularTexture)
  1347.             source += "gl_FragColor = color * diff + texture2D(specTex, " + specTexCoord + ".st) * spec;n";
  1348.         else
  1349.             source += "gl_FragColor = color * diff + spec;n";
  1350.     }
  1351.     else
  1352.     {
  1353.         source += "gl_FragColor = color * diff;n";
  1354.     }
  1355.     // Add in the emissive color
  1356.     // TODO: support a constant emissive color, not just an emissive texture
  1357.     if (props.texUsage & ShaderProperties::NightTexture)
  1358.     {
  1359.         // If the night texture blend factor wasn't computed in the vertex
  1360.         // shader, we need to do so now.
  1361.         if (!VSComputesColorSum(props))
  1362.         {
  1363.             if (!props.usesTangentSpaceLighting())
  1364.             {
  1365.                 source += "float totalLight = ";
  1366.                 
  1367.                 if (props.nLights == 0)
  1368.                 {
  1369.                     source += "0.0fn";
  1370.                 }
  1371.                 else
  1372.                 {
  1373.                     int k;
  1374.                     for (k = 0; k < props.nLights - 1; k++)
  1375.                         source += SeparateDiffuse(k) + " + ";
  1376.                     source += SeparateDiffuse(k) + ";n";
  1377.                 }
  1378.             }
  1379.             source += NightTextureBlend();
  1380.         }
  1381. #ifdef USE_HDR
  1382.         source += "gl_FragColor += texture2D(nightTex, " + nightTexCoord + ".st) * totalLight * nightLightScale;n";
  1383. #else
  1384.         source += "gl_FragColor += texture2D(nightTex, " + nightTexCoord + ".st) * totalLight;n";
  1385. #endif
  1386.     }
  1387.     if (props.texUsage & ShaderProperties::EmissiveTexture)
  1388.     {
  1389.         source += "gl_FragColor += texture2D(emissiveTex, " + emissiveTexCoord + ".st);n";
  1390.     }
  1391.     // Include the effect of atmospheric scattering.
  1392.     if (props.hasScattering())
  1393.     {
  1394.         source += "gl_FragColor.rgb = gl_FragColor.rgb * scatterEx + " + VarScatterInFS() + ";n";
  1395.     }
  1396.     source += "}n";
  1397.     if (g_shaderLogFile != NULL)
  1398.     {
  1399.         *g_shaderLogFile << "Fragment shader source:n";
  1400.         DumpShaderSource(*g_shaderLogFile, source);
  1401.         *g_shaderLogFile << 'n';
  1402.     }
  1403.     GLFragmentShader* fs = NULL;
  1404.     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
  1405.     if (status != ShaderStatus_OK)
  1406.         return NULL;
  1407.     else
  1408.         return fs;
  1409. }
  1410. GLVertexShader*
  1411. ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
  1412. {
  1413.     string source = CommonHeader;
  1414.     source += DeclareLights(props);
  1415.     source += "uniform vec3 eyePosition;n";
  1416.     source += "varying vec4 diffFactors;n";
  1417.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1418.         source += "varying vec2 diffTexCoord;n";
  1419.     if (props.shadowCounts != 0)
  1420.     {
  1421.         source += "varying vec3 position_obj;n";
  1422.         source += "varying vec4 shadowDepths;n";
  1423.     }
  1424.     source += "nvoid main(void)n{n";
  1425.     // Get the normalized direction from the eye to the vertex
  1426.     source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  1427.     for (unsigned int i = 0; i < props.nLights; i++)
  1428.     {
  1429.         source += SeparateDiffuse(i) + " = (dot(" +
  1430.             LightProperty(i, "direction") + ", eyeDir) + 1.0) * 0.5;n";
  1431.     }
  1432.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1433.         source += "diffTexCoord = " + TexCoord2D(0) + ";n";
  1434.     if (props.shadowCounts != 0)
  1435.     {
  1436.         source += "position_obj = gl_Vertex.xyz;n";
  1437.         for (unsigned int i = 0; i < props.nLights; i++)
  1438.         {
  1439.             source += ShadowDepth(i) + " = dot(gl_Vertex.xyz, " +
  1440.                        LightProperty(i, "direction") + ");n";
  1441.         }
  1442.     }
  1443.     source += "gl_Position = ftransform();n";
  1444.     source += "}n";
  1445.     if (g_shaderLogFile != NULL)
  1446.     {
  1447.         *g_shaderLogFile << "Vertex shader source:n";
  1448.         DumpShaderSource(*g_shaderLogFile, source);
  1449.         *g_shaderLogFile << 'n';
  1450.     }
  1451.     GLVertexShader* vs = NULL;
  1452.     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
  1453.     if (status != ShaderStatus_OK)
  1454.         return NULL;
  1455.     else
  1456.         return vs;
  1457. }
  1458. GLFragmentShader*
  1459. ShaderManager::buildRingsFragmentShader(const ShaderProperties& props)
  1460. {
  1461.     string source = CommonHeader;
  1462.     source += "uniform vec3 ambientColor;n";
  1463.     source += "vec4 diff = vec4(ambientColor, 1.0);n";
  1464.     for (unsigned int i = 0; i < props.nLights; i++)
  1465.         source += "uniform vec3 " + FragLightProperty(i, "color") + ";n";
  1466.     source += "varying vec4 diffFactors;n";
  1467.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1468.     {
  1469.         source += "varying vec2 diffTexCoord;n";
  1470.         source += "uniform sampler2D diffTex;n";
  1471.     }
  1472.     if (props.shadowCounts != 0)
  1473.     {
  1474.         source += "varying vec3 position_obj;n";
  1475.         source += "varying vec4 shadowDepths;n";
  1476.         for (unsigned int i = 0; i < props.nLights; i++)
  1477.         {
  1478.             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
  1479.             {
  1480.                 source += "uniform vec4 " +
  1481.                     IndexedParameter("shadowTexGenS", i, j) + ";n";
  1482.                 source += "uniform vec4 " +
  1483.                     IndexedParameter("shadowTexGenT", i, j) + ";n";
  1484.                 source += "uniform float " +
  1485.                     IndexedParameter("shadowFalloff", i, j) + ";n";
  1486.                 source += "uniform float " +
  1487.                     IndexedParameter("shadowMaxDepth", i, j) + ";n";
  1488.             }
  1489.         }
  1490.     }
  1491.     source += "nvoid main(void)n{n";
  1492.     source += "vec4 color;n";
  1493.     if (props.usesShadows())
  1494.     {
  1495.         // Temporaries required for shadows
  1496.         source += "float shadow;n";
  1497.         source += "vec2 shadowCenter;n";
  1498.         source += "float shadowR;n";
  1499.     }
  1500.     // Sum the contributions from each light source
  1501.     for (unsigned i = 0; i < props.nLights; i++)
  1502.     {
  1503.         if (props.usesShadows())
  1504.         {
  1505.             source += "shadow = 1.0;n";
  1506.             source += Shadow(i, 0);
  1507.             source += "shadow = min(1.0, shadow + step(0.0, " + ShadowDepth(i) + "));n";
  1508.             source += "diff.rgb += (shadow * " + SeparateDiffuse(i) + ") * " +
  1509.                 FragLightProperty(i, "color") + ";n";
  1510.         }
  1511.         else
  1512.         {
  1513.             source += "diff.rgb += " + SeparateDiffuse(i) + " * " +
  1514.                 FragLightProperty(i, "color") + ";n";
  1515.         }
  1516.     }
  1517.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1518.         source += "color = texture2D(diffTex, diffTexCoord.st);n";
  1519.     else
  1520.         source += "color = vec4(1.0, 1.0, 1.0, 1.0);n";
  1521.     source += "gl_FragColor = color * diff;n";
  1522.     source += "}n";
  1523.     if (g_shaderLogFile != NULL)
  1524.     {
  1525.         *g_shaderLogFile << "Fragment shader source:n";
  1526.         DumpShaderSource(*g_shaderLogFile, source);
  1527.         *g_shaderLogFile << 'n';
  1528.     }
  1529.     GLFragmentShader* fs = NULL;
  1530.     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
  1531.     if (status != ShaderStatus_OK)
  1532.         return NULL;
  1533.     else
  1534.         return fs;
  1535. }
  1536. GLVertexShader*
  1537. ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props)
  1538. {
  1539.     string source = CommonHeader;
  1540.     source += DeclareLights(props);
  1541.     source += "uniform vec3 eyePosition;n";
  1542.     source += ScatteringConstantDeclarations(props);
  1543.     for (unsigned int i = 0; i < props.nLights; i++)
  1544.     {
  1545.         source += "varying vec3 " + ScatteredColor(i) + ";n";
  1546.     }
  1547.     source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  1548.     source += "float NV = dot(gl_Normal, eyeDir);n";
  1549.     source += "varying vec3 scatterEx;n";
  1550.     source += "varying vec3 eyeDir_obj;n";
  1551.     // Begin main() function
  1552.     source += "nvoid main(void)n{n";
  1553.     source += "float NL;n";
  1554.     source += AtmosphericEffects(props);
  1555.     source += "eyeDir_obj = eyeDir;n";
  1556.     source += "gl_Position = ftransform();n";
  1557.     source += "}n";
  1558.     if (g_shaderLogFile != NULL)
  1559.     {
  1560.         *g_shaderLogFile << "Vertex shader source:n";
  1561.         DumpShaderSource(*g_shaderLogFile, source);
  1562.         *g_shaderLogFile << 'n';
  1563.     }
  1564.     GLVertexShader* vs = NULL;
  1565.     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
  1566.     if (status != ShaderStatus_OK)
  1567.         return NULL;
  1568.     else
  1569.         return vs;
  1570. }
  1571. GLFragmentShader*
  1572. ShaderManager::buildAtmosphereFragmentShader(const ShaderProperties& props)
  1573. {
  1574.     string source = CommonHeader;
  1575.     source += "varying vec3 scatterEx;n";
  1576.     source += "varying vec3 eyeDir_obj;n";
  1577.     // Scattering constants
  1578.     source += "uniform float mieK;n";
  1579.     source += "uniform float mieCoeff;n";
  1580.     source += "uniform vec3  rayleighCoeff;n";
  1581.     source += "uniform vec3  invScatterCoeffSum;n";
  1582.     unsigned int i;
  1583.     for (i = 0; i < props.nLights; i++)
  1584.     {
  1585.         source += "uniform vec3 " + LightProperty(i, "direction") + ";n";
  1586.         source += "varying vec3 " + ScatteredColor(i) + ";n";
  1587.     }
  1588.     source += "nvoid main(void)n";
  1589.     source += "{n";
  1590.     // Sum the contributions from each light source
  1591.     source += "vec3 color = vec3(0.0, 0.0, 0.0);n";
  1592.     source += "vec3 V = normalize(eyeDir_obj);n";
  1593.     // Only do scattering calculations for the primary light source
  1594.     // TODO: Eventually handle multiple light sources, and removed the 'min'
  1595.     // from the line below.
  1596.     for (i = 0; i < min((unsigned int) props.nLights, 1u); i++)
  1597.     {
  1598.         source += "    float cosTheta = dot(V, " + LightProperty(i, "direction") + ");n";
  1599.         source += ScatteringPhaseFunctions(props);
  1600.         // TODO: Consider premultiplying by invScatterCoeffSum
  1601.         source += "    color += (phRayleigh * rayleighCoeff + phMie * mieCoeff) * invScatterCoeffSum * " + ScatteredColor(i) + ";n";
  1602.     }
  1603.     source += "    gl_FragColor = vec4(color, dot(scatterEx, vec3(0.333, 0.333, 0.333)));n";
  1604.     source += "}n";
  1605.     if (g_shaderLogFile != NULL)
  1606.     {
  1607.         *g_shaderLogFile << "Fragment shader source:n";
  1608.         DumpShaderSource(*g_shaderLogFile, source);
  1609.         *g_shaderLogFile << 'n';
  1610.     }
  1611.     GLFragmentShader* fs = NULL;
  1612.     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
  1613.     if (status != ShaderStatus_OK)
  1614.         return NULL;
  1615.     else
  1616.         return fs;
  1617. }
  1618. // The emissive shader ignores all lighting and uses the diffuse color
  1619. // as the final fragment color.
  1620. GLVertexShader*
  1621. ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props)
  1622. {
  1623.     string source = CommonHeader;
  1624.     source += "uniform float opacity;n";
  1625.     // There are no light sources used for the emissive light model, but
  1626.     // we still need the diffuse property of light 0. For other lighting
  1627.     // models, the material color is premultiplied with the light color.
  1628.     // Emissive shaders interoperate better with other shaders if they also
  1629.     // take the color from light source 0.
  1630. #ifndef USE_GLSL_STRUCTS
  1631.     source += string("uniform vec3 light0_diffuse;n");
  1632. #else
  1633.     source += string("uniform struct {n   vec3 diffuse;n} lights[1];n");
  1634. #endif
  1635.     if (props.texUsage & ShaderProperties::PointSprite)
  1636.     {
  1637.         source += "uniform float pointScale;n";
  1638.         source += "attribute float pointSize;n";
  1639.     }
  1640.     // Begin main() function
  1641.     source += "nvoid main(void)n{n";
  1642.     // Optional texture coordinates (generated automatically for point
  1643.     // sprites.)
  1644.     if ((props.texUsage & ShaderProperties::DiffuseTexture) &&
  1645.         !(props.texUsage & ShaderProperties::PointSprite))
  1646.     {
  1647.         source += "    gl_TexCoord[0].st = " + TexCoord2D(0) + ";n";
  1648.     }
  1649.     // Set the color. 
  1650.     string colorSource;
  1651.     if (props.texUsage & ShaderProperties::VertexColors)
  1652.         colorSource = "gl_Color.rgb";
  1653.     else
  1654.         colorSource = LightProperty(0, "diffuse");
  1655.     source += "    gl_FrontColor = vec4(" + colorSource + ", opacity);n";
  1656.     // Optional point size
  1657.     if ((props.texUsage & ShaderProperties::PointSprite) != 0)
  1658.         source += PointSizeCalculation();
  1659.     source += "    gl_Position = ftransform();n";
  1660.     source += "}n";
  1661.     // End of main()
  1662.     if (g_shaderLogFile != NULL)
  1663.     {
  1664.         *g_shaderLogFile << "Vertex shader source:n";
  1665.         DumpShaderSource(*g_shaderLogFile, source);
  1666.         *g_shaderLogFile << 'n';
  1667.     }
  1668.     GLVertexShader* vs = NULL;
  1669.     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
  1670.     if (status != ShaderStatus_OK)
  1671.         return NULL;
  1672.     else
  1673.         return vs;
  1674. }
  1675. GLFragmentShader*
  1676. ShaderManager::buildEmissiveFragmentShader(const ShaderProperties& props)
  1677. {
  1678.     string source = CommonHeader;
  1679.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1680.     {
  1681.         source += "uniform sampler2D diffTex;n";
  1682.     }
  1683.     // Begin main()
  1684.     source += "nvoid main(void)n";
  1685.     source += "{n";
  1686.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1687.     {
  1688.         source += "    gl_FragColor = gl_Color * texture2D(diffTex, gl_TexCoord[0].st);n";
  1689.     }
  1690.     else
  1691.     {
  1692.         source += "    gl_FragColor = gl_Color;n";
  1693.     }
  1694.     source += "}n";
  1695.     // End of main()
  1696.     if (g_shaderLogFile != NULL)
  1697.     {
  1698.         *g_shaderLogFile << "Fragment shader source:n";
  1699.         DumpShaderSource(*g_shaderLogFile, source);
  1700.         *g_shaderLogFile << 'n';
  1701.     }
  1702.     GLFragmentShader* fs = NULL;
  1703.     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
  1704.     if (status != ShaderStatus_OK)
  1705.         return NULL;
  1706.     else
  1707.         return fs;
  1708. }
  1709. // Build the vertex shader used for rendering particle systems.
  1710. GLVertexShader*
  1711. ShaderManager::buildParticleVertexShader(const ShaderProperties& props)
  1712. {
  1713.     ostringstream source;
  1714.     
  1715.     source << CommonHeader;
  1716.     
  1717.     source << "// PARTICLE SHADERn";
  1718.     source << "// shadow count: " << props.shadowCounts << endl;
  1719.     
  1720.     source << DeclareLights(props);
  1721.     
  1722.     source << "uniform vec3 eyePosition;n";
  1723.     // TODO: scattering constants
  1724.     
  1725.     if (props.texUsage & ShaderProperties::PointSprite)
  1726.     {
  1727.         source << "uniform float pointScale;n";
  1728.         source << "attribute float pointSize;n";
  1729.     }
  1730.     
  1731.     // Shadow parameters
  1732.     if (props.shadowCounts != 0)
  1733.     {
  1734.         source << "varying vec3 position_obj;n";
  1735.     }
  1736.     
  1737.     // Begin main() function
  1738.     source << "nvoid main(void)n{n";
  1739. #define PARTICLE_PHASE_PARAMETER 0
  1740. #if PARTICLE_PHASE_PARAMETER
  1741.     float g = -0.4f;
  1742.     float miePhaseAsymmetry = 1.55f * g - 0.55f * g * g * g;
  1743.     source << "    float mieK = " << miePhaseAsymmetry << ";n";
  1744.     source << "    vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);n";
  1745.     source << "    float brightness = 0.0;n";
  1746.     for (unsigned int i = 0; i < min(1u, props.nLights); i++)
  1747.     {
  1748.         source << "    {n";
  1749.         source << "         float cosTheta = dot(" << LightProperty(i, "direction") << ", eyeDir);n";
  1750.         source << "         float phMie = (1.0 - mieK * mieK) / ((1.0 - mieK * cosTheta) * (1.0 - mieK * cosTheta));n";
  1751.         source << "         brightness += phMie;n";
  1752.         source << "    }n";
  1753.     }
  1754. #else
  1755.     source << "    float brightness = 1.0;n";
  1756. #endif
  1757.     // Optional texture coordinates (generated automatically for point
  1758.     // sprites.)
  1759.     if ((props.texUsage & ShaderProperties::DiffuseTexture) &&
  1760.         !(props.texUsage & ShaderProperties::PointSprite))
  1761.     {
  1762.         source << "    gl_TexCoord[0].st = " << TexCoord2D(0) << ";n";
  1763.     }
  1764.     
  1765.     // Set the color. Should *always* use vertex colors for color and opacity.
  1766.     source << "    gl_FrontColor = gl_Color * brightness;n";
  1767.     
  1768.     // Optional point size
  1769.     if ((props.texUsage & ShaderProperties::PointSprite) != 0)
  1770.         source << PointSizeCalculation();
  1771.     
  1772.     source << "    gl_Position = ftransform();n";
  1773.     
  1774.     source << "}n";
  1775.     // End of main()
  1776.     
  1777.     if (g_shaderLogFile != NULL)
  1778.     {
  1779.         *g_shaderLogFile << "Vertex shader source:n";
  1780.         DumpShaderSource(*g_shaderLogFile, source.str());
  1781.         *g_shaderLogFile << endl;
  1782.     }
  1783.     
  1784.     GLVertexShader* vs = NULL;
  1785.     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source.str(), &vs);
  1786.     if (status != ShaderStatus_OK)
  1787.         return NULL;
  1788.     else
  1789.         return vs;
  1790. }
  1791. GLFragmentShader*
  1792. ShaderManager::buildParticleFragmentShader(const ShaderProperties& props)
  1793. {
  1794.     ostringstream source;
  1795.     source << CommonHeader;
  1796.     
  1797.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1798.     {
  1799.         source << "uniform sampler2D diffTex;n";
  1800.     }
  1801.     if (props.usesShadows())
  1802.     {
  1803.         source << "uniform vec3 ambientColor;n";
  1804.         for (unsigned int i = 0; i < props.nLights; i++)
  1805.         {
  1806.             source << "uniform vec3 " << FragLightProperty(i, "color") << ";n";
  1807.         }        
  1808.     }
  1809.     
  1810.     // Declare shadow parameters
  1811.     if (props.shadowCounts != 0)
  1812.     {
  1813.         source << "varying vec3 position_obj;n";
  1814.         for (unsigned int i = 0; i < props.nLights; i++)
  1815.         {
  1816.             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
  1817.             {
  1818.                 source << "uniform vec4 " << IndexedParameter("shadowTexGenS", i, j) << ";n";
  1819.                 source << "uniform vec4 " << IndexedParameter("shadowTexGenT", i, j) << ";n";
  1820.                 source << "uniform float " << IndexedParameter("shadowFalloff", i, j) << ";n";
  1821.                 source << "uniform float " << IndexedParameter("shadowMaxDepth", i, j) << ";n";
  1822.             }
  1823.         }
  1824.     }
  1825.     
  1826.     // Begin main()
  1827.     source << "nvoid main(void)n";
  1828.     source << "{n";
  1829.     
  1830.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  1831.     {
  1832.         source << "    gl_FragColor = gl_Color * texture2D(diffTex, gl_TexCoord[0].st);n";
  1833.     }
  1834.     else
  1835.     {
  1836.         source << "    gl_FragColor = gl_Color;n";
  1837.     }
  1838.     
  1839.     source << "}n";
  1840.     // End of main()
  1841.     
  1842.     if (g_shaderLogFile != NULL)
  1843.     {
  1844.         *g_shaderLogFile << "Fragment shader source:n";
  1845.         DumpShaderSource(*g_shaderLogFile, source.str());
  1846.         *g_shaderLogFile << 'n';
  1847.     }
  1848.     
  1849.     GLFragmentShader* fs = NULL;
  1850.     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source.str(), &fs);
  1851.     if (status != ShaderStatus_OK)
  1852.         return NULL;
  1853.     else
  1854.         return fs;
  1855. }
  1856. CelestiaGLProgram*
  1857. ShaderManager::buildProgram(const ShaderProperties& props)
  1858. {
  1859.     GLProgram* prog = NULL;
  1860.     GLShaderStatus status;
  1861.     GLVertexShader* vs = NULL;
  1862.     GLFragmentShader* fs = NULL;
  1863.     if (props.lightModel == ShaderProperties::RingIllumModel)
  1864.     {
  1865.         vs = buildRingsVertexShader(props);
  1866.         fs = buildRingsFragmentShader(props);
  1867.     }
  1868.     else if (props.lightModel == ShaderProperties::AtmosphereModel)
  1869.     {
  1870.         vs = buildAtmosphereVertexShader(props);
  1871.         fs = buildAtmosphereFragmentShader(props);
  1872.     }
  1873.     else if (props.lightModel == ShaderProperties::EmissiveModel)
  1874.     {
  1875.         vs = buildEmissiveVertexShader(props);
  1876.         fs = buildEmissiveFragmentShader(props);
  1877.     }
  1878.     else if (props.lightModel == ShaderProperties::ParticleModel)
  1879.     {
  1880.         vs = buildParticleVertexShader(props);
  1881.         fs = buildParticleFragmentShader(props);
  1882.     }
  1883.     else
  1884.     {
  1885.         vs = buildVertexShader(props);
  1886.         fs = buildFragmentShader(props);
  1887.     }
  1888.     if (vs != NULL && fs != NULL)
  1889.     {
  1890.         status = GLShaderLoader::CreateProgram(*vs, *fs, &prog);
  1891.         if (status == ShaderStatus_OK)
  1892.         {
  1893.             if (props.texUsage & ShaderProperties::NormalTexture)
  1894.             {
  1895.                 // Tangents always in attribute 6 (should be a constant
  1896.                 // someplace)
  1897.                 glx::glBindAttribLocationARB(prog->getID(), 6, "tangent");
  1898.             }
  1899.             if (props.texUsage & ShaderProperties::PointSprite)
  1900.             {
  1901.                 // Point size is always in attribute 7
  1902.                 glx::glBindAttribLocationARB(prog->getID(), 7, "pointSize");
  1903.             }
  1904.             status = prog->link();
  1905.         }
  1906.     }
  1907.     else
  1908.     {
  1909.         status = ShaderStatus_CompileError;
  1910.     }
  1911.     delete vs;
  1912.     delete fs;
  1913.     if (status != ShaderStatus_OK)
  1914.     {
  1915.         // If the shader creation failed for some reason, substitute the
  1916.         // error shader.
  1917.         status = GLShaderLoader::CreateProgram(errorVertexShaderSource,
  1918.                                                errorFragmentShaderSource,
  1919.                                                &prog);
  1920.         if (status != ShaderStatus_OK)
  1921.         {
  1922.             if (g_shaderLogFile != NULL)
  1923.                 *g_shaderLogFile << "Failed to create error shader!n";
  1924.         }
  1925.         else
  1926.         {
  1927.             status = prog->link();
  1928.         }
  1929.     }
  1930.     if (prog == NULL)
  1931.         return NULL;
  1932.     else
  1933.         return new CelestiaGLProgram(*prog, props);
  1934. }
  1935. CelestiaGLProgram::CelestiaGLProgram(GLProgram& _program,
  1936.                                      const ShaderProperties& _props) :
  1937.     program(&_program),
  1938.     props(_props)
  1939. {
  1940.     initParameters();
  1941.     initSamplers();
  1942. };
  1943. CelestiaGLProgram::~CelestiaGLProgram()
  1944. {
  1945.     delete program;
  1946. }
  1947. FloatShaderParameter
  1948. CelestiaGLProgram::floatParam(const string& paramName)
  1949. {
  1950.     return FloatShaderParameter(program->getID(), paramName.c_str());
  1951. }
  1952. Vec3ShaderParameter
  1953. CelestiaGLProgram::vec3Param(const string& paramName)
  1954. {
  1955.     return Vec3ShaderParameter(program->getID(), paramName.c_str());
  1956. }
  1957. Vec4ShaderParameter
  1958. CelestiaGLProgram::vec4Param(const string& paramName)
  1959. {
  1960.     return Vec4ShaderParameter(program->getID(), paramName.c_str());
  1961. }
  1962. void
  1963. CelestiaGLProgram::initParameters()
  1964. {
  1965.     for (unsigned int i = 0; i < props.nLights; i++)
  1966.     {
  1967.         lights[i].direction  = vec3Param(LightProperty(i, "direction"));
  1968.         lights[i].diffuse    = vec3Param(LightProperty(i, "diffuse"));
  1969.         lights[i].specular   = vec3Param(LightProperty(i, "specular"));
  1970.         lights[i].halfVector = vec3Param(LightProperty(i, "halfVector"));
  1971.         if (props.texUsage & ShaderProperties::NightTexture)
  1972.             lights[i].brightness = floatParam(LightProperty(i, "brightness"));
  1973.         fragLightColor[i] = vec3Param(FragLightProperty(i, "color"));
  1974.         fragLightSpecColor[i] = vec3Param(FragLightProperty(i, "specColor"));
  1975.         if (props.texUsage & ShaderProperties::NightTexture)
  1976.             fragLightBrightness[i] = floatParam(FragLightProperty(i, "brightness"));
  1977.         for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
  1978.         {
  1979.             shadows[i][j].texGenS =
  1980.                 vec4Param(IndexedParameter("shadowTexGenS", i, j));
  1981.             shadows[i][j].texGenT =
  1982.                 vec4Param(IndexedParameter("shadowTexGenT", i, j));
  1983.             shadows[i][j].falloff =
  1984.                 floatParam(IndexedParameter("shadowFalloff", i, j));
  1985.             shadows[i][j].maxDepth =
  1986.                 floatParam(IndexedParameter("shadowMaxDepth", i, j));
  1987.         }
  1988.     }
  1989.     if (props.hasSpecular())
  1990.     {
  1991.         shininess            = floatParam("shininess");
  1992.     }
  1993.     if (props.isViewDependent() || props.hasScattering())
  1994.     {
  1995.         eyePosition          = vec3Param("eyePosition");
  1996.     }
  1997.     opacity      = floatParam("opacity");
  1998.     ambientColor = vec3Param("ambientColor");
  1999. #ifdef USE_HDR
  2000.     nightLightScale          = floatParam("nightLightScale");
  2001. #endif
  2002.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  2003.     {
  2004.         ringWidth            = floatParam("ringWidth");
  2005.         ringRadius           = floatParam("ringRadius");
  2006.     }
  2007.     textureOffset = floatParam("textureOffset");
  2008.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  2009.     {
  2010.         cloudHeight         = floatParam("cloudHeight");
  2011.         shadowTextureOffset = floatParam("cloudShadowTexOffset");
  2012.     }
  2013.     if (props.hasScattering())
  2014.     {
  2015.         mieCoeff             = floatParam("mieCoeff");
  2016.         mieScaleHeight       = floatParam("mieH");
  2017.         miePhaseAsymmetry    = floatParam("mieK");
  2018.         rayleighCoeff        = vec3Param("rayleighCoeff");
  2019.         rayleighScaleHeight  = floatParam("rayleighH");
  2020.         atmosphereRadius     = vec3Param("atmosphereRadius");
  2021.         scatterCoeffSum      = vec3Param("scatterCoeffSum");
  2022.         invScatterCoeffSum   = vec3Param("invScatterCoeffSum");
  2023.         extinctionCoeff      = vec3Param("extinctionCoeff");
  2024.     }
  2025.     if (props.lightModel == ShaderProperties::LunarLambertModel)
  2026.     {
  2027.         lunarLambert         = floatParam("lunarLambert");
  2028.     }
  2029.     if ((props.texUsage & ShaderProperties::PointSprite) != 0)
  2030.     {
  2031.         pointScale           = floatParam("pointScale");
  2032.     }
  2033. }
  2034. void
  2035. CelestiaGLProgram::initSamplers()
  2036. {
  2037.     program->use();
  2038.     unsigned int nSamplers = 0;
  2039.     if (props.texUsage & ShaderProperties::DiffuseTexture)
  2040.     {
  2041.         int slot = glx::glGetUniformLocationARB(program->getID(), "diffTex");
  2042.         if (slot != -1)
  2043.             glx::glUniform1iARB(slot, nSamplers++);
  2044.     }
  2045.     if (props.texUsage & ShaderProperties::NormalTexture)
  2046.     {
  2047.         int slot = glx::glGetUniformLocationARB(program->getID(), "normTex");
  2048.         if (slot != -1)
  2049.             glx::glUniform1iARB(slot, nSamplers++);
  2050.     }
  2051.     if (props.texUsage & ShaderProperties::SpecularTexture)
  2052.     {
  2053.         int slot = glx::glGetUniformLocationARB(program->getID(), "specTex");
  2054.         if (slot != -1)
  2055.             glx::glUniform1iARB(slot, nSamplers++);
  2056.     }
  2057.     if (props.texUsage & ShaderProperties::NightTexture)
  2058.     {
  2059.         int slot = glx::glGetUniformLocationARB(program->getID(), "nightTex");
  2060.         if (slot != -1)
  2061.             glx::glUniform1iARB(slot, nSamplers++);
  2062.     }
  2063.     if (props.texUsage & ShaderProperties::EmissiveTexture)
  2064.     {
  2065.         int slot = glx::glGetUniformLocationARB(program->getID(), "emissiveTex");
  2066.         if (slot != -1)
  2067.             glx::glUniform1iARB(slot, nSamplers++);
  2068.     }
  2069.     if (props.texUsage & ShaderProperties::OverlayTexture)
  2070.     {
  2071.         int slot = glx::glGetUniformLocationARB(program->getID(), "overlayTex");
  2072.         if (slot != -1)
  2073.             glx::glUniform1iARB(slot, nSamplers++);
  2074.     }
  2075.     if (props.texUsage & ShaderProperties::RingShadowTexture)
  2076.     {
  2077.         int slot = glx::glGetUniformLocationARB(program->getID(), "ringTex");
  2078.         if (slot != -1)
  2079.             glx::glUniform1iARB(slot, nSamplers++);
  2080.     }
  2081.     if (props.texUsage & ShaderProperties::CloudShadowTexture)
  2082.     {
  2083.         int slot = glx::glGetUniformLocationARB(program->getID(), "cloudShadowTex");
  2084.         if (slot != -1)
  2085.             glx::glUniform1iARB(slot, nSamplers++);
  2086.     }
  2087. }
  2088. void
  2089. CelestiaGLProgram::setLightParameters(const LightingState& ls,
  2090.                                       Color materialDiffuse,
  2091.                                       Color materialSpecular,
  2092.                                       Color materialEmissive
  2093. #ifdef USE_HDR
  2094.                                      ,float _nightLightScale
  2095. #endif
  2096.                                       )
  2097. {
  2098.     unsigned int nLights = min(MaxShaderLights, ls.nLights);
  2099.     Vec3f diffuseColor(materialDiffuse.red(),
  2100.                        materialDiffuse.green(),
  2101.                        materialDiffuse.blue());
  2102.     Vec3f specularColor(materialSpecular.red(),
  2103.                         materialSpecular.green(),
  2104.                         materialSpecular.blue());
  2105.     for (unsigned int i = 0; i < nLights; i++)
  2106.     {
  2107.         const DirectionalLight& light = ls.lights[i];
  2108.         Vec3f lightColor = Vec3f(light.color.red(),
  2109.                                  light.color.green(),
  2110.                                  light.color.blue()) * light.irradiance;
  2111.         lights[i].direction = light.direction_obj;
  2112.         if (props.usesShadows() ||
  2113.             props.usesFragmentLighting() ||
  2114.             props.lightModel == ShaderProperties::RingIllumModel)
  2115.         {
  2116.             fragLightColor[i] = Vec3f(lightColor.x * diffuseColor.x,
  2117.                                       lightColor.y * diffuseColor.y,
  2118.                                       lightColor.z * diffuseColor.z);
  2119.             if (props.hasSpecular())
  2120.             {
  2121.                 fragLightSpecColor[i] = Vec3f(lightColor.x * specularColor.x,
  2122.                                               lightColor.y * specularColor.y,
  2123.                                               lightColor.z * specularColor.z);
  2124.             }
  2125.             fragLightBrightness[i] = max(lightColor.x, max(lightColor.y, lightColor.z));
  2126.         }
  2127.         else
  2128.         {
  2129.             lights[i].diffuse = Vec3f(lightColor.x * diffuseColor.x,
  2130.                                       lightColor.y * diffuseColor.y,
  2131.                                       lightColor.z * diffuseColor.z);
  2132.         }
  2133.         lights[i].brightness = max(lightColor.x, max(lightColor.y, lightColor.z));
  2134.         lights[i].specular = Vec3f(lightColor.x * specularColor.x,
  2135.                                    lightColor.y * specularColor.y,
  2136.                                    lightColor.z * specularColor.z);
  2137.         Vec3f halfAngle_obj = ls.eyeDir_obj + light.direction_obj;
  2138.         if (halfAngle_obj.length() != 0.0f)
  2139.             halfAngle_obj.normalize();
  2140.         lights[i].halfVector = halfAngle_obj;
  2141.     }
  2142.     eyePosition = ls.eyePos_obj;
  2143.     ambientColor = Vec3f(ls.ambientColor.x * diffuseColor.x + materialEmissive.red(),
  2144.                          ls.ambientColor.y * diffuseColor.y + materialEmissive.green(),
  2145.                          ls.ambientColor.z * diffuseColor.z + materialEmissive.blue());
  2146.     opacity = materialDiffuse.alpha();
  2147. #ifdef USE_HDR
  2148.     nightLightScale = _nightLightScale;
  2149. #endif
  2150. }
  2151. // Set GLSL shader constants for shadows from ellipsoid occluders; shadows from
  2152. // irregular objects are not handled yet.
  2153. void
  2154. CelestiaGLProgram::setEclipseShadowParameters(const LightingState& ls,
  2155.                                               float planetRadius,
  2156.                                               const Mat4f& planetMat)
  2157. {
  2158.     for (unsigned int li = 0;
  2159.          li < min(ls.nLights, MaxShaderLights);
  2160.          li++)
  2161.     {
  2162.         if (shadows != NULL)
  2163.         {
  2164.             unsigned int nShadows = min((size_t) MaxShaderShadows, ls.shadows[li]->size());
  2165.             for (unsigned int i = 0; i < nShadows; i++)
  2166.             {
  2167.                 EclipseShadow& shadow = ls.shadows[li]->at(i);
  2168.                 CelestiaGLProgramShadow& shadowParams = shadows[li][i];
  2169.                 // Compute shadow parameters: max depth of at the center of the shadow
  2170.                 // (always 1 if an eclipse is total) and the linear falloff
  2171.                 // rate from the center to the outer endge of the penumbra.
  2172.                 float u = shadow.umbraRadius / shadow.penumbraRadius;
  2173.                 shadowParams.falloff = -shadow.maxDepth / std::max(0.001f, 1.0f - std::fabs(u));
  2174.                 shadowParams.maxDepth = shadow.maxDepth;
  2175.                 // Compute the transformation to use for generating texture
  2176.                 // coordinates from the object vertices.
  2177.                 Point3f origin = shadow.origin * planetMat;
  2178.                 Vec3f dir = shadow.direction * planetMat;
  2179.                 float scale = planetRadius / shadow.penumbraRadius;
  2180.                 Vec3f axis = Vec3f(0, 1, 0) ^ dir;
  2181.                 float angle = (float) acos(Vec3f(0, 1, 0) * dir);
  2182.                 axis.normalize();
  2183.                 Mat4f mat = Mat4f::rotation(axis, -angle);
  2184.                 Vec3f sAxis = Vec3f(0.5f * scale, 0, 0) * mat;
  2185.                 Vec3f tAxis = Vec3f(0, 0, 0.5f * scale) * mat;
  2186.                 float sw = (Point3f(0, 0, 0) - origin) * sAxis / planetRadius + 0.5f;
  2187.                 float tw = (Point3f(0, 0, 0) - origin) * tAxis / planetRadius + 0.5f;
  2188.                 shadowParams.texGenS = Vec4f(sAxis.x, sAxis.y, sAxis.z, sw);
  2189.                 shadowParams.texGenT = Vec4f(tAxis.x, tAxis.y, tAxis.z, tw);
  2190.             }
  2191.         }
  2192.     }
  2193. }
  2194. // Set the scattering and absoroption shader parameters for atmosphere simulation.
  2195. // They are from standard units to the normalized system used by the shaders.
  2196. // atmPlanetRadius - the radius in km of the planet with the atmosphere
  2197. // objRadius - the radius in km of the object we're rendering
  2198. void
  2199. CelestiaGLProgram::setAtmosphereParameters(const Atmosphere& atmosphere,
  2200.                                            float atmPlanetRadius,
  2201.                                            float objRadius)
  2202. {
  2203.     // Compute the radius of the sky sphere to render; the density of the atmosphere
  2204.     // fallse off exponentially with height above the planet's surface, so the actual
  2205.     // radius is infinite. That's a bit impractical, so well just render the portion
  2206.     // out to the point where the density is some fraction of the surface density.
  2207.     float skySphereRadius = atmPlanetRadius + -atmosphere.mieScaleHeight * (float) log(AtmosphereExtinctionThreshold);
  2208.     float tMieCoeff        = atmosphere.mieCoeff * objRadius;
  2209.     Vec3f tRayleighCoeff   = atmosphere.rayleighCoeff * objRadius;
  2210.     Vec3f tAbsorptionCoeff = atmosphere.absorptionCoeff * objRadius;
  2211.     float r = skySphereRadius / objRadius;
  2212.     atmosphereRadius = Vec3f(r, r * r, atmPlanetRadius / objRadius);
  2213.     mieCoeff = tMieCoeff;
  2214.     mieScaleHeight = objRadius / atmosphere.mieScaleHeight;
  2215.     // The scattering shaders use the Schlick approximation to the
  2216.     // Henyey-Greenstein phase function because it's slightly faster
  2217.     // to compute. Convert the HG asymmetry parameter to the Schlick
  2218.     // parameter.
  2219.     float g = atmosphere.miePhaseAsymmetry;
  2220.     miePhaseAsymmetry = 1.55f * g - 0.55f * g * g * g;
  2221.     rayleighCoeff = tRayleighCoeff;
  2222.     rayleighScaleHeight = 0.0f; // TODO
  2223.     // Precompute sum and inverse sum of scattering coefficients to save work
  2224.     // in the vertex shader.
  2225.     Vec3f tScatterCoeffSum = Vec3f(tRayleighCoeff.x + tMieCoeff,
  2226.                                    tRayleighCoeff.y + tMieCoeff,
  2227.                                    tRayleighCoeff.z + tMieCoeff);
  2228.     scatterCoeffSum = tScatterCoeffSum;
  2229.     invScatterCoeffSum = Vec3f(1.0f / tScatterCoeffSum.x, 1.0f / tScatterCoeffSum.y, 1.0f / tScatterCoeffSum.z);
  2230.     extinctionCoeff = tScatterCoeffSum + tAbsorptionCoeff;
  2231. }