00001
00002
00003
00004
00005
00006
00007
00008
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
00022
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
00146 return iter->second;
00147 }
00148 else
00149 {
00150
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
00279
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
00404
00405
00406
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
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
00457
00458 }
00459 else if (props.usesShadows())
00460 {
00461
00462
00463 source += SeparateDiffuse(i) + " = nDotVP;\n";
00464 }
00465 else
00466 {
00467
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
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
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
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
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
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
01051 source += "float shadow;\n";
01052 source += "vec2 shadowCenter;\n";
01053 source += "float shadowR;\n";
01054 }
01055
01056
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
01128
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
01146
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 }