Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

shadermanager.cpp

Go to the documentation of this file.
00001 // shadermanager.cpp
00002 //
00003 // Copyright (C) 2001-2004, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include "gl.h"
00011 #include "glext.h"
00012 #include "shadermanager.h"
00013 #include <iostream>
00014 #include <fstream>
00015 #include <iomanip>
00016 #include <cstdio>
00017 #include <cassert>
00018 
00019 using namespace std;
00020 
00021 // GLSL on Mac OS X appears to have a bug that precludes us from using structs
00022 // #define USE_GLSL_STRUCTS
00023 
00024 ShaderManager g_ShaderManager;
00025 
00026 
00027 static const char* errorVertexShaderSource = 
00028     "void main(void) {\n"
00029     "   gl_Position = ftransform();\n"
00030     "}\n";
00031 static const char* errorFragmentShaderSource =
00032     "void main(void) {\n"
00033     "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
00034     "}\n";
00035 
00036 
00037 ShaderManager&
00038 GetShaderManager()
00039 {
00040     return g_ShaderManager;
00041 }
00042 
00043 
00044 ShaderProperties::ShaderProperties() :
00045     nLights(0),
00046     texUsage(0),
00047     lightModel(DiffuseModel),
00048     shadowCounts(0)
00049 {
00050 }
00051 
00052 
00053 bool
00054 ShaderProperties::usesShadows() const
00055 {
00056     if ((texUsage & RingShadowTexture) != 0 || shadowCounts != 0)
00057         return true;
00058     else
00059         return false;
00060 }
00061 
00062 
00063 bool
00064 ShaderProperties::usesFragmentLighting() const
00065 {
00066     if ((texUsage & NormalTexture) != 0)
00067         return true;
00068     else
00069         return false;
00070 }
00071 
00072 
00073 unsigned int
00074 ShaderProperties::getShadowCountForLight(unsigned int i) const
00075 {
00076     return (shadowCounts >> i * 2) & 3;
00077 }
00078 
00079 
00080 void
00081 ShaderProperties::setShadowCountForLight(unsigned int light, unsigned int n)
00082 {
00083     assert(n < MaxShaderShadows);
00084     assert(light < MaxShaderLights);
00085     if (n <= MaxShaderShadows && light < MaxShaderLights)
00086     {
00087         shadowCounts &= ~(3 << light * 2);
00088         shadowCounts |= n << light * 2;
00089     }
00090 }
00091 
00092 
00093 bool
00094 ShaderProperties::hasShadowsForLight(unsigned int light) const
00095 {
00096     assert(light < MaxShaderLights);
00097     return ((getShadowCountForLight(light) != 0) ||
00098             (texUsage & RingShadowTexture));
00099 }
00100 
00101 
00102 bool operator<(const ShaderProperties& p0, const ShaderProperties& p1)
00103 {
00104     if (p0.texUsage < p1.texUsage)
00105         return true;
00106     else if (p1.texUsage < p0.texUsage)
00107         return false;
00108 
00109     if (p0.nLights < p1.nLights)
00110         return true;
00111     else if (p1.nLights < p0.nLights)
00112         return false;
00113 
00114     if (p0.shadowCounts < p1.shadowCounts)
00115         return true;
00116     else if (p1.shadowCounts < p0.shadowCounts)
00117         return false;
00118 
00119     return (p0.lightModel < p1.lightModel);
00120 }
00121 
00122 
00123 ShaderManager::ShaderManager()
00124 {
00125     if (g_shaderLogFile == NULL)
00126 #ifdef _WIN32
00127         g_shaderLogFile = new ofstream("shaders.log");
00128 #else
00129         g_shaderLogFile = new ofstream("/tmp/celestia-shaders.log");
00130 #endif
00131 }
00132 
00133 
00134 ShaderManager::~ShaderManager()
00135 {
00136 }
00137 
00138 
00139 CelestiaGLProgram*
00140 ShaderManager::getShader(const ShaderProperties& props)
00141 {
00142     map<ShaderProperties, CelestiaGLProgram*>::iterator iter = shaders.find(props);
00143     if (iter != shaders.end())
00144     {
00145         // Shader already exists
00146         return iter->second;
00147     }
00148     else
00149     {
00150         // Create a new shader and add it to the table of created shaders
00151         CelestiaGLProgram* prog = buildProgram(props);
00152         shaders[props] = prog;
00153 
00154         return prog;
00155     }
00156 }
00157 
00158 
00159 CelestiaGLProgram::CelestiaGLProgram(GLProgram& _program,
00160                                      const ShaderProperties& props) :
00161     program(&_program)
00162 {
00163     initParameters(props);
00164     initSamplers(props);
00165 };
00166 
00167 
00168 CelestiaGLProgram::~CelestiaGLProgram()
00169 {
00170     delete program;
00171 }
00172 
00173 
00174 FloatShaderParameter
00175 CelestiaGLProgram::floatParam(const string& paramName)
00176 {
00177     return FloatShaderParameter(program->getID(), paramName.c_str());
00178 }
00179 
00180 
00181 Vec3ShaderParameter
00182 CelestiaGLProgram::vec3Param(const string& paramName)
00183 {
00184     return Vec3ShaderParameter(program->getID(), paramName.c_str());
00185 }
00186 
00187 
00188 Vec4ShaderParameter
00189 CelestiaGLProgram::vec4Param(const string& paramName)
00190 {
00191     return Vec4ShaderParameter(program->getID(), paramName.c_str());
00192 }
00193 
00194 
00195 static string
00196 LightProperty(unsigned int i, char* property)
00197 {
00198     char buf[64];
00199 
00200 #ifndef USE_GLSL_STRUCTS
00201     sprintf(buf, "light%d_%s", i, property);
00202 #else
00203     sprintf(buf, "lights[%d].%s", i, property);
00204 #endif
00205     return string(buf);
00206 }
00207 
00208 
00209 static string
00210 FragLightProperty(unsigned int i, char* property)
00211 {
00212     char buf[64];
00213     sprintf(buf, "light%s%d", property, i);
00214     return string(buf);
00215 }
00216 
00217 
00218 static string
00219 IndexedParameter(const char* name, unsigned int index)
00220 {
00221     char buf[64];
00222     sprintf(buf, "%s%d", name, index);
00223     return string(buf);
00224 }
00225 
00226 
00227 static string
00228 IndexedParameter(const char* name, unsigned int index0, unsigned int index1)
00229 {
00230     char buf[64];
00231     sprintf(buf, "%s%d_%d", name, index0, index1);
00232     return string(buf);
00233 }
00234 
00235 
00236 static string
00237 RingShadowTexCoord(unsigned int index)
00238 {
00239     char buf[64];
00240     sprintf(buf, "ringShadowTexCoord.%c", "xyzw"[index]);
00241     return string(buf);
00242 }
00243 
00244 
00245 void
00246 CelestiaGLProgram::initParameters(const ShaderProperties& props)
00247 {
00248     for (unsigned int i = 0; i < props.nLights; i++)
00249     {
00250         lights[i].direction  = vec3Param(LightProperty(i, "direction"));
00251         lights[i].diffuse    = vec3Param(LightProperty(i, "diffuse"));
00252         lights[i].specular   = vec3Param(LightProperty(i, "specular"));
00253         lights[i].halfVector = vec3Param(LightProperty(i, "halfVector"));
00254 
00255         fragLightColor[i] = vec3Param(FragLightProperty(i, "color"));
00256         fragLightSpecColor[i] = vec3Param(FragLightProperty(i, "specColor"));
00257 
00258         for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
00259         {
00260             shadows[i][j].texGenS =
00261                 vec4Param(IndexedParameter("shadowTexGenS", i, j));
00262             shadows[i][j].texGenT =
00263                 vec4Param(IndexedParameter("shadowTexGenT", i, j));
00264             shadows[i][j].scale =
00265                 floatParam(IndexedParameter("shadowScale", i, j));
00266             shadows[i][j].bias =
00267                 floatParam(IndexedParameter("shadowBias", i, j));
00268         }
00269     }
00270 
00271     if (props.lightModel == ShaderProperties::SpecularModel)
00272     {
00273         shininess            = floatParam("shininess");
00274     }
00275 
00276     if (props.lightModel == ShaderProperties::RingIllumModel)
00277     {
00278         // TODO: Eye position also required for specular lighting with
00279         // local viewer.
00280         eyePosition          = vec3Param("eyePosition");
00281     }
00282 
00283     ambientColor = vec3Param("ambientColor");
00284 
00285     if (props.texUsage & ShaderProperties::RingShadowTexture)
00286     {
00287         ringWidth            = floatParam("ringWidth");
00288         ringRadius           = floatParam("ringRadius");
00289     }
00290 
00291     textureOffset = floatParam("textureOffset");
00292 }
00293 
00294 
00295 void
00296 CelestiaGLProgram::initSamplers(const ShaderProperties& props)
00297 {
00298     program->use();
00299 
00300     unsigned int nSamplers = 0;
00301     if (props.texUsage & ShaderProperties::DiffuseTexture)
00302     {
00303         int slot = glx::glGetUniformLocationARB(program->getID(), "diffTex");
00304         if (slot != -1)
00305             glx::glUniform1iARB(slot, nSamplers++);
00306     }
00307 
00308     if (props.texUsage & ShaderProperties::NormalTexture)
00309     {
00310         int slot = glx::glGetUniformLocationARB(program->getID(), "normTex");
00311         if (slot != -1)
00312             glx::glUniform1iARB(slot, nSamplers++);
00313     }
00314 
00315     if (props.texUsage & ShaderProperties::SpecularTexture)
00316     {
00317         int slot = glx::glGetUniformLocationARB(program->getID(), "specTex");
00318         if (slot != -1)
00319             glx::glUniform1iARB(slot, nSamplers++);
00320     }
00321 
00322     if (props.texUsage & ShaderProperties::NightTexture)
00323     {
00324         int slot = glx::glGetUniformLocationARB(program->getID(), "nightTex");
00325         if (slot != -1)
00326             glx::glUniform1iARB(slot, nSamplers++);
00327     }
00328 
00329     if (props.texUsage & ShaderProperties::RingShadowTexture)
00330     {
00331         int slot = glx::glGetUniformLocationARB(program->getID(), "ringTex");
00332         if (slot != -1)
00333             glx::glUniform1iARB(slot, nSamplers++);
00334     }
00335 }
00336 
00337 
00338 static void
00339 DumpShaderSource(ostream& out, const std::string& source)
00340 {
00341     bool newline = true;
00342     unsigned int lineNumber = 0;
00343 
00344     for (unsigned int i = 0; i < source.length(); i++)
00345     {
00346         if (newline)
00347         {
00348             lineNumber++;
00349             out << setw(3) << lineNumber << ": ";
00350             newline = false;
00351         }
00352 
00353         out << source[i];
00354         if (source[i] == '\n')
00355             newline = true;
00356     }
00357 
00358     out.flush();
00359 }
00360 
00361 
00362 static string
00363 DeclareLights(const ShaderProperties& props)
00364 {
00365     if (props.nLights == 0)
00366         return string("");
00367 
00368     char lightSourceBuf[128];
00369 
00370 #ifndef USE_GLSL_STRUCTS
00371     string lightSourceDecl;
00372     
00373     for (unsigned int i = 0; i < props.nLights; i++)
00374     {
00375         sprintf(lightSourceBuf,
00376                 "uniform vec3 light%d_direction;\n"
00377                 "uniform vec3 light%d_diffuse;\n"
00378                 "uniform vec3 light%d_specular;\n"
00379                 "uniform vec3 light%d_halfVector;\n",
00380                 i, i, i, i);
00381         lightSourceDecl += string(lightSourceBuf);
00382     }
00383     
00384     return lightSourceDecl;
00385 #else    
00386     sprintf(lightSourceBuf,
00387             "uniform struct {\n"
00388             "   vec3 direction;\n"
00389             "   vec3 diffuse;\n"
00390             "   vec3 specular;\n"
00391             "   vec3 halfVector;\n"
00392             "} lights[%d];\n",
00393             props.nLights);
00394 
00395     return string(lightSourceBuf);
00396 #endif
00397 }
00398 
00399 
00400 static string
00401 SeparateDiffuse(unsigned int i)
00402 {
00403     // Used for packing multiple diffuse factors into the diffuse color.
00404     // It's probably better to use separate float interpolants.  I'll switch
00405     // to this once I verify that shader compilers are smart enough to pack
00406     // multiple scalars into a single vector interpolant.
00407     char buf[32];
00408     sprintf(buf, "diffFactors.%c", "xyzw"[i & 3]);
00409     return string(buf);
00410 }
00411 
00412 
00413 static string
00414 SeparateSpecular(unsigned int i)
00415 {
00416     // Used for packing multiple specular factors into the specular color.
00417     char buf[32];
00418     sprintf(buf, "specFactors.%c", "xyzw"[i & 3]);
00419     return string(buf);
00420 }
00421 
00422 
00423 static string
00424 TexCoord2D(unsigned int i)
00425 {
00426     char buf[64];
00427     sprintf(buf, "gl_MultiTexCoord%d.st", i);
00428     return string(buf);
00429 }
00430 
00431 
00432 static string
00433 LightDir(unsigned int i)
00434 {
00435     char buf[32];
00436     sprintf(buf, "lightDir%d", i);
00437     return string(buf);
00438 }
00439 
00440 
00441 static string
00442 DirectionalLight(unsigned int i, const ShaderProperties& props)
00443 {
00444     string source;
00445 
00446     source += "nDotVP = max(0.0, dot(gl_Normal, " +
00447         LightProperty(i, "direction") + "));\n";
00448     if (props.lightModel == ShaderProperties::SpecularModel)
00449     {
00450         source += "nDotHV = max(0.0, dot(gl_Normal, " +
00451             LightProperty(i, "halfVector") + "));\n";
00452     }
00453 
00454     if (props.usesFragmentLighting())
00455     {
00456         // Diffuse is computed in the fragment shader when fragment lighting
00457         // is enabled.
00458     }
00459     else if (props.usesShadows())
00460     {
00461         // When there are shadows, we need to track the diffuse contributions
00462         // separately for each light.
00463         source += SeparateDiffuse(i) + " = nDotVP;\n";
00464     }
00465     else
00466     {
00467         // Sum the diffuse contribution from all lights
00468         source += "diff.rgb += " + LightProperty(i, "diffuse") + " * nDotVP;\n";
00469     }
00470 
00471     if (props.lightModel == ShaderProperties::SpecularModel)
00472     {
00473         if (props.usesShadows())
00474         {
00475             source += SeparateSpecular(i) +
00476                 " = pow(nDotHV, shininess);\n";
00477         }
00478         else
00479         {
00480             source += "spec.rgb += " + LightProperty(i, "specular") +
00481                 " * (pow(nDotHV, shininess) * nDotVP);\n";
00482         }
00483     }
00484 
00485     if (props.texUsage & ShaderProperties::NightTexture)
00486     {
00487         source += "totalLight += nDotVP;\n";
00488     }
00489 
00490 
00491     return source;
00492 }
00493 
00494 
00495 static string
00496 BeginLightSourceShadows(const ShaderProperties& props, unsigned int light)
00497 {
00498     string source;
00499 
00500     if (props.usesFragmentLighting())
00501     {
00502         if (props.hasShadowsForLight(light))
00503             source += "shadow = 1.0;\n";
00504     }
00505     else
00506     {
00507         source += "shadow = " + SeparateDiffuse(light) + ";\n";
00508     }
00509 
00510     if (props.texUsage & ShaderProperties::RingShadowTexture)
00511     {
00512         source += "shadow *= (1.0 - texture2D(ringTex, vec2(" +
00513             RingShadowTexCoord(light) + ", 0.0)).a);\n";
00514     }
00515 
00516     return source;
00517 }
00518 
00519 
00520 static string
00521 Shadow(unsigned int light, unsigned int shadow)
00522 {
00523     string source;
00524 
00525     source += "shadowCenter = " +
00526         IndexedParameter("shadowTexCoord", light, shadow) +
00527         ".st - vec2(0.5, 0.5);\n";
00528     source += "shadowR = clamp(dot(shadowCenter, shadowCenter) * " +
00529         IndexedParameter("shadowScale", light, shadow) + " + " +
00530         IndexedParameter("shadowBias", light, shadow) + ", 0.0, 1.0);\n";
00531     source += "shadow *= sqrt(shadowR);\n";
00532 
00533     return source;
00534 }
00535 
00536 
00537 static string
00538 ShadowsForLightSource(const ShaderProperties& props, unsigned int light)
00539 {
00540     string source = BeginLightSourceShadows(props, light);
00541 
00542     for (unsigned int i = 0; i < props.getShadowCountForLight(light); i++)
00543         source += Shadow(light, i);
00544 
00545     return source;
00546 }
00547 
00548 
00549 
00550 GLVertexShader*
00551 ShaderManager::buildVertexShader(const ShaderProperties& props)
00552 {
00553     string source;
00554 
00555     source += DeclareLights(props);
00556     if (props.lightModel == ShaderProperties::SpecularModel)
00557         source += "uniform float shininess;\n";
00558 
00559     if (!props.usesFragmentLighting())
00560     {
00561         if (!props.usesShadows())
00562         {
00563             source += "uniform vec3 ambientColor;\n";
00564             source += "varying vec4 diff;\n";
00565         }
00566         else 
00567         {
00568             source += "varying vec4 diffFactors;\n";
00569         }
00570     }
00571 
00572     if (props.lightModel == ShaderProperties::SpecularModel)
00573     {
00574         if (!props.usesShadows())
00575             source += "varying vec4 spec;\n";
00576         else
00577             source += "varying vec4 specFactors;\n";
00578     }
00579 
00580     if (props.texUsage & ShaderProperties::DiffuseTexture)
00581         source += "varying vec2 diffTexCoord;\n";
00582     if (props.texUsage & ShaderProperties::NormalTexture)
00583     {
00584         source += "varying vec2 normTexCoord;\n";
00585         for (unsigned int i = 0; i < props.nLights; i++)
00586             source += "varying vec3 " + LightDir(i) + ";\n";
00587     }
00588     if (props.texUsage & ShaderProperties::SpecularTexture)
00589         source += "varying vec2 specTexCoord;\n";
00590     if (props.texUsage & ShaderProperties::NightTexture)
00591     {
00592         source += "varying vec2 nightTexCoord;\n";
00593         source += "varying float totalLight;\n";
00594     }
00595 
00596     if (props.texUsage & ShaderProperties::RingShadowTexture)
00597     {
00598         source += "uniform float ringWidth;\n";
00599         source += "uniform float ringRadius;\n";
00600         source += "varying vec4 ringShadowTexCoord;\n";
00601     }
00602 
00603     source += "uniform float textureOffset;\n";
00604 
00605     if (props.shadowCounts != 0)
00606     {
00607         for (unsigned int i = 0; i < props.nLights; i++)
00608         {
00609             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
00610             {
00611                 source += "varying vec2 " +
00612                     IndexedParameter("shadowTexCoord", i, j) + ";\n";
00613                 source += "uniform vec4 " +
00614                     IndexedParameter("shadowTexGenS", i, j) + ";\n";
00615                 source += "uniform vec4 " +
00616                     IndexedParameter("shadowTexGenT", i, j) + ";\n";
00617             }
00618         }
00619     }
00620 
00621     if (props.texUsage & ShaderProperties::NormalTexture)
00622         source += "attribute vec3 tangent;\n";
00623 
00624     source += "\nvoid main(void)\n{\n";
00625     source += "float nDotVP;\n";
00626     if (props.lightModel == ShaderProperties::SpecularModel)
00627     {
00628         source += "float nDotHV;\n";
00629     }
00630 
00631     if (!props.usesShadows() && !props.usesFragmentLighting())
00632     {
00633         source += "diff = vec4(ambientColor, 1.0);\n";
00634     }
00635         
00636     if (props.lightModel == ShaderProperties::SpecularModel && !props.usesShadows())
00637     {
00638         source += "spec = vec4(0.0, 0.0, 0.0, 0.0);\n";
00639     }
00640 
00641     if (props.texUsage & ShaderProperties::NightTexture)
00642     {
00643         source += "totalLight = 0.0;\n";
00644         }       
00645 
00646     for (unsigned int i = 0; i < props.nLights; i++)
00647     {
00648         source += DirectionalLight(i, props);
00649     }
00650 
00651     if (props.texUsage & ShaderProperties::NightTexture)
00652     {
00653         // Output the blend factor for night lights textures
00654         source += "totalLight = 1.0 - totalLight;\n";
00655         source += "totalLight = totalLight * totalLight * totalLight * totalLight;\n";
00656     }
00657 
00658     if (props.texUsage & ShaderProperties::NormalTexture)
00659     {
00660         source += "vec3 bitangent = cross(gl_Normal, tangent);\n";
00661         for (unsigned int j = 0; j < props.nLights; j++)
00662         {
00663             source += LightDir(j) + ".x = dot(tangent, " + LightProperty(j, "direction") + ");\n";
00664             source += LightDir(j) + ".y = dot(-bitangent, " + LightProperty(j, "direction") + ");\n";
00665             source += LightDir(j) + ".z = dot(gl_Normal, " + LightProperty(j, "direction") + ");\n";
00666         }
00667     }
00668 
00669     unsigned int nTexCoords = 0;
00670     if (props.texUsage & ShaderProperties::DiffuseTexture)
00671     {
00672         source += "diffTexCoord = " + TexCoord2D(nTexCoords) + ";\n";
00673         source += "diffTexCoord.x += textureOffset;\n";
00674         nTexCoords++;
00675     }
00676 
00677     if (props.texUsage & ShaderProperties::NormalTexture)
00678     {
00679         source += "normTexCoord = " + TexCoord2D(nTexCoords) + ";\n";
00680         nTexCoords++;
00681     }
00682 
00683     if (props.texUsage & ShaderProperties::SpecularTexture)
00684     {
00685         source += "specTexCoord = " + TexCoord2D(nTexCoords) + ";\n";
00686         nTexCoords++;
00687     }
00688 
00689     if (props.texUsage & ShaderProperties::NightTexture)
00690     {
00691         source += "nightTexCoord = " + TexCoord2D(nTexCoords) + ";\n";
00692         nTexCoords++;
00693     }
00694 
00695     if (props.texUsage & ShaderProperties::RingShadowTexture)
00696     {
00697         source += "vec3 ringShadowProj;\n";
00698         for (unsigned int j = 0; j < props.nLights; j++)
00699         {
00700             source += "ringShadowProj = gl_Vertex.xyz + " +
00701                 LightProperty(j, "direction") +
00702                 " * max(0.0, gl_Vertex.y / -" +
00703                 LightProperty(j, "direction") + ".y);\n";
00704             source += RingShadowTexCoord(j) +
00705                 " = (length(ringShadowProj) - ringRadius) * ringWidth;\n";
00706         }
00707     }
00708 
00709     if (props.shadowCounts != 0)
00710     {
00711         for (unsigned int i = 0; i < props.nLights; i++)
00712         {
00713             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
00714             {
00715                 source += IndexedParameter("shadowTexCoord", i, j) +
00716                     ".s = dot(gl_Vertex, " +
00717                     IndexedParameter("shadowTexGenS", i, j) + ");\n";
00718                 source += IndexedParameter("shadowTexCoord", i, j) +
00719                     ".t = dot(gl_Vertex, " +
00720                     IndexedParameter("shadowTexGenT", i, j) + ");\n";
00721             }
00722         }
00723     }
00724 
00725     source += "gl_Position = ftransform();\n";
00726     source += "}\n";
00727 
00728     if (g_shaderLogFile != NULL)
00729     {
00730         *g_shaderLogFile << "Vertex shader source:\n";
00731         DumpShaderSource(*g_shaderLogFile, source);
00732         *g_shaderLogFile << '\n';
00733     }
00734 
00735     GLVertexShader* vs = NULL;
00736     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
00737     if (status != ShaderStatus_OK)
00738         return NULL;
00739     else
00740         return vs;
00741 }
00742 
00743 
00744 GLFragmentShader*
00745 ShaderManager::buildFragmentShader(const ShaderProperties& props)
00746 {
00747     string source;
00748 
00749     if (props.usesFragmentLighting() || props.usesShadows())
00750     {
00751         source += "uniform vec3 ambientColor;\n";
00752         source += "vec4 diff = vec4(ambientColor, 1.0);\n";
00753         for (unsigned int i = 0; i < props.nLights; i++)
00754         {
00755             source += "uniform vec3 " + FragLightProperty(i, "color") + ";\n";
00756             if (props.lightModel == ShaderProperties::SpecularModel)
00757             {
00758                 source += "uniform vec3 " +
00759                     FragLightProperty(i, "specColor") + ";\n";
00760             }
00761         }
00762     }
00763     else
00764     {
00765         source += "varying vec4 diff;\n";
00766     }
00767 
00768     if (props.usesShadows() && !props.usesFragmentLighting())
00769     {
00770         source += "varying vec4 diffFactors;\n";
00771     }
00772 
00773     if (props.lightModel == ShaderProperties::SpecularModel)
00774     {
00775         if (props.usesShadows())
00776         {
00777             source += "varying vec4 specFactors;\n";
00778             source += "vec4 spec;\n";
00779         }
00780         else
00781         {
00782             source += "varying vec4 spec;\n";
00783         }
00784     }
00785 
00786     if (props.texUsage & ShaderProperties::DiffuseTexture)
00787     {
00788         source += "varying vec2 diffTexCoord;\n";
00789         source += "uniform sampler2D diffTex;\n";
00790     }
00791 
00792     if (props.texUsage & ShaderProperties::NormalTexture)
00793     {
00794         source += "varying vec2 normTexCoord;\n";
00795         for (unsigned int i = 0; i < props.nLights; i++)
00796             source += "varying vec3 " + LightDir(i) + ";\n";
00797         source += "uniform sampler2D normTex;\n";
00798     }
00799 
00800     if (props.texUsage & ShaderProperties::SpecularTexture)
00801     {
00802         source += "varying vec2 specTexCoord;\n";
00803         source += "uniform sampler2D specTex;\n";
00804     }
00805 
00806     if (props.texUsage & ShaderProperties::NightTexture)
00807     {
00808         source += "varying vec2 nightTexCoord;\n";
00809         source += "uniform sampler2D nightTex;\n";
00810         source += "varying float totalLight;\n";
00811     }
00812 
00813     if (props.texUsage & ShaderProperties::RingShadowTexture)
00814     {
00815         source += "uniform sampler2D ringTex;\n";
00816         source += "varying vec4 ringShadowTexCoord;\n";
00817     }
00818 
00819     if (props.shadowCounts != 0)
00820     {
00821         for (unsigned int i = 0; i < props.nLights; i++)
00822         {
00823             for (unsigned int j = 0; j < props.getShadowCountForLight(i); j++)
00824             {
00825                 source += "varying vec2 " +
00826                     IndexedParameter("shadowTexCoord", i, j) + ";\n";
00827                 source += "uniform float " +
00828                     IndexedParameter("shadowScale", i, j) + ";\n";
00829                 source += "uniform float " +
00830                     IndexedParameter("shadowBias", i, j) + ";\n";
00831             }
00832         }
00833     }
00834 
00835     source += "\nvoid main(void)\n{\n";
00836     source += "vec4 color;\n";
00837 
00838     if (props.usesShadows())
00839     {
00840         // Temporaries required for shadows
00841         source += "float shadow;\n";
00842         if (props.shadowCounts != 0)
00843         {
00844             source += "vec2 shadowCenter;\n";
00845             source += "float shadowR;\n";
00846         }
00847     }
00848 
00849     if (props.texUsage & ShaderProperties::NormalTexture)
00850     {
00851         source += "vec3 n = texture2D(normTex, normTexCoord.st).xyz * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);\n";
00852         source += "float l;\n";
00853         for (unsigned i = 0; i < props.nLights; i++)
00854         {
00855             // Bump mapping with self shadowing
00856             source += "l = max(0.0, dot(" + LightDir(i) + ", n)) * clamp(" + LightDir(i) + ".z * 8.0, 0.0, 1.0);\n";
00857 
00858             string illum;
00859             if (props.hasShadowsForLight(i))
00860                 illum = string("l * shadow");
00861             else
00862                 illum = string("l");
00863 
00864             if (props.hasShadowsForLight(i))
00865                 source += ShadowsForLightSource(props, i);
00866 
00867             source += "diff.rgb += " + illum + " * " +
00868                 FragLightProperty(i, "color") + ";\n";
00869 
00870             if (props.lightModel == ShaderProperties::SpecularModel &&
00871                 props.usesShadows())
00872             {
00873                 source += "spec.rgb += " + illum + " * " + SeparateSpecular(i) +
00874                     " * " + FragLightProperty(i, "specColor") +
00875                     ";\n";
00876             }
00877         }
00878     }
00879     else if (props.usesShadows())
00880     {
00881         // Sum the contributions from each light source
00882         for (unsigned i = 0; i < props.nLights; i++)
00883         {
00884             source += ShadowsForLightSource(props, i);
00885             source += "diff.rgb += shadow * " +
00886                 FragLightProperty(i, "color") + ";\n";
00887             if (props.lightModel == ShaderProperties::SpecularModel)
00888             {
00889                 source += "spec.rgb += shadow * " + SeparateSpecular(i) +
00890                     " * " +
00891                     FragLightProperty(i, "specColor") + ";\n";
00892             }
00893         }
00894     }
00895 
00896     if (props.texUsage & ShaderProperties::DiffuseTexture)
00897         source += "color = texture2D(diffTex, diffTexCoord.st);\n";
00898     else
00899         source += "color = vec4(1.0, 1.0, 1.0, 1.0);\n";
00900 
00901     if (props.lightModel == ShaderProperties::SpecularModel)
00902     {
00903         if (props.texUsage & ShaderProperties::SpecularInDiffuseAlpha)
00904             source += "gl_FragColor = color * diff + float(color.a) * spec;\n";
00905         else if (props.texUsage & ShaderProperties::SpecularTexture)
00906             source += "gl_FragColor = color * diff + texture2D(specTex, specTexCoord.st) * spec;\n";
00907         else
00908             source += "gl_FragColor = color * diff + spec;\n";
00909     }
00910     else
00911     {
00912         source += "gl_FragColor = color * diff;\n";
00913     }
00914 
00915     if (props.texUsage & ShaderProperties::NightTexture)
00916     {
00917         source += "gl_FragColor += texture2D(nightTex, nightTexCoord.st) * totalLight;\n";
00918     }
00919 
00920     source += "}\n";
00921 
00922     if (g_shaderLogFile != NULL)
00923     {
00924         *g_shaderLogFile << "Fragment shader source:\n";
00925         DumpShaderSource(*g_shaderLogFile, source);
00926         *g_shaderLogFile << '\n';
00927     }
00928     
00929     GLFragmentShader* fs = NULL;
00930     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
00931     if (status != ShaderStatus_OK)
00932         return NULL;
00933     else
00934         return fs;
00935 }
00936 
00937 
00938 GLVertexShader*
00939 ShaderManager::buildRingsVertexShader(const ShaderProperties& props)
00940 {
00941     string source;
00942 
00943     source += DeclareLights(props);
00944     source += "uniform vec3 eyePosition;\n";
00945 
00946     source += "varying vec4 diffFactors;\n";
00947 
00948     if (props.texUsage & ShaderProperties::DiffuseTexture)
00949         source += "varying vec2 diffTexCoord;\n";
00950 
00951     if (props.shadowCounts != 0)
00952     {
00953         for (unsigned int i = 0; i < props.nLights; i++)
00954         {
00955             source += "uniform vec4 " +
00956                 IndexedParameter("shadowTexGenS", i, 0) + ";\n";
00957             source += "uniform vec4 " +
00958                 IndexedParameter("shadowTexGenT", i, 0) + ";\n";
00959             source += "varying vec3 " +
00960                 IndexedParameter("shadowTexCoord", i, 0) + ";\n";
00961         }
00962     }
00963 
00964     source += "\nvoid main(void)\n{\n";
00965     source += "float nDotVP;\n";
00966 
00967     // Get the normalized direction from the eye to the vertex
00968     source += "vec3 eyeDir = normalize(eyePosition - gl_Vertex.xyz);\n";
00969 
00970     for (unsigned int i = 0; i < props.nLights; i++)
00971     {
00972         source += SeparateDiffuse(i) + " = (dot(" +
00973             LightProperty(i, "direction") + ", eyeDir) + 1.0) * 0.5;\n";
00974     }
00975 
00976     if (props.texUsage & ShaderProperties::DiffuseTexture)
00977         source += "diffTexCoord = " + TexCoord2D(0) + ";\n";
00978 
00979     if (props.shadowCounts != 0)
00980     {
00981         for (unsigned int i = 0; i < props.nLights; i++)
00982         {
00983             source += IndexedParameter("shadowTexCoord", i, 0) +
00984                 ".x = dot(gl_Vertex, " +
00985                 IndexedParameter("shadowTexGenS", i, 0) + ");\n";
00986             source += IndexedParameter("shadowTexCoord", i, 0) +
00987                 ".y = dot(gl_Vertex, " +
00988                 IndexedParameter("shadowTexGenT", i, 0) + ");\n";
00989             source += IndexedParameter("shadowTexCoord", i, 0) +
00990                 ".z = dot(gl_Vertex.xyz, " +
00991                 LightProperty(i, "direction") + ");\n";
00992         }
00993     }
00994 
00995     source += "gl_Position = ftransform();\n";
00996     source += "}\n";
00997 
00998     if (g_shaderLogFile != NULL)
00999     {
01000         *g_shaderLogFile << "Vertex shader source:\n";
01001         DumpShaderSource(*g_shaderLogFile, source);
01002         *g_shaderLogFile << '\n';
01003     }
01004 
01005     GLVertexShader* vs = NULL;
01006     GLShaderStatus status = GLShaderLoader::CreateVertexShader(source, &vs);
01007     if (status != ShaderStatus_OK)
01008         return NULL;
01009     else
01010         return vs;
01011 }
01012 
01013 
01014 GLFragmentShader*
01015 ShaderManager::buildRingsFragmentShader(const ShaderProperties& props)
01016 {
01017     string source;
01018 
01019     source += "uniform vec3 ambientColor;\n";
01020     source += "vec4 diff = vec4(ambientColor, 1.0);\n";
01021     for (unsigned int i = 0; i < props.nLights; i++)
01022         source += "uniform vec3 " + FragLightProperty(i, "color") + ";\n";
01023 
01024     source += "varying vec4 diffFactors;\n";
01025 
01026     if (props.texUsage & ShaderProperties::DiffuseTexture)
01027     {
01028         source += "varying vec2 diffTexCoord;\n";
01029         source += "uniform sampler2D diffTex;\n";
01030     }
01031 
01032     if (props.shadowCounts != 0)
01033     {
01034         for (unsigned int i = 0; i < props.nLights; i++)
01035         {
01036             source += "varying vec3 " +
01037                 IndexedParameter("shadowTexCoord", i, 0) + ";\n";
01038             source += "uniform float " +
01039                 IndexedParameter("shadowScale", i, 0) + ";\n";
01040             source += "uniform float " +
01041                 IndexedParameter("shadowBias", i, 0) + ";\n";
01042         }
01043     }
01044 
01045     source += "\nvoid main(void)\n{\n";
01046     source += "vec4 color;\n";
01047 
01048     if (props.usesShadows())
01049     {
01050         // Temporaries required for shadows
01051         source += "float shadow;\n";
01052         source += "vec2 shadowCenter;\n";
01053         source += "float shadowR;\n";
01054     }
01055 
01056     // Sum the contributions from each light source
01057     for (unsigned i = 0; i < props.nLights; i++)
01058     {
01059         if (props.usesShadows())
01060         {
01061             source += "shadow = 1.0;\n";
01062             source += Shadow(i, 0);
01063             source += "shadow = min(1.0, shadow + step(0.0, " +
01064                 IndexedParameter("shadowTexCoord", i, 0) + ".z));\n";
01065             source += "diff.rgb += (shadow * " + SeparateDiffuse(i) + ") * " +
01066                 FragLightProperty(i, "color") + ";\n";
01067         }
01068         else
01069         {
01070             source += "diff.rgb += " + SeparateDiffuse(i) + " * " +
01071                 FragLightProperty(i, "color") + ";\n";
01072         }
01073     }
01074 
01075     if (props.texUsage & ShaderProperties::DiffuseTexture)
01076         source += "color = texture2D(diffTex, diffTexCoord.st);\n";
01077     else
01078         source += "color = vec4(1.0, 1.0, 1.0, 1.0);\n";
01079 
01080     source += "gl_FragColor = color * diff;\n";
01081 
01082     source += "}\n";
01083 
01084     if (g_shaderLogFile != NULL)
01085     {
01086         *g_shaderLogFile << "Fragment shader source:\n";
01087         DumpShaderSource(*g_shaderLogFile, source);
01088         *g_shaderLogFile << '\n';
01089     }
01090     
01091     GLFragmentShader* fs = NULL;
01092     GLShaderStatus status = GLShaderLoader::CreateFragmentShader(source, &fs);
01093     if (status != ShaderStatus_OK)
01094         return NULL;
01095     else
01096         return fs;
01097 }
01098 
01099 
01100 CelestiaGLProgram*
01101 ShaderManager::buildProgram(const ShaderProperties& props)
01102 {
01103     GLProgram* prog = NULL;
01104     GLShaderStatus status;
01105 
01106     GLVertexShader* vs = NULL;
01107     GLFragmentShader* fs = NULL;
01108 
01109     if (props.lightModel == ShaderProperties::RingIllumModel)
01110     {
01111         vs = buildRingsVertexShader(props);
01112         fs = buildRingsFragmentShader(props);
01113     }
01114     else
01115     {
01116         vs = buildVertexShader(props);
01117         fs = buildFragmentShader(props);
01118     }
01119 
01120     if (vs != NULL && fs != NULL)
01121     {
01122         status = GLShaderLoader::CreateProgram(*vs, *fs, &prog);
01123         if (status == ShaderStatus_OK)
01124         {
01125             if (props.texUsage & ShaderProperties::NormalTexture)
01126             {
01127                 // Tangents always in attribute 6 (should be a constant
01128                 // someplace)
01129                 glx::glBindAttribLocationARB(prog->getID(), 6, "tangent");
01130             }
01131             status = prog->link();
01132         }
01133     }
01134     else
01135     {
01136         status = ShaderStatus_CompileError;
01137         if (vs != NULL)
01138             delete vs;
01139         if (fs != NULL)
01140             delete fs;
01141     }
01142 
01143     if (status != ShaderStatus_OK)
01144     {
01145         // If the shader creation failed for some reason, substitute the
01146         // error shader.
01147         status = GLShaderLoader::CreateProgram(errorVertexShaderSource,
01148                                                errorFragmentShaderSource,
01149                                                &prog);
01150         if (status != ShaderStatus_OK)
01151         {
01152             if (g_shaderLogFile != NULL)
01153                 *g_shaderLogFile << "Failed to create error shader!\n";
01154         }
01155         else
01156         {
01157             status = prog->link();
01158         }
01159     }
01160 
01161     if (prog == NULL)
01162         return NULL;
01163     else
01164         return new CelestiaGLProgram(*prog, props);
01165 }

Generated on Sat Jan 14 22:30:28 2006 for Celestia by  doxygen 1.4.1